Skip to content

Commit 926c31b

Browse files
authored
final
1 parent 01a3522 commit 926c31b

3 files changed

Lines changed: 354 additions & 0 deletions

File tree

CPU.py

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
class CPU:
2+
def __init__(self, barramento):
3+
self.barramento = barramento
4+
self.pc = 0x00000000
5+
self.regs = [0] * 32
6+
7+
# Funcoes Auxiliares
8+
def correcao_dsinal(self, entrada):
9+
entrada = entrada & 0xFFFFFFFF
10+
if (entrada & 0x80000000) == 0x80000000:
11+
return entrada - 0x100000000
12+
return entrada
13+
14+
def correcao_dtamanho(self, entrada):
15+
return entrada & 0xFFFFFFFF
16+
17+
def carregar_programa(self, lista_hex):
18+
addr = 0
19+
for inst in lista_hex:
20+
self.barramento.escreva(addr, inst, 32)
21+
addr += 4
22+
23+
# Execucao
24+
def run(self):
25+
ciclos = 0
26+
while True:
27+
if not self.Decoder():
28+
break
29+
ciclos += 1
30+
if ciclos > 5000:
31+
print("Aviso: Limite de ciclos atingido.")
32+
break
33+
self.barramento.imprimir()
34+
print("\n")
35+
print("CPU Halt (Fim do programa).")
36+
37+
# Decodificador
38+
def Decoder(self):
39+
self.regs[0] = 0
40+
41+
instrucao = self.barramento.leia(self.pc, 32)
42+
if instrucao == 0: return False
43+
44+
next_pc = self.pc + 4
45+
46+
# Separação da entrada
47+
opcode = instrucao & 0x7F
48+
rd = (instrucao >> 7) & 0x1F
49+
funct3 = (instrucao >> 12) & 0x7
50+
rs1 = (instrucao >> 15) & 0x1F
51+
rs2 = (instrucao >> 20) & 0x1F
52+
funct7 = (instrucao >> 25) & 0x7F
53+
54+
# Imediatos (Com correção de sinal ajustada)
55+
# Tipo I Imediato
56+
imm_i = instrucao >> 20
57+
if imm_i & 0x800: imm_i -= 0x1000
58+
# Tipo S Imediato
59+
imm_s = ((instrucao >> 25) << 5) | ((instrucao >> 7) & 0x1F)
60+
if imm_s & 0x800: imm_s -= 0x1000
61+
# Tipo B Imediato
62+
imm_b = ((instrucao >> 31) << 12) | ((instrucao & 0x7E000000) >> 20) | ((instrucao & 0xF00) >> 7) | ((instrucao & 0x80) << 4)
63+
if imm_b & 0x1000: imm_b -= 0x2000
64+
# Tipo U Imediato
65+
imm_u = instrucao & 0xFFFFF000
66+
# Tipo J Imediato
67+
imm_j = ((instrucao >> 31) << 20) | (instrucao & 0xFF000) | ((instrucao & 0x100000) >> 9) | ((instrucao & 0x7FE00000) >> 20)
68+
if imm_j & 0x100000: imm_j -= 0x200000
69+
70+
# Instrucoes - Em ordem de Opcode
71+
72+
# Opcode 0b0000011 - Tipo I (LOAD)
73+
if opcode == 0x03:
74+
addr = self.regs[rs1] + imm_i
75+
76+
if funct3 == 0x0: # LB (Load Byte)
77+
val = self.barramento.leia(addr, 8)
78+
if (val & 0x80) != 0:
79+
val -= 0x100
80+
self.regs[rd] = self.correcao_dtamanho(val)
81+
82+
elif funct3 == 0x1: # LH (Load Half - Signed)
83+
val = self.barramento.leia(addr, 16)
84+
if (val & 0x8000) != 0:
85+
val -= 0x10000
86+
self.regs[rd] = self.correcao_dtamanho(val)
87+
88+
elif funct3 == 0x2: # LW (Load Word)
89+
self.regs[rd] = self.barramento.leia(addr, 32)
90+
91+
elif funct3 == 0x4: # LBU (Load Byte Unsigned)
92+
self.regs[rd] = self.barramento.leia(addr, 8)
93+
94+
elif funct3 == 0x5: # LHU (Load Half Unsigned)
95+
self.regs[rd] = self.barramento.leia(addr, 16)
96+
97+
# Opcode 0b0010011 - Tipo I (OPERACAO IMEDIATA)
98+
elif opcode == 0x13:
99+
val1 = self.correcao_dsinal(self.regs[rs1]) # Valor com sinal
100+
101+
if funct3 == 0x0: # ADDI
102+
self.regs[rd] = self.correcao_dtamanho(val1 + imm_i)
103+
104+
elif funct3 == 0x1: # SLLI
105+
self.regs[rd] = self.correcao_dtamanho(val1 << (imm_i & 0x1F))
106+
107+
elif funct3 == 0x2: # SLTI (Set Less Than Immediate - Signed)
108+
self.regs[rd] = 1 if val1 < imm_i else 0
109+
110+
elif funct3 == 0x3: # SLTIU (Set Less Than Immediate Unsigned)
111+
if self.correcao_dtamanho(val1) < self.correcao_dtamanho(imm_i):
112+
self.regs[rd] = 1
113+
else:
114+
self.regs[rd] = 0
115+
116+
elif funct3 == 0x4: # XORI
117+
self.regs[rd] = self.correcao_dtamanho(val1 ^ imm_i)
118+
119+
elif funct3 == 0x5: # SRLI / SRAI
120+
shamt = imm_i & 0x1F
121+
if (imm_i >> 10) & 1: # SRAI (Shift Right Arithmetic)
122+
self.regs[rd] = self.correcao_dtamanho(val1 >> shamt)
123+
else: # SRLI (Shift Right Logical)
124+
self.regs[rd] = self.correcao_dtamanho(self.regs[rs1] >> shamt)
125+
126+
elif funct3 == 0x6: # ORI
127+
self.regs[rd] = self.correcao_dtamanho(val1 | imm_i)
128+
129+
elif funct3 == 0x7: # ANDI
130+
self.regs[rd] = self.correcao_dtamanho(val1 & imm_i)
131+
132+
# Opcode 0b0010111 - Tipo U (CRIAR ENDERECO IMEDIATO)
133+
elif opcode == 0x17: # AUIPC (add upper immediate to PC)
134+
self.regs[rd] = self.correcao_dtamanho(self.pc + imm_u)
135+
136+
# Opcode 0b0100011 - S-Type (ARMAZENAR)
137+
elif opcode == 0x23:
138+
addr = self.regs[rs1] + imm_s
139+
if funct3 == 0x0: # SB (Store Byte)
140+
self.barramento.escreva(addr, self.regs[rs2] & 0xFF, 8)
141+
elif funct3 == 0x1: # SH (store half)
142+
self.barramento.escreva(addr, self.regs[rs2] & 0xFFFF, 16)
143+
elif funct3 == 0x2: # SW (Store Word)
144+
self.barramento.escreva(addr, self.regs[rs2], 32)
145+
146+
# Opcode 0b0110011 - Tipo R (OPERACOES ENTRE REGISTRADORES)
147+
elif opcode == 0x33:
148+
val1 = self.correcao_dsinal(self.regs[rs1])
149+
val2 = self.correcao_dsinal(self.regs[rs2])
150+
151+
if funct3 == 0x0:
152+
if funct7 == 0x00: # ADD
153+
self.regs[rd] = self.correcao_dtamanho(val1 + val2)
154+
elif funct7 == 0x20: # SUB
155+
self.regs[rd] = self.correcao_dtamanho(val1 - val2)
156+
157+
elif funct3 == 0x1: # SLL (Shift Left Logical)
158+
shamt = val2 & 0x1F
159+
self.regs[rd] = self.correcao_dtamanho(val1 << shamt)
160+
161+
elif funct3 == 0x2: # SLT (Set Less Than Signed)
162+
self.regs[rd] = 1 if val1 < val2 else 0
163+
164+
elif funct3 == 0x3: # SLTU (Set Less Than Unsigned)
165+
u_val1 = self.correcao_dtamanho(val1)
166+
u_val2 = self.correcao_dtamanho(val2)
167+
self.regs[rd] = 1 if u_val1 < u_val2 else 0
168+
169+
elif funct3 == 0x4: # XOR
170+
self.regs[rd] = self.correcao_dtamanho(val1 ^ val2)
171+
172+
elif funct3 == 0x5: # SRL / SRA (Shift Right)
173+
shamt = val2 & 0x1F
174+
if funct7 == 0x20: # SRA (Arithmetic)
175+
self.regs[rd] = self.correcao_dtamanho(val1 >> shamt)
176+
else: # SRL (Logical)
177+
self.regs[rd] = self.correcao_dtamanho(self.correcao_dtamanho(val1) >> shamt)
178+
179+
elif funct3 == 0x6: # OR
180+
self.regs[rd] = self.correcao_dtamanho(val1 | val2)
181+
182+
elif funct3 == 0x7: # AND
183+
self.regs[rd] = self.correcao_dtamanho(val1 & val2)
184+
185+
# Opcode 0b0110111 - Tipo U (CARREGAR ENDERECO IMEDIATO)
186+
elif opcode == 0x37: # LUI
187+
self.regs[rd] = imm_u
188+
189+
# Opcode 0x1100011 - Tipo B (ESCOLHAS)
190+
elif opcode == 0x63: # BRANCH
191+
val1 = self.correcao_dsinal(self.regs[rs1])
192+
val2 = self.correcao_dsinal(self.regs[rs2])
193+
desvio = False
194+
195+
# Comparações com SINAL (Tratam -1 como menor que 1)
196+
if funct3 == 0x0: # BEQ (IGUAL)
197+
desvio = (val1 == val2)
198+
elif funct3 == 0x1: # BNE (DIFERENTE)
199+
desvio = (val1 != val2)
200+
elif funct3 == 0x4: # BLT (MENOR QUE)
201+
desvio = (val1 < val2)
202+
elif funct3 == 0x5: # BGE (MAIOR OU IGUAL)
203+
desvio = (val1 >= val2)
204+
elif funct3 == 0x6: # BLTU (MAIIOR)
205+
desvio = (self.correcao_dtamanho(val1) < self.correcao_dtamanho(val2))
206+
elif funct3 == 0x7: # BGEU (MENOR OU IGUAL)
207+
desvio = (self.correcao_dtamanho(val1)>= self.correcao_dtamanho(val2))
208+
209+
# Se a condição for verdadeira, atualiza o next_pc
210+
if desvio == True:
211+
next_pc = self.pc + imm_b
212+
213+
# Opcode 0x67 (1100111) - Tipo I (PULO com registrador)
214+
elif opcode == 0x67: # JALR
215+
self.regs[rd] = next_pc
216+
next_pc = (self.regs[rs1] + imm_i) & ~1
217+
218+
# Opcode 0x6F (1101111) - Tipo J (PULO)
219+
elif opcode == 0x6F: # JAL
220+
self.regs[rd] = next_pc
221+
next_pc = self.pc + imm_j
222+
223+
self.pc = self.correcao_dtamanho(next_pc)
224+
return True

