From 6ae130c794250731cd81b86d024e8b2feb665059 Mon Sep 17 00:00:00 2001 From: BalkisJerad Date: Sat, 21 Mar 2026 18:38:18 +0100 Subject: [PATCH] Epreuve 3 --- Epreuve3.py | 263 +++++++++++++++++++++++++++++++ programme.bin | Bin 0 -> 18 bytes programme.py | 17 ++ test_bin_epreuve3/call_label.bin | Bin 0 -> 12 bytes test_bin_epreuve3/cmp_reg.bin | 1 + test_bin_epreuve3/cmp_val.bin | 1 + test_bin_epreuve3/db1.bin | Bin 0 -> 25 bytes test_bin_epreuve3/db2.bin | 1 + test_bin_epreuve3/db3.bin | 1 + test_bin_epreuve3/db4.bin | 1 + test_bin_epreuve3/jeq_label.bin | Bin 0 -> 8 bytes test_bin_epreuve3/jlt_label.bin | Bin 0 -> 8 bytes test_bin_epreuve3/jmp_label.bin | Bin 0 -> 8 bytes test_bin_epreuve3/ldr_label.bin | Bin 0 -> 8 bytes test_bin_epreuve3/mov_reg.bin | 1 + test_bin_epreuve3/mov_val.bin | 1 + test_bin_epreuve3/out.bin | 1 + test_bin_epreuve3/pop.bin | 1 + test_bin_epreuve3/push.bin | 1 + test_bin_epreuve3/str_label.bin | Bin 0 -> 8 bytes test_bin_epreuve3/sub_reg.bin | 1 + test_bin_epreuve3/sub_val.bin | 1 + test_bin_epreuve3/tim.bin | Bin 0 -> 8 bytes 23 files changed, 292 insertions(+) create mode 100644 Epreuve3.py create mode 100644 programme.bin create mode 100644 programme.py create mode 100644 test_bin_epreuve3/call_label.bin create mode 100644 test_bin_epreuve3/cmp_reg.bin create mode 100644 test_bin_epreuve3/cmp_val.bin create mode 100644 test_bin_epreuve3/db1.bin create mode 100644 test_bin_epreuve3/db2.bin create mode 100644 test_bin_epreuve3/db3.bin create mode 100644 test_bin_epreuve3/db4.bin create mode 100644 test_bin_epreuve3/jeq_label.bin create mode 100644 test_bin_epreuve3/jlt_label.bin create mode 100644 test_bin_epreuve3/jmp_label.bin create mode 100644 test_bin_epreuve3/ldr_label.bin create mode 100644 test_bin_epreuve3/mov_reg.bin create mode 100644 test_bin_epreuve3/mov_val.bin create mode 100644 test_bin_epreuve3/out.bin create mode 100644 test_bin_epreuve3/pop.bin create mode 100644 test_bin_epreuve3/push.bin create mode 100644 test_bin_epreuve3/str_label.bin create mode 100644 test_bin_epreuve3/sub_reg.bin create mode 100644 test_bin_epreuve3/sub_val.bin create mode 100644 test_bin_epreuve3/tim.bin diff --git a/Epreuve3.py b/Epreuve3.py new file mode 100644 index 0000000..f6876d0 --- /dev/null +++ b/Epreuve3.py @@ -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") diff --git a/programme.bin b/programme.bin new file mode 100644 index 0000000000000000000000000000000000000000..d6049e9f949f840a7e4fc0d499bd4bd801780254 GIT binary patch literal 18 ZcmZ4Zfd3)m#R&`wd=9J(&WR5k8vsNk28;jz literal 0 HcmV?d00001 diff --git a/programme.py b/programme.py new file mode 100644 index 0000000..e649a52 --- /dev/null +++ b/programme.py @@ -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) diff --git a/test_bin_epreuve3/call_label.bin b/test_bin_epreuve3/call_label.bin new file mode 100644 index 0000000000000000000000000000000000000000..a223f5021a35708fc118eda8f44bf079f0cea8da GIT binary patch literal 12 TcmZQzYhd7PU|?=wU}yjU3#9@R literal 0 HcmV?d00001 diff --git a/test_bin_epreuve3/cmp_reg.bin b/test_bin_epreuve3/cmp_reg.bin new file mode 100644 index 0000000..30c6288 --- /dev/null +++ b/test_bin_epreuve3/cmp_reg.bin @@ -0,0 +1 @@ +0123456789:;<=>? \ No newline at end of file diff --git a/test_bin_epreuve3/cmp_val.bin b/test_bin_epreuve3/cmp_val.bin new file mode 100644 index 0000000..b183244 --- /dev/null +++ b/test_bin_epreuve3/cmp_val.bin @@ -0,0 +1 @@ +azBX09 \ No newline at end of file diff --git a/test_bin_epreuve3/db1.bin b/test_bin_epreuve3/db1.bin new file mode 100644 index 0000000000000000000000000000000000000000..137b09d6bcccce70fa46311c7c2e35274bb27f0b GIT binary patch literal 25 gcmZQzWMXDvWn<^y}W3 literal 0 HcmV?d00001 diff --git a/test_bin_epreuve3/jlt_label.bin b/test_bin_epreuve3/jlt_label.bin new file mode 100644 index 0000000000000000000000000000000000000000..63bbe01bd40046ab0188a3dce803edb6eb93d2fb GIT binary patch literal 8 PcmX@Wa)9js(*Xtm4@d(I literal 0 HcmV?d00001 diff --git a/test_bin_epreuve3/jmp_label.bin b/test_bin_epreuve3/jmp_label.bin new file mode 100644 index 0000000000000000000000000000000000000000..d0ecd957100da084a86f8c0a24c1cfc217c2ecff GIT binary patch literal 8 PcmZ=@abR;`a$o=e1xNu6 literal 0 HcmV?d00001 diff --git a/test_bin_epreuve3/ldr_label.bin b/test_bin_epreuve3/ldr_label.bin new file mode 100644 index 0000000000000000000000000000000000000000..dcbedf99b9b4ab433b6b04d3f72335d0df6c944e GIT binary patch literal 8 PcmdnUvW;yw(;fx@4tN6V literal 0 HcmV?d00001 diff --git a/test_bin_epreuve3/mov_reg.bin b/test_bin_epreuve3/mov_reg.bin new file mode 100644 index 0000000..bc3d563 --- /dev/null +++ b/test_bin_epreuve3/mov_reg.bin @@ -0,0 +1 @@ +PQRSTUVWXYZ[\]^_ \ No newline at end of file diff --git a/test_bin_epreuve3/mov_val.bin b/test_bin_epreuve3/mov_val.bin new file mode 100644 index 0000000..1a8aede --- /dev/null +++ b/test_bin_epreuve3/mov_val.bin @@ -0,0 +1 @@ +azBX09 \ No newline at end of file diff --git a/test_bin_epreuve3/out.bin b/test_bin_epreuve3/out.bin new file mode 100644 index 0000000..d96c762 --- /dev/null +++ b/test_bin_epreuve3/out.bin @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test_bin_epreuve3/pop.bin b/test_bin_epreuve3/pop.bin new file mode 100644 index 0000000..ddadce8 --- /dev/null +++ b/test_bin_epreuve3/pop.bin @@ -0,0 +1 @@ +`abc \ No newline at end of file diff --git a/test_bin_epreuve3/push.bin b/test_bin_epreuve3/push.bin new file mode 100644 index 0000000..6395729 --- /dev/null +++ b/test_bin_epreuve3/push.bin @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test_bin_epreuve3/str_label.bin b/test_bin_epreuve3/str_label.bin new file mode 100644 index 0000000000000000000000000000000000000000..2e2e047a0ec6d200b31d7674ff0f7f11ba77e52b GIT binary patch literal 8 PcmXS9DPyZC33vhP literal 0 HcmV?d00001 diff --git a/test_bin_epreuve3/sub_reg.bin b/test_bin_epreuve3/sub_reg.bin new file mode 100644 index 0000000..f86b4cd --- /dev/null +++ b/test_bin_epreuve3/sub_reg.bin @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test_bin_epreuve3/sub_val.bin b/test_bin_epreuve3/sub_val.bin new file mode 100644 index 0000000..6e1a122 --- /dev/null +++ b/test_bin_epreuve3/sub_val.bin @@ -0,0 +1 @@ +azBX09 \ No newline at end of file diff --git a/test_bin_epreuve3/tim.bin b/test_bin_epreuve3/tim.bin new file mode 100644 index 0000000000000000000000000000000000000000..3a5ceabafddcd3c35e560f9c44792f2f9592d941 GIT binary patch literal 8 Pcmeyt@PqM3!;k*}73>9J literal 0 HcmV?d00001