24H_du_code_2026/Epreuve2.py
2026-03-22 00:16:34 +01:00

179 lines
7.6 KiB
Python

import sys
# --- Configuration des instructions (Inchangée) ---
instructions = {
"DB": {"ins": "DB", "args": [{"isRegister": False, "isValue": True, "isLabel": False}]},
"CALL": {"ins": "CALL", "args": [{"isRegister": False, "isValue": False, "isLabel": True}]},
"RET": {"ins": "RET", "args": []},
"JMP": {"ins": "JMP", "args": [{"isRegister": False, "isValue": False, "isLabel": True}]},
"JLT": {"ins": "JLT", "args": [{"isRegister": False, "isValue": False, "isLabel": True}]},
"JEQ": {"ins": "JEQ", "args": [{"isRegister": False, "isValue": False, "isLabel": True}]},
"PUSH": {"ins": "PUSH", "args": [{"isRegister": True, "isValue": False, "isLabel": False}]},
"POP": {"ins": "POP", "args": [{"isRegister": True, "isValue": False, "isLabel": False}]},
"MOV": {"ins": "MOV", "args": [{"isRegister": True, "isValue": False, "isLabel": False}, {"isRegister": True, "isValue": True, "isLabel": False}]},
"SUB": {"ins": "SUB", "args": [{"isRegister": True, "isValue": False, "isLabel": False}, {"isRegister": True, "isValue": True, "isLabel": False}]},
"CMP": {"ins": "CMP", "args": [{"isRegister": True, "isValue": False, "isLabel": False}, {"isRegister": True, "isValue": True, "isLabel": False}]},
"LDR": {"ins": "LDR", "args": [{"isRegister": True, "isValue": False, "isLabel": False}, {"isRegister": True, "isValue": False, "isLabel": False}, {"isRegister": False, "isValue": False, "isLabel": True}]},
"STR": {"ins": "STR", "args": [{"isRegister": True, "isValue": False, "isLabel": False}, {"isRegister": True, "isValue": False, "isLabel": False}, {"isRegister": False, "isValue": False, "isLabel": True}]},
"OUT": {"ins": "OUT", "args": [{"isRegister": True, "isValue": False, "isLabel": False}]},
"TIM": {"ins": "TIM", "args": [{"isRegister": False, "isValue": True, "isLabel": False}]}
}
# --- Fonctions Utilitaires (Inchangées) ---
def valueToInt(arg):
try: return int(arg)
except: return ord(arg[1])
def registerToDec(reg): return int(reg[1])
def testArgIsRegister(arg):
if len(arg) != 2 or arg[0] != "R": return False
try: return 0 <= int(arg[1]) <= 3
except: return False
def testArgIsValue(arg):
try:
if 0 <= int(arg) <= 255: return True
except: pass
if len(arg) == 3 and arg[0] == arg[2] == "'": return True
return False
def testArgIsLabel(arg, twoDotsIncluded=False):
if not arg or arg[0] != "_": return False
body = arg[1:-1] if twoDotsIncluded else arg[1:]
if twoDotsIncluded and arg[-1] != ":": return False
return all(c in "abcdefghijklmnopqrstuvwxyz0123456789_" for c in body)
# --- Fonctions de Conversion (Inchangées) ---
def convertInsDB(args): return {"opcode": [valueToInt(args[0])], "is_db": True}
def convertInsCALL(args): return {"opcode": [0x00, "label"], "label": args[0]}
def convertInsRET(args): return {"opcode": [0x80]}
def convertInsJMP(args): return {"opcode": [0x40, "label"], "label": args[0]}
def convertInsJLT(args): return {"opcode": [0xC0, "label"], "label": args[0]}
def convertInsJEQ(args): return {"opcode": [0x20, "label"], "label": args[0]}
def convertInsPUSH(args): return {"opcode": [0xA0 | registerToDec(args[0])]}
def convertInsPOP(args): return {"opcode": [0x60 | registerToDec(args[0])]}
def convertInsMOV(args):
idReg0 = registerToDec(args[0])
if testArgIsRegister(args[1]): return {"opcode": [0x50 | (idReg0 << 2) | registerToDec(args[1])]}
return {"opcode": [0xE0 | idReg0, valueToInt(args[1])]}
def convertInsSUB(args):
idReg0 = registerToDec(args[0])
if testArgIsRegister(args[1]): return {"opcode": [0xD0 | (idReg0 << 2) | registerToDec(args[1])]}
return {"opcode": [0x10 | idReg0, valueToInt(args[1])]}
def convertInsCMP(args):
idReg0 = registerToDec(args[0])
if testArgIsRegister(args[1]): return {"opcode": [0x30 | (idReg0 << 2) | registerToDec(args[1])]}
return {"opcode": [0x90 | idReg0, valueToInt(args[1])]}
def convertInsLDR(args):
return {"opcode": [0xB0 | (registerToDec(args[0]) << 2) | registerToDec(args[1]), "label"], "label": args[2]}
def convertInsSTR(args):
return {"opcode": [0x70 | (registerToDec(args[0]) << 2) | registerToDec(args[1]), "label"], "label": args[2]}
def convertInsOUT(args): return {"opcode": [0xF0 | registerToDec(args[0])]}
def convertInsTIM(args): return {"opcode": [0xF8, valueToInt(args[0])]}
# --- Assembleur ---
def assemble(path):
labels = {}
code_elements = []
data_elements = []
with open(path, "r") as f:
lines = f.readlines()
current_pending_labels = []
for line_num, line in enumerate(lines, 1):
line = line.split(";")[0].strip()
if not line: continue
parts = line.split()
# Traitement des labels (on peut en avoir plusieurs de suite)
while parts and testArgIsLabel(parts[0], True):
label_name = parts[0][:-1]
current_pending_labels.append(label_name)
parts = parts[1:] # On retire le label et on continue sur la même ligne
if not parts: continue # Ligne ne contenait que des labels
instr_name = parts[0]
args = parts[1:]
try:
res = globals()[f"convertIns{instr_name}"](args)
res["attached_labels"] = current_pending_labels
current_pending_labels = []
if res.get("is_db"):
data_elements.append(res)
else:
code_elements.append(res)
except Exception as e:
print(f"ERROR Line {line_num}: {instr_name} -> {e}")
sys.exit(1)
# Si des labels traînent à la toute fin du fichier
if current_pending_labels:
# On les attache à un élément factice à la fin de la data
data_elements.append({"opcode": [], "attached_labels": current_pending_labels, "is_db": True})
# CALCUL DES ADRESSES FINALES
final_labels = {}
current_pc = 0
# 1. On passe sur le CODE d'abord
for item in code_elements:
for lbl in item["attached_labels"]:
final_labels[lbl] = current_pc
current_pc += len(item["opcode"])
# 2. On passe sur la DATA ensuite
for item in data_elements:
for lbl in item["attached_labels"]:
final_labels[lbl] = current_pc
current_pc += len(item["opcode"])
# GÉNÉRATION DU BYTECODE
final_bytecode = []
# Ordre : Code puis Data
for item in code_elements + data_elements:
for op in item["opcode"]:
if op == "label":
label_target = item["label"]
if label_target not in final_labels:
print(f"ERROR: Label '{label_target}' missing!")
sys.exit(1)
final_bytecode.append(final_labels[label_target])
else:
final_bytecode.append(op)
return final_bytecode, final_labels
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python asm.py <file.asm>")
sys.exit(1)
path = sys.argv[1]
bytecode, labels_map = assemble(path)
# Affichage propre
print("\n" + "="*50)
print(f" ASSEMBLY PREVIEW: {path}")
print("="*50)
print(f"{'ADDR':<7} | {'HEX':<5} | {'BINARY':<10}")
print("-" * 30)
for i, b in enumerate(bytecode):
# On cherche si un label pointe ici pour l'afficher
lbl_str = ""
for name, addr in labels_map.items():
if addr == i: lbl_str += f" ({name})"
print(f"0x{i:02X} | {b:02x} | {b:08b} {lbl_str}")
print("="*50 + "\n")
with open(path + ".bin", "wb") as file:
file.write(bytes(bytecode))
print(f"Success: {path}.bin generated.")