barramento.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
class barramento:
2+
def __init__(self, memoria, saida):
3+
self.memoria = memoria
4+
self.saida = saida
5+
6+
def leia(self, endereco, tamanho=32):
7+
num_bytes = tamanho // 8
8+
if endereco <= self.memoria.RAM_LIMITE:
9+
return self.memoria.leia(endereco, num_bytes)
10+
11+
elif self.memoria.VRAM <= endereco <= self.memoria.VRAM_LIMITE:
12+
return self.memoria.leia(endereco, num_bytes)
13+
14+
return 0
15+
16+
def escreva(self, endereco, valor, tamanho=32):
17+
num_bytes = tamanho // 8
18+
if endereco <= self.memoria.RAM_LIMITE: #RAM
19+
self.memoria.escreva(endereco, valor, num_bytes)
20+
elif self.memoria.VRAM <= endereco <= self.memoria.VRAM_LIMITE: #VRAM
21+
self.memoria.escreva(endereco, valor, num_bytes)
22+
23+
def imprimir(self):
24+
self.saida.atualizar_monitor(self.memoria)
25+
26+
27+
class monitor:
28+
def atualizar_monitor(self, memoria):
29+
output = ""
30+
inicio = memoria.VRAM
31+
fim = memoria.VRAM_LIMITE + 1
32+
video = memoria.dados[inicio:fim]
33+
for byte in video:
34+
if byte == 0:
35+
continue
36+
if 32 <= byte <= 126:
37+
output += chr(byte)
38+
elif byte == 10:
39+
output += '\n'
40+
else:
41+
output += '.'
42+
43+
if output:
44+
print(output)
45+
else:
46+
print("[ Sem Sinal de Vídeo ]")
47+
48+
49+
class ram:
50+
tamanho_total = 0xA0000
51+
RAM_LIMITE = 0x7FFFF
52+
53+
VRAM = 0x80000
54+
VRAM_LIMITE = 0x8FFFF
55+
56+
E_S = 0x9FC00
57+
58+
def __init__(self):
59+
self.dados = bytearray(self.tamanho_total)
60+
61+
def leia(self, endereco, num_bytes):
62+
if endereco + num_bytes > self.tamanho_total: return 0
63+
return int.from_bytes(self.dados[endereco : endereco + num_bytes], 'little')
64+
65+
def escreva(self, endereco, val, num_bytes):
66+
if endereco + num_bytes > self.tamanho_total: return
67+
mascara = (1 << (num_bytes * 8)) - 1
68+
self.dados[endereco : endereco + num_bytes] = (val & mascara).to_bytes(num_bytes, 'little')

