diff options
Diffstat (limited to 'src/assembler.py')
| -rwxr-xr-x | src/assembler.py | 215 |
1 files changed, 31 insertions, 184 deletions
diff --git a/src/assembler.py b/src/assembler.py index 7420a04..3a1d39f 100755 --- a/src/assembler.py +++ b/src/assembler.py @@ -2,6 +2,10 @@ # Assemble ATK16 assembly to bytecode import sys +from typing import Callable +import importlib +from assembler_ops import * +from assembler_eval import * if len(sys.argv) != 3: print("usage: assembler.py <infile> <outfile> # read from file") @@ -43,50 +47,11 @@ def parse(line: str) -> list[str]: result.append(acc) return list(filter(lambda x: len(x) > 0, result)) -def eval_expr(expr: str) -> int: - expr = eval_symbol(expr) - return eval(expr, labels.copy()) # eval as Python expr - -constants: dict[str, str] = { - # Registers - "rz": "0", - "ra": "1", - "rb": "2", - "rc": "3", - "rd": "4", - "rf": "5", - "rg": "6", - # ALU instructions - "al_plus": "0", - "al_minus": "1", - "al_and": "2", - "al_or": "3", - "al_xor": "4", - "al_shift_lr": "5", - "al_shift_ar": "6", - "al_shift_ll": "7", - # ALU flags - "f_carry": "0", - "f_overflow": "1", - "f_zero": "2", - "f_sign": "3", -} - -def eval_symbol(c: str): - if c in labels: - return str(labels[c]) - - if c in constants: - return constants[c] - - return c - -# 1st pass, gather labels, set options +# 1st pass, gather labels, set options, eval operations options: dict[str, str] = { "stack_pointer": "6" # RG } -labels: dict[str, int] = {} address: int = 0 for (lineNo, line) in enumerate(src_lines): @@ -104,6 +69,15 @@ for (lineNo, line) in enumerate(src_lines): opt_name = args[0] opt_value = constants.get(args[1], args[1]) options[opt_name] = opt_value + case "@use": + module_name, ops = args[0].split(":") + ops_split = ops.split(",") + module = importlib.import_module(module_name) + mod_operations: dict[str, Callable[..., list[int]]] = module.operations + for op in mod_operations: + callable = mod_operations[op] + if ops == "*" or op in ops_split: + operations[op] = callable case _: pass @@ -111,98 +85,6 @@ for (lineNo, line) in enumerate(src_lines): # 2nd pass -def make_alr(alu_op: str, left: str, right: str, target: str) -> list[int]: - """ALR 0000 TTTL LLRR RSSS""" - target_e = eval_expr(target) - left_e = eval_expr(left) - right_e = eval_expr(right) - alu_op_e = eval_expr(alu_op) - word = (0b0000 << 12) + \ - (target_e << 9) + \ - (left_e << 6) + \ - (right_e << 3) + \ - alu_op_e - return [word] - -def make_ali(alu_op: str, left: str, imm: str, target: str) -> list[int]: - """ALI 0001 TTTL LLII ISSS""" - target_e = eval_expr(target) - left_e = eval_expr(left) - imm_e = eval_expr(imm) - alu_op_e = eval_expr(alu_op) - word = (0b0001 << 12) + \ - (target_e << 9) + \ - (left_e << 6) + \ - (imm_e << 3) + \ - alu_op_e - return [word] - -def make_ldr(to_reg: str, addr_reg: str) -> list[int]: - """LDR 0010 TTTR RRXX XXXX""" - to_reg_e = eval_expr(to_reg) - addr_reg_e = eval_expr(addr_reg) - word = (0b0010 << 12) + \ - (to_reg_e << 9) + \ - (addr_reg_e << 6) - return [word] - -def make_str(from_reg: str, addr_reg: str) -> list[int]: - """STR 0011 TTTR RRXX XXXX""" - from_reg_e = eval_expr(from_reg) - addr_reg_e = eval_expr(addr_reg) - word = (0b0011 << 12) + \ - (from_reg_e << 9) + \ - (addr_reg_e << 6) - return [word] - -def make_ldi(to_reg: str, imm: str) -> list[int]: - """LDI 0100 TTTI IIII IIII""" - to_reg_e = eval_expr(to_reg) - imm_e = eval_expr(imm) - word = (0b0100 << 12) + \ - (to_reg_e << 9) + \ - imm_e - return [word] - -def make_jpr(addr_reg: str) -> list[int]: - """JPR 0101 XXXR RRXX XXXX""" - addr_reg_e = eval_expr(addr_reg) - word = (0b0101 << 12) + \ - (addr_reg_e << 6) - return [word] - -def make_jpi(address: int, imm: str) -> list[int]: - """JPI 0110 XXXI IIII IIII""" - imm_e = eval_expr(imm) - imm_e = imm_e - address - 1 - word = (0b0110 << 12) + \ - imm_e - return [word] - -def make_br(flag_s: str, addr_reg: str) -> list[int]: - """BR 0111 XFFR RRXX XXXX""" - flag_s_e = eval_expr(flag_s) - addr_reg_e = eval_expr(addr_reg) - word = (0b0111 << 12) + \ - (flag_s_e << 9) + \ - (addr_reg_e << 6) - return [word] - -def make_bri(address: int, flag_s: str, imm: str) -> list[int]: - """BRI 1000 XFFI IIII IIII""" - flag_s_e = eval_expr(flag_s) - imm_e = eval_expr(imm) - imm_e = imm_e - address - 1 - word = (0b1000 << 12) + \ - (flag_s_e << 9) + \ - imm_e - return [word] - -def make_hlt() -> list[int]: - """HLT 1111 XXXX XXXX XXXX""" - word = (0b1111 << 12) - return [word] - # def make_spu(reg: str) -> list[int]: # stack_pointer = options["stack_pointer"] # reg = eval_symbol(reg) @@ -210,7 +92,7 @@ def make_hlt() -> list[int]: # words_str: list[int] = make_str(reg, stack_pointer) # return words_inc + words_str -address = 0 +address: int = 0 nop = bytearray([0b1000_0000, 0]) result = bytearray() # initially one nop @@ -220,59 +102,24 @@ for (lineNo, line) in enumerate(src_lines): line = line.split(";")[0].strip() if line == "": continue keyword, *args = parse(line.lower()) - match keyword: - # Directives - case "@address": - address = eval_expr(args[0]) - continue - case "@label" | "@opt": - continue - # Instructions - case "alr": - words = make_alr(*args) - case "ali": - words = make_ali(*args) - case "ldr": - words = make_ldr(*args) - case "str": - words = make_str(*args) - case "ldi": - words = make_ldi(*args) - case "jpr": - words = make_jpr(*args) - case "jpi": - words = make_jpi(address, *args) - case "br": - words = make_br(*args) - case "bri": - words = make_bri(address, *args) - case "hlt": - words = make_hlt() + if keyword in operations: + words = operations[keyword](address, *args) + else: + match keyword: + # Directives + case "@address": + address = eval_expr(args[0]) + continue + case "@label" | "@opt" | "@use": + continue - # Pseudoinstructions - case "add": - words = make_alr("al_plus", *args) - case "sub": - words = make_alr("al_minus", *args) - case "inc": - words = make_ali("al_plus", args[0], "1", args[0]) - case "dec": - words = make_ali("al_minus", args[0], "1", args[0]) - case "mov": - words = make_ali("al_plus", args[0], "0", args[1]) - # case "csr": - # reg = args[0] - # words_spu = make_spu(reg) - # words = [] - # # todo finish this - - # Default case: evaluate as is (e.g. data word) - case _: - try: - words = [eval_expr(keyword)] - except: - raise Exception(f"Invalid assembly at {infile_path}:{lineNo + 1}\n\n{line}") + # Default case: evaluate as is (e.g. data word) + case _: + try: + words = [eval_expr(keyword)] + except: + raise Exception(f"Invalid assembly at {infile_path}:{lineNo + 1}\n\n{line}") if len(result) < 2 * address + 1: result.extend((2 * address + 1 - len(result)) * nop) |
