Epreuve 3
This commit is contained in:
parent
c05b92a03b
commit
6ae130c794
263
Epreuve3.py
Normal file
263
Epreuve3.py
Normal file
@ -0,0 +1,263 @@
|
||||
# ---------------------------------------------------------
|
||||
# Simulateur
|
||||
# ---------------------------------------------------------
|
||||
# - Bus données : 8 bits
|
||||
# - 4 registres R0..R3 (8 bits)
|
||||
# - Bus adresse : 8 bits
|
||||
# - RAM : 256 octets
|
||||
# - Instructions : 1 ou 2 octets
|
||||
# - Cycles : 1 octet -> 1, 2 octets -> 2, LDR/STR -> 3
|
||||
# - PC démarre à 0
|
||||
# - Pile descendante, SP=255
|
||||
# ---------------------------------------------------------
|
||||
from dataclasses import dataclass, field
|
||||
import sys
|
||||
|
||||
|
||||
@dataclass
|
||||
class CPU:
|
||||
pc: int = 0
|
||||
sp: int = 255
|
||||
regs: list = field(default_factory=list) # R0..R3
|
||||
lt: int = 0 # flag LT
|
||||
eq: int = 0 # flag EQ
|
||||
cycles: int = 0
|
||||
running: bool = True
|
||||
after_ret: bool = False
|
||||
|
||||
def __post_init__(self):
|
||||
if not self.regs:
|
||||
self.regs = [0, 0, 0, 0]
|
||||
|
||||
|
||||
class Simulator:
|
||||
def __init__(self, program: bytes):
|
||||
self.ram = bytearray(256)
|
||||
for i, b in enumerate(program[:256]):
|
||||
self.ram[i] = b
|
||||
self.cpu = CPU()
|
||||
self.program_size = len(program)
|
||||
|
||||
|
||||
# ----------------- utilitaires mémoire / pile -----------------
|
||||
|
||||
def fetch_byte(self) -> int:
|
||||
b = self.ram[self.cpu.pc]
|
||||
self.cpu.pc = (self.cpu.pc + 1) & 0xFF
|
||||
return b
|
||||
|
||||
def push(self, value: int):
|
||||
if self.cpu.sp < 0:
|
||||
raise RuntimeError("STACK OVERFLOW")
|
||||
self.ram[self.cpu.sp] = value & 0xFF
|
||||
self.cpu.sp -= 1
|
||||
|
||||
def pop(self) -> int:
|
||||
if self.cpu.sp >= 255:
|
||||
return 0
|
||||
self.cpu.sp += 1
|
||||
return self.ram[self.cpu.sp]
|
||||
|
||||
# ----------------- exécution d'une instruction -----------------
|
||||
|
||||
def step(self):
|
||||
c = self.cpu
|
||||
pc_before = c.pc
|
||||
b = self.fetch_byte()
|
||||
|
||||
instr = ""
|
||||
size = 1 # taille en octets (1 ou 2)
|
||||
extra_cycles = 0 # pour LDR/STR/TIM
|
||||
|
||||
# --- instructions 2 octets à opcode fixe ---
|
||||
#print(pc_before)
|
||||
#print(self.program_size)
|
||||
if c.after_ret:
|
||||
instr = f"DB 0x{b:02X}"
|
||||
|
||||
elif b == 0x00: # CALL _label
|
||||
addr = self.fetch_byte()
|
||||
size = 2
|
||||
instr = f"CALL {addr}"
|
||||
self.push(c.pc)
|
||||
c.pc = addr
|
||||
|
||||
elif b == 0x40: # JMP _label
|
||||
addr = self.fetch_byte()
|
||||
size = 2
|
||||
instr = f"JMP {addr}"
|
||||
c.pc = addr
|
||||
|
||||
elif b == 0xC0: # JLT _label
|
||||
addr = self.fetch_byte()
|
||||
size = 2
|
||||
instr = f"JLT {addr}"
|
||||
if c.lt == 1:
|
||||
c.pc = addr
|
||||
|
||||
elif b == 0x20: # JEQ _label
|
||||
addr = self.fetch_byte()
|
||||
size = 2
|
||||
instr = f"JEQ {addr}"
|
||||
if c.eq == 1:
|
||||
c.pc = addr
|
||||
|
||||
elif b == 0x80: # RET
|
||||
instr = "RET"
|
||||
ret = self.pop()
|
||||
if c.sp >= 255 and ret == 0:
|
||||
c.after_ret = True
|
||||
c.running = False
|
||||
else:
|
||||
c.pc = ret
|
||||
|
||||
# --- PUSH / POP ---
|
||||
elif (b & 0b11111100) == 0b10100000: # PUSH Rx
|
||||
r = b & 0b11
|
||||
instr = f"PUSH R{r}"
|
||||
self.push(c.regs[r])
|
||||
|
||||
elif (b & 0b11111100) == 0b01100000: # POP Rx
|
||||
r = b & 0b11
|
||||
instr = f"POP R{r}"
|
||||
c.regs[r] = self.pop()
|
||||
|
||||
# --- MOV Rx valeur / SUB Rx valeur / CMP Rx valeur ---
|
||||
elif (b & 0b11111100) == 0b11100000: # MOV Rx valeur
|
||||
r = b & 0b11
|
||||
imm = self.fetch_byte()
|
||||
size = 2
|
||||
instr = f"MOV R{r}, {imm}"
|
||||
c.regs[r] = imm
|
||||
|
||||
elif (b & 0b11111100) == 0b00010000: # SUB Rx valeur
|
||||
r = b & 0b11
|
||||
imm = self.fetch_byte()
|
||||
size = 2
|
||||
instr = f"SUB R{r}, {imm}"
|
||||
c.regs[r] = (c.regs[r] - imm) & 0xFF
|
||||
|
||||
elif (b & 0b11111100) == 0b10010000: # CMP Rx valeur
|
||||
r = b & 0b11
|
||||
imm = self.fetch_byte()
|
||||
size = 2
|
||||
instr = f"CMP R{r}, {imm}"
|
||||
v = c.regs[r]
|
||||
c.lt = 1 if v < imm else 0
|
||||
c.eq = 1 if v == imm else 0
|
||||
|
||||
# --- MOV / SUB / CMP registre-registre ---
|
||||
elif (b & 0b11110000) == 0b01010000: # MOV Rx Ry
|
||||
dst = (b >> 2) & 0b11
|
||||
src = b & 0b11
|
||||
instr = f"MOV R{dst}, R{src}"
|
||||
c.regs[dst] = c.regs[src]
|
||||
|
||||
elif (b & 0b11110000) == 0b11010000: # SUB Rx Ry
|
||||
dst = (b >> 2) & 0b11
|
||||
src = b & 0b11
|
||||
instr = f"SUB R{dst}, R{src}"
|
||||
c.regs[dst] = (c.regs[dst] - c.regs[src]) & 0xFF
|
||||
|
||||
elif (b & 0b11110000) == 0b00110000: # CMP Rx Ry
|
||||
dst = (b >> 2) & 0b11
|
||||
src = b & 0b11
|
||||
instr = f"CMP R{dst}, R{src}"
|
||||
v1 = c.regs[dst]
|
||||
v2 = c.regs[src]
|
||||
c.lt = 1 if v1 < v2 else 0
|
||||
c.eq = 1 if v1 == v2 else 0
|
||||
|
||||
# --- LDR / STR (2 octets, 3 cycles) ---
|
||||
elif (b & 0b11110000) == 0b10110000: # LDR Rx Ry _label
|
||||
dst = (b >> 2) & 0b11
|
||||
src = b & 0b11
|
||||
addr = self.fetch_byte()
|
||||
size = 2
|
||||
instr = f"LDR R{dst}, R{src}, {addr}"
|
||||
eff = (addr + c.regs[src]) & 0xFF
|
||||
c.regs[dst] = self.ram[eff]
|
||||
extra_cycles = 1 # 2 octets -> 2 cycles +1 = 3
|
||||
|
||||
elif (b & 0b11110000) == 0b01110000: # STR Rx Ry _label
|
||||
dst = (b >> 2) & 0b11
|
||||
src = b & 0b11
|
||||
addr = self.fetch_byte()
|
||||
size = 2
|
||||
instr = f"STR R{dst}, R{src}, {addr}"
|
||||
eff = (addr + c.regs[src]) & 0xFF
|
||||
self.ram[eff] = c.regs[dst] & 0xFF
|
||||
extra_cycles = 1
|
||||
|
||||
# --- OUT Rx ---
|
||||
elif (b & 0b11111100) == 0b11110000: # OUT Rx
|
||||
r = b & 0b11
|
||||
instr = f"OUT R{r}"
|
||||
print(f"[OUT] R{r} = {c.regs[r]}")
|
||||
|
||||
# --- TIM valeur ---
|
||||
elif b == 0xF8: # TIM
|
||||
second = self.fetch_byte()
|
||||
size = 2
|
||||
m = (second >> 7) & 0x1
|
||||
v = second & 0x7F
|
||||
instr = f"TIM m={m}, v={v}"
|
||||
mult = 1 if m == 0 else 100
|
||||
pause_ms = mult * (v + 1)
|
||||
c.cycles += pause_ms # modélisation de la pause
|
||||
|
||||
# if pc_before >= self.program_size:
|
||||
# if 32 <= b <= 126:
|
||||
# instr = f"DB 0x{b:02X} ('{chr(b)}')"
|
||||
# else:
|
||||
# instr = f"DB 0x{b:02X}"
|
||||
else:
|
||||
instr = f"UNKNOWN 0x{b:02X}"
|
||||
c.running = False
|
||||
|
||||
|
||||
|
||||
# calcul des cycles
|
||||
if (b & 0b11110000) in (0xB0, 0x70): # LDR / STR
|
||||
c.cycles += 3
|
||||
cycles_added = 3
|
||||
else:
|
||||
c.cycles += size
|
||||
cycles_added = size
|
||||
|
||||
self.report(pc_before, instr, cycles_added)
|
||||
|
||||
# ----------------- rapport d'exécution -----------------
|
||||
|
||||
def report(self, pc_before: int, instr: str, cycles_added: int):
|
||||
c = self.cpu
|
||||
regs_str = " ".join(f"R{i}={c.regs[i]:02X}" for i in range(4))
|
||||
print(f"PC={pc_before:02X} {instr:20s} +Cycles={cycles_added:3d} Total={c.cycles}")
|
||||
print(f" {regs_str} LT={c.lt} EQ={c.eq} SP={c.sp}")
|
||||
print("-" * 60)
|
||||
|
||||
# ----------------- boucle principale -----------------
|
||||
|
||||
def run(self, max_steps: int = 100000):
|
||||
steps = 0
|
||||
while self.cpu.running and steps < max_steps:
|
||||
self.step()
|
||||
steps += 1
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# LECTURE D'UN FICHIER .bin ET LANCEMENT
|
||||
# ---------------------------------------------------------
|
||||
if __name__ == "__main__":
|
||||
# Nom du fichier binaire à exécuter
|
||||
path =""
|
||||
args= sys.argv
|
||||
if (len(args) > 1):
|
||||
filename = args[1]
|
||||
print("filename: " + filename)
|
||||
with open(filename, "rb") as f:
|
||||
program = f.read()
|
||||
sim = Simulator(program)
|
||||
sim.run()
|
||||
else:
|
||||
print("Needs *.bin as parameter")
|
||||
BIN
programme.bin
Normal file
BIN
programme.bin
Normal file
Binary file not shown.
17
programme.py
Normal file
17
programme.py
Normal file
@ -0,0 +1,17 @@
|
||||
program = bytes([
|
||||
0b10100001, # PUSH R1
|
||||
0b11100000, 0b00001111, # MOV R0, 15
|
||||
0b11100001, 0b00000001, # MOV R1, 1
|
||||
0b11010001, # SUB R0, R1
|
||||
0b10010000, 0b00000000, # CMP R0, 0
|
||||
0b00100000, 0b00001110, # JEQ 14
|
||||
0b01000000, 0b00000101, # JMP 5
|
||||
0b00000000, # DB 0
|
||||
0b01000011, # 'C'
|
||||
0b01100001, # POP R1
|
||||
0b11100000, 0b01000001, # MOV R0, 'A'
|
||||
0b10000000 # RET
|
||||
])
|
||||
|
||||
with open("programme.bin", "wb") as f:
|
||||
f.write(program)
|
||||
BIN
test_bin_epreuve3/call_label.bin
Normal file
BIN
test_bin_epreuve3/call_label.bin
Normal file
Binary file not shown.
1
test_bin_epreuve3/cmp_reg.bin
Normal file
1
test_bin_epreuve3/cmp_reg.bin
Normal file
@ -0,0 +1 @@
|
||||
0123456789:;<=>?
|
||||
1
test_bin_epreuve3/cmp_val.bin
Normal file
1
test_bin_epreuve3/cmp_val.bin
Normal file
@ -0,0 +1 @@
|
||||
<EFBFBD>‘˙’a“z<E2809C>B‘X’0“9
|
||||
BIN
test_bin_epreuve3/db1.bin
Normal file
BIN
test_bin_epreuve3/db1.bin
Normal file
Binary file not shown.
1
test_bin_epreuve3/db2.bin
Normal file
1
test_bin_epreuve3/db2.bin
Normal file
@ -0,0 +1 @@
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
1
test_bin_epreuve3/db3.bin
Normal file
1
test_bin_epreuve3/db3.bin
Normal file
@ -0,0 +1 @@
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
1
test_bin_epreuve3/db4.bin
Normal file
1
test_bin_epreuve3/db4.bin
Normal file
@ -0,0 +1 @@
|
||||
0123456789
|
||||
BIN
test_bin_epreuve3/jeq_label.bin
Normal file
BIN
test_bin_epreuve3/jeq_label.bin
Normal file
Binary file not shown.
BIN
test_bin_epreuve3/jlt_label.bin
Normal file
BIN
test_bin_epreuve3/jlt_label.bin
Normal file
Binary file not shown.
BIN
test_bin_epreuve3/jmp_label.bin
Normal file
BIN
test_bin_epreuve3/jmp_label.bin
Normal file
Binary file not shown.
BIN
test_bin_epreuve3/ldr_label.bin
Normal file
BIN
test_bin_epreuve3/ldr_label.bin
Normal file
Binary file not shown.
1
test_bin_epreuve3/mov_reg.bin
Normal file
1
test_bin_epreuve3/mov_reg.bin
Normal file
@ -0,0 +1 @@
|
||||
PQRSTUVWXYZ[\]^_
|
||||
1
test_bin_epreuve3/mov_val.bin
Normal file
1
test_bin_epreuve3/mov_val.bin
Normal file
@ -0,0 +1 @@
|
||||
<EFBFBD><01><><EFBFBD>a<EFBFBD>z<EFBFBD>B<EFBFBD>X<EFBFBD>0<EFBFBD>9
|
||||
1
test_bin_epreuve3/out.bin
Normal file
1
test_bin_epreuve3/out.bin
Normal file
@ -0,0 +1 @@
|
||||
πρςσ
|
||||
1
test_bin_epreuve3/pop.bin
Normal file
1
test_bin_epreuve3/pop.bin
Normal file
@ -0,0 +1 @@
|
||||
`abc
|
||||
1
test_bin_epreuve3/push.bin
Normal file
1
test_bin_epreuve3/push.bin
Normal file
@ -0,0 +1 @@
|
||||
<EFBFBD>。「」
|
||||
BIN
test_bin_epreuve3/str_label.bin
Normal file
BIN
test_bin_epreuve3/str_label.bin
Normal file
Binary file not shown.
1
test_bin_epreuve3/sub_reg.bin
Normal file
1
test_bin_epreuve3/sub_reg.bin
Normal file
@ -0,0 +1 @@
|
||||
ΠΡ<EFBFBD>ΣΤΥΦΧΨΩΪΫάέήί
|
||||
1
test_bin_epreuve3/sub_val.bin
Normal file
1
test_bin_epreuve3/sub_val.bin
Normal file
@ -0,0 +1 @@
|
||||
˙azBX09
|
||||
BIN
test_bin_epreuve3/tim.bin
Normal file
BIN
test_bin_epreuve3/tim.bin
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user