main.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from barramento import barramento, monitor, ram
2+
from CPU import CPU
3+
4+
programa = [
5+
# --- INICIALIZAÇÃO ---
6+
0x000800b7, # LUI x1, 0x80000 (Base VRAM)
7+
0x00000113, # ADDI x2, x0, 0
8+
0x00000293, # ADDI x5, x0, 0 (i = 0)
9+
0x00900313, # ADDI x6, x0, 9 (Lim = 9)
10+
# --- LOOP START (0x10) ---
11+
# BEQ x5, x6, EXIT (Se i==9, vai para 0xAC)
12+
0x08628e63,
13+
# Corpo
14+
0x00128393, # ADDI x7, x5, 1 (a = i+1)
15+
0x0013f413, # ANDI x8, x7, 1 (Check Impar)
16+
17+
# BNE x8, x0, ODD (Se impar, vai para 0x84)
18+
0x06041463,
19+
# --- CAMINHO PAR (0x20) ---
20+
# Imprime 'a hey\n'
21+
0x03038e13, 0x00208eb3, 0x01ce8023, 0x00110113,
22+
0x02000e13, 0x00208eb3, 0x01ce8023, 0x00110113,
23+
0x06800e13, 0x00208eb3, 0x01ce8023, 0x00110113,
24+
0x06500e13, 0x00208eb3, 0x01ce8023, 0x00110113,
25+
0x07900e13, 0x00208eb3, 0x01ce8023, 0x00110113,
26+
0x00a00e13, 0x00208eb3, 0x01ce8023, 0x00110113,
27+
# PULO PARA NEXT (0x80)
28+
0x02000263,
29+
# --- CAMINHO IMPAR (0x84) ---
30+
# Imprime 'a\n'
31+
0x03038e13, 0x00208eb3, 0x01ce8023, 0x00110113,
32+
0x00a00e13, 0x00208eb3, 0x01ce8023, 0x00110113,
33+
# --- NEXT (0xA4) ---
34+
0x00128293, # ADDI x5, x5, 1 (i++)
35+
# VOLTA PARA LOOP (0xA8)
36+
# BEQ x0, x0, LoopStart (-152 bytes)
37+
# Hex correto para -152:
38+
0xF60004E3,
39+
# --- EXIT (0xAC) ---
40+
# "Ola Mundo"
41+
0x04f00e13, 0x00208eb3, 0x01ce8023, 0x00110113,
42+
0x06c00e13, 0x00208eb3, 0x01ce8023, 0x00110113,
43+
0x06100e13, 0x00208eb3, 0x01ce8023, 0x00110113,
44+
0x02000e13, 0x00208eb3, 0x01ce8023, 0x00110113,
45+
0x04d00e13, 0x00208eb3, 0x01ce8023, 0x00110113,
46+
0x07500e13, 0x00208eb3, 0x01ce8023, 0x00110113,
47+
0x06e00e13, 0x00208eb3, 0x01ce8023, 0x00110113,
48+
0x06400e13, 0x00208eb3, 0x01ce8023, 0x00110113,
49+
0x06f00e13, 0x00208eb3, 0x01ce8023, 0x00110113,
50+
# HALT
51+
0x00000000
52+
]
53+
54+
if __name__ == "__main__":
55+
mem = ram()
56+
e_s = monitor()
57+
cabo = barramento(mem, e_s)
58+
cpu = CPU(cabo)
59+
60+
print("--- Carregando Sistema ---")
61+
cpu.carregar_programa(programa)
62+
cpu.run()

0 commit comments

Comments
 (0)