From dd3c90011ab33717e4c4175cd6804ae86582135f Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Tue, 11 Apr 2023 14:38:51 +0300 Subject: Refactor folder --- src/asm_eval.py | 47 ++++++++++++++++ src/asm_ops.py | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/asm_pass1.py | 4 +- src/asm_pass2.py | 4 +- src/asm_pass3.py | 4 +- src/asm_pass4.py | 4 +- src/assembler.py | 4 +- src/assembler_eval.py | 47 ---------------- src/assembler_ops.py | 150 -------------------------------------------------- src/ext_std.py | 2 +- src/test.atk16 | 33 ----------- src/test_alu.py | 48 ---------------- src/test_fibo.atk16 | 66 ---------------------- src/test_sum.atk16 | 3 - src/test_utils.py | 93 ------------------------------- 15 files changed, 208 insertions(+), 451 deletions(-) create mode 100644 src/asm_eval.py create mode 100644 src/asm_ops.py delete mode 100644 src/assembler_eval.py delete mode 100644 src/assembler_ops.py delete mode 100644 src/test.atk16 delete mode 100755 src/test_alu.py delete mode 100644 src/test_fibo.atk16 delete mode 100644 src/test_sum.atk16 delete mode 100644 src/test_utils.py (limited to 'src') diff --git a/src/asm_eval.py b/src/asm_eval.py new file mode 100644 index 0000000..691e4eb --- /dev/null +++ b/src/asm_eval.py @@ -0,0 +1,47 @@ +constants: dict[str, str] = { + # Registers + "ra": "0", + "rb": "1", + "rc": "2", + "rd": "3", + "re": "4", + "rf": "5", + "rg": "6", + "rh": "7", + # ALU instructions + "al_plus": "0", + "al_minus": "1", + "al_and": "2", + "al_or": "3", + "al_xor": "4", + "al_slr": "5", + "al_sar": "6", + "al_sll": "7", + # ALU flags + "carry": "0", + "overflow": "1", + "zero": "2", + "sign": "3", +} + +Labels = dict[str, int] + +def check_size(bits: int, val: int) -> None: + if val >= 2 ** bits: + raise Exception(f"Value does not fit in {bits} bits: {val}") + +def eval_symbol(labels: Labels, c: str) -> str: + if c in labels: + return str(labels[c]) + + if c in constants: + return constants[c] + + return c + +def eval_expr(labels: Labels, expr: str, bits: int = 16) -> int: + expr = expr.lower() + expr = eval_symbol(labels, expr) + ret = eval(expr, labels.copy()) # eval as Python expr + check_size(bits, ret) + return ret diff --git a/src/asm_ops.py b/src/asm_ops.py new file mode 100644 index 0000000..74e7930 --- /dev/null +++ b/src/asm_ops.py @@ -0,0 +1,150 @@ +from typing import Callable +from asm_eval import * +from dataclasses import dataclass + +@dataclass +class Options: + stack_pointer = "rf" + csr_scratch = "rh" + +@dataclass +class Meta: + address: int + +def make_alr(meta: Meta, labels: Labels, alu_op: str, left: str, right: str, target: str) -> int: + """ALR 0000 TTTL LLRR RSSS""" + target_e = eval_expr(labels, target, bits=3) + left_e = eval_expr(labels, left, bits=3) + right_e = eval_expr(labels, right, bits=3) + alu_op_e = eval_expr(labels, alu_op, bits=3) + word = (0b0000 << 12) + \ + (target_e << 9) + \ + (left_e << 6) + \ + (right_e << 3) + \ + alu_op_e + return word + +def make_ali(meta: Meta, labels: Labels, alu_op: str, left: str, imm: str, target: str) -> int: + """ALI 0001 TTTL LLII ISSS""" + target_e = eval_expr(labels, target, bits=3) + left_e = eval_expr(labels, left, bits=3) + imm_e = eval_expr(labels, imm, bits=3) + alu_op_e = eval_expr(labels, alu_op, bits=3) + word = (0b0001 << 12) + \ + (target_e << 9) + \ + (left_e << 6) + \ + (imm_e << 3) + \ + alu_op_e + return word + +def make_ldr(meta: Meta, labels: Labels, addr_reg: str, to_reg: str) -> int: + """LDR 0010 TTTR RRXX XXXX""" + to_reg_e = eval_expr(labels, to_reg, bits=3) + addr_reg_e = eval_expr(labels, addr_reg, bits=3) + word = (0b0010 << 12) + \ + (to_reg_e << 9) + \ + (addr_reg_e << 6) + return word + +def make_str(meta: Meta, labels: Labels, from_reg: str, addr_reg: str) -> int: + """STR 0011 XXXL LLRR RXXX""" + from_reg_e = eval_expr(labels, from_reg, bits=3) + addr_reg_e = eval_expr(labels, addr_reg, bits=3) + word = (0b0011 << 12) + \ + (addr_reg_e << 6) + \ + (from_reg_e << 3) + return word + +def make_ldi(meta: Meta, labels: Labels, imm: str, to_reg: str) -> int: + """LDI 0100 TTTI IIII IIII""" + to_reg_e = eval_expr(labels, to_reg, bits=3) + imm_e = eval_expr(labels, imm, bits=9) + word = (0b0100 << 12) + \ + (to_reg_e << 9) + \ + imm_e + return word + +def make_jpr(meta: Meta, labels: Labels, addr_reg: str) -> int: + """JPR 0101 XXXR RRXX XXXX""" + addr_reg_e = eval_expr(labels, addr_reg, bits=3) + word = (0b0101 << 12) + \ + (addr_reg_e << 6) + return word + +def make_jpi(meta: Meta, labels: Labels, imm: str) -> int: + """JPI 0110 XXXI IIII IIII""" + imm_e = eval_expr(labels, imm, bits=9) + imm_e = imm_e - meta.address - 1 + imm_e = imm_e & (0b111111111) + word = (0b0110 << 12) + \ + imm_e + return word + +def make_brr(meta: Meta, labels: Labels, flag_s: str, addr_reg: str) -> int: + """brr 0111 XFFR RRXX XXXX""" + flag_s_e = eval_expr(labels, flag_s, bits=2) + addr_reg_e = eval_expr(labels, addr_reg, bits=3) + word = (0b0111 << 12) + \ + (flag_s_e << 9) + \ + (addr_reg_e << 6) + return word + +def make_bri(meta: Meta, labels: Labels, flag_s: str, imm: str) -> int: + """BRI 1000 XFFI IIII IIII""" + flag_s_e = eval_expr(labels, flag_s, bits=2) + imm_e = eval_expr(labels, imm, bits=9) + imm_e = imm_e - meta.address - 1 + imm_e = imm_e & (0b111111111) + word = (0b1000 << 12) + \ + (flag_s_e << 9) + \ + imm_e + return word + +def make_lpc(meta: Meta, labels: Labels, target: str) -> int: + """LPC 1001 TTTX XXXX XXXX""" + target_e = eval_expr(labels, target, bits=3) + word = (0b1001 << 12) + \ + (target_e << 9) + return word + +def make_hlt(meta: Meta, labels: Labels) -> int: + """HLT 1111 XXXX XXXX XXXX""" + word = (0b1111 << 12) + return word + +OpWordDict = dict[str, Callable[..., int]] +operations: OpWordDict = { + "alr": make_alr, + "ali": make_ali, + "ldr": make_ldr, + "str": make_str, + "ldi": make_ldi, + "jpr": make_jpr, + "jpi": make_jpi, + "brr": make_brr, + "bri": make_bri, + "lpc": make_lpc, + "hlt": make_hlt, +} + +ExpandResult = list[list[str]] +ExpandFn = Callable[..., ExpandResult] +OpExpansionDict = dict[str, ExpandFn] + +def expand_id(*parts: str) -> ExpandResult: + return [list(parts)] + +default_expansions: OpExpansionDict = { + "alr": lambda *args: expand_id("alr", *args), + "ali": lambda *args: expand_id("ali", *args), + "ldr": lambda *args: expand_id("ldr", *args), + "str": lambda *args: expand_id("str", *args), + "ldi": lambda *args: expand_id("ldi", *args), + "jpr": lambda *args: expand_id("jpr", *args), + "jpi": lambda *args: expand_id("jpi", *args), + "brr": lambda *args: expand_id("brr", *args), + "bri": lambda *args: expand_id("bri", *args), + "lpc": lambda *args: expand_id("lpc", *args), + "hlt": lambda *args: expand_id("hlt", *args), +} + diff --git a/src/asm_pass1.py b/src/asm_pass1.py index 6537aea..606a1a1 100644 --- a/src/asm_pass1.py +++ b/src/asm_pass1.py @@ -1,7 +1,7 @@ import importlib from dataclasses import dataclass -from assembler_ops import * -from assembler_eval import * +from asm_ops import * +from asm_eval import * @dataclass class Result1Line: diff --git a/src/asm_pass2.py b/src/asm_pass2.py index 261ba06..e7f48ac 100644 --- a/src/asm_pass2.py +++ b/src/asm_pass2.py @@ -1,6 +1,6 @@ from dataclasses import dataclass -from assembler_ops import * -from assembler_eval import * +from asm_ops import * +from asm_eval import * from asm_pass1 import * @dataclass diff --git a/src/asm_pass3.py b/src/asm_pass3.py index e8e44d3..038e3f7 100644 --- a/src/asm_pass3.py +++ b/src/asm_pass3.py @@ -1,6 +1,6 @@ from dataclasses import dataclass -from assembler_ops import * -from assembler_eval import * +from asm_ops import * +from asm_eval import * from asm_pass2 import * @dataclass diff --git a/src/asm_pass4.py b/src/asm_pass4.py index 926b354..3d4f45c 100644 --- a/src/asm_pass4.py +++ b/src/asm_pass4.py @@ -1,6 +1,6 @@ from dataclasses import dataclass -from assembler_ops import * -from assembler_eval import * +from asm_ops import * +from asm_eval import * from asm_pass3 import * @dataclass diff --git a/src/assembler.py b/src/assembler.py index 4e82deb..3f0c8bc 100755 --- a/src/assembler.py +++ b/src/assembler.py @@ -2,8 +2,8 @@ # Assemble ATK16 assembly to bytecode import sys -from assembler_ops import * -from assembler_eval import * +from asm_ops import * +from asm_eval import * from asm_pass1 import pass_1 from asm_pass2 import pass_2 from asm_pass3 import pass_3 diff --git a/src/assembler_eval.py b/src/assembler_eval.py deleted file mode 100644 index 691e4eb..0000000 --- a/src/assembler_eval.py +++ /dev/null @@ -1,47 +0,0 @@ -constants: dict[str, str] = { - # Registers - "ra": "0", - "rb": "1", - "rc": "2", - "rd": "3", - "re": "4", - "rf": "5", - "rg": "6", - "rh": "7", - # ALU instructions - "al_plus": "0", - "al_minus": "1", - "al_and": "2", - "al_or": "3", - "al_xor": "4", - "al_slr": "5", - "al_sar": "6", - "al_sll": "7", - # ALU flags - "carry": "0", - "overflow": "1", - "zero": "2", - "sign": "3", -} - -Labels = dict[str, int] - -def check_size(bits: int, val: int) -> None: - if val >= 2 ** bits: - raise Exception(f"Value does not fit in {bits} bits: {val}") - -def eval_symbol(labels: Labels, c: str) -> str: - if c in labels: - return str(labels[c]) - - if c in constants: - return constants[c] - - return c - -def eval_expr(labels: Labels, expr: str, bits: int = 16) -> int: - expr = expr.lower() - expr = eval_symbol(labels, expr) - ret = eval(expr, labels.copy()) # eval as Python expr - check_size(bits, ret) - return ret diff --git a/src/assembler_ops.py b/src/assembler_ops.py deleted file mode 100644 index b55927b..0000000 --- a/src/assembler_ops.py +++ /dev/null @@ -1,150 +0,0 @@ -from typing import Callable -from assembler_eval import * -from dataclasses import dataclass - -@dataclass -class Options: - stack_pointer = "rf" - csr_scratch = "rh" - -@dataclass -class Meta: - address: int - -def make_alr(meta: Meta, labels: Labels, alu_op: str, left: str, right: str, target: str) -> int: - """ALR 0000 TTTL LLRR RSSS""" - target_e = eval_expr(labels, target, bits=3) - left_e = eval_expr(labels, left, bits=3) - right_e = eval_expr(labels, right, bits=3) - alu_op_e = eval_expr(labels, alu_op, bits=3) - word = (0b0000 << 12) + \ - (target_e << 9) + \ - (left_e << 6) + \ - (right_e << 3) + \ - alu_op_e - return word - -def make_ali(meta: Meta, labels: Labels, alu_op: str, left: str, imm: str, target: str) -> int: - """ALI 0001 TTTL LLII ISSS""" - target_e = eval_expr(labels, target, bits=3) - left_e = eval_expr(labels, left, bits=3) - imm_e = eval_expr(labels, imm, bits=3) - alu_op_e = eval_expr(labels, alu_op, bits=3) - word = (0b0001 << 12) + \ - (target_e << 9) + \ - (left_e << 6) + \ - (imm_e << 3) + \ - alu_op_e - return word - -def make_ldr(meta: Meta, labels: Labels, addr_reg: str, to_reg: str) -> int: - """LDR 0010 TTTR RRXX XXXX""" - to_reg_e = eval_expr(labels, to_reg, bits=3) - addr_reg_e = eval_expr(labels, addr_reg, bits=3) - word = (0b0010 << 12) + \ - (to_reg_e << 9) + \ - (addr_reg_e << 6) - return word - -def make_str(meta: Meta, labels: Labels, from_reg: str, addr_reg: str) -> int: - """STR 0011 XXXL LLRR RXXX""" - from_reg_e = eval_expr(labels, from_reg, bits=3) - addr_reg_e = eval_expr(labels, addr_reg, bits=3) - word = (0b0011 << 12) + \ - (addr_reg_e << 6) + \ - (from_reg_e << 3) - return word - -def make_ldi(meta: Meta, labels: Labels, imm: str, to_reg: str) -> int: - """LDI 0100 TTTI IIII IIII""" - to_reg_e = eval_expr(labels, to_reg, bits=3) - imm_e = eval_expr(labels, imm, bits=9) - word = (0b0100 << 12) + \ - (to_reg_e << 9) + \ - imm_e - return word - -def make_jpr(meta: Meta, labels: Labels, addr_reg: str) -> int: - """JPR 0101 XXXR RRXX XXXX""" - addr_reg_e = eval_expr(labels, addr_reg, bits=3) - word = (0b0101 << 12) + \ - (addr_reg_e << 6) - return word - -def make_jpi(meta: Meta, labels: Labels, imm: str) -> int: - """JPI 0110 XXXI IIII IIII""" - imm_e = eval_expr(labels, imm, bits=9) - imm_e = imm_e - meta.address - 1 - imm_e = imm_e & (0b111111111) - word = (0b0110 << 12) + \ - imm_e - return word - -def make_brr(meta: Meta, labels: Labels, flag_s: str, addr_reg: str) -> int: - """brr 0111 XFFR RRXX XXXX""" - flag_s_e = eval_expr(labels, flag_s, bits=2) - addr_reg_e = eval_expr(labels, addr_reg, bits=3) - word = (0b0111 << 12) + \ - (flag_s_e << 9) + \ - (addr_reg_e << 6) - return word - -def make_bri(meta: Meta, labels: Labels, flag_s: str, imm: str) -> int: - """BRI 1000 XFFI IIII IIII""" - flag_s_e = eval_expr(labels, flag_s, bits=2) - imm_e = eval_expr(labels, imm, bits=9) - imm_e = imm_e - meta.address - 1 - imm_e = imm_e & (0b111111111) - word = (0b1000 << 12) + \ - (flag_s_e << 9) + \ - imm_e - return word - -def make_lpc(meta: Meta, labels: Labels, target: str) -> int: - """LPC 1001 TTTX XXXX XXXX""" - target_e = eval_expr(labels, target, bits=3) - word = (0b1001 << 12) + \ - (target_e << 9) - return word - -def make_hlt(meta: Meta, labels: Labels) -> int: - """HLT 1111 XXXX XXXX XXXX""" - word = (0b1111 << 12) - return word - -OpWordDict = dict[str, Callable[..., int]] -operations: OpWordDict = { - "alr": make_alr, - "ali": make_ali, - "ldr": make_ldr, - "str": make_str, - "ldi": make_ldi, - "jpr": make_jpr, - "jpi": make_jpi, - "brr": make_brr, - "bri": make_bri, - "lpc": make_lpc, - "hlt": make_hlt, -} - -ExpandResult = list[list[str]] -ExpandFn = Callable[..., ExpandResult] -OpExpansionDict = dict[str, ExpandFn] - -def expand_id(*parts: str) -> ExpandResult: - return [list(parts)] - -default_expansions: OpExpansionDict = { - "alr": lambda *args: expand_id("alr", *args), - "ali": lambda *args: expand_id("ali", *args), - "ldr": lambda *args: expand_id("ldr", *args), - "str": lambda *args: expand_id("str", *args), - "ldi": lambda *args: expand_id("ldi", *args), - "jpr": lambda *args: expand_id("jpr", *args), - "jpi": lambda *args: expand_id("jpi", *args), - "brr": lambda *args: expand_id("brr", *args), - "bri": lambda *args: expand_id("bri", *args), - "lpc": lambda *args: expand_id("lpc", *args), - "hlt": lambda *args: expand_id("hlt", *args), -} - diff --git a/src/ext_std.py b/src/ext_std.py index 5f41f60..11da8aa 100644 --- a/src/ext_std.py +++ b/src/ext_std.py @@ -1,4 +1,4 @@ -from assembler_ops import * +from asm_ops import * def expand_add(left: str, right: str, target: str) -> ExpandResult: return [["alr", "al_plus", left, right, target]] diff --git a/src/test.atk16 b/src/test.atk16 deleted file mode 100644 index 3f2d378..0000000 --- a/src/test.atk16 +++ /dev/null @@ -1,33 +0,0 @@ -; Program: sum two values and store the result in RAM - -@use ext_std:* - -; ROM (and program execution) starts at offset 0x0 -@address 0x0 - jpi program - -@label ram_offset - 0x8000 ; store ram offset for later memory access - -@label program - ldi RA 10 ; RA := 10 - ldi RB 20 ; RB := 20 - add RA RB RC ; RC := RA + RB - ldi RD @ram_offset ; store address of ram_offset in RD - ldr RD RD ; dereference ram_offset address -@label debug - str RD RC ; store RC in RAM - -; Check that 10 + 20 = 30 - mov RC RA ; RA := result of sum - ldi RB 30 ; RB := 30 - sub RA RB RC ; RC := RA - RB - bri zero @success ; if result is zero, jump to success - - ldi RA 2 ; RA := 2 to signal failure - hlt - -; Else -@label success - ldi RA 1 ; RA := 1 to signal success - hlt diff --git a/src/test_alu.py b/src/test_alu.py deleted file mode 100755 index af30443..0000000 --- a/src/test_alu.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 - -from test_utils import * - -def make_alu_table() -> str: - alu = ALU() - n = 10000 - alu.generate_cases(n) - alu.process() - print(f"[test] running {n} ALU test cases") - return alu.to_table().strip() - -class ALU(TestGroup): - def __init__(self): - TestGroup.__init__(self, [ - Param("A", 0x0, 0xffff), - Param("B", 0x0, 0xffff), - Param("S", 0, 7), - ], [ - "Y", - "FLAGS", - ]) - - def process(self): - new_cases = [] - for kase in self.cases: - S = kase["S"] - A = kase["A"] - B = kase["B"] - kase["FLAGS"] = "x" - - match S: - case 0: Y = 0 - case 1: Y = (B - A) & 0xFFFF - case 2: Y = (A - B) & 0xFFFF - case 3: Y = (A + B) & 0xFFFF - case 4: Y = (A ^ B) & 0xFFFF - case 5: Y = (A | B) & 0xFFFF - case 6: Y = (A & B) & 0xFFFF - case 7: Y = 0xffff - - kase["Y"] = Y - new_cases.append(kase) - - self.cases = new_cases - -table = make_alu_table() -run_test("ALU", table) diff --git a/src/test_fibo.atk16 b/src/test_fibo.atk16 deleted file mode 100644 index 8bb7a6e..0000000 --- a/src/test_fibo.atk16 +++ /dev/null @@ -1,66 +0,0 @@ -@opt stack_pointer RF -@opt csr_scratch RH -@use ext_std:* - -; jump over data segment - jpi program - -; data segment -@label ram_offset - 0x8000 - -@label program -; set up stack pointer to point to beginning of RAM - ldi ram_offset RA - ldr RA RF - -; call fibo subroutine with parameter 10 - ldi 10 RA - csi fibo - hlt - -@label fibo -; function fibo -; parameters: -; RA n : u16 -; return value: -; RA fibo(n) : u16 - -; store RB, RC on stack - spu RB - spu RC -; if n < 2, return n - subi RA 2 RA - bri sign fibo_early -; store also RD on stack - spu RD -; a = 0 - ldi 0 RB -; b = 1 - ldi 1 RC -@label fibo_loop -; v = a + b - add RB RC RD -; a = b - mov RC RB -; b = v - mov RD RC -; n -= 1 - dec RA -; loop while n > 0 - bri zero fibo_done - jpi fibo_loop -@label fibo_early -; restore used registers - spo RC - spo RB -; return from subroutine - rsr -@label fibo_done - mov RD RA -; restore used registers - spo RD - spo RC - spo RB -; return from subroutine - rsr diff --git a/src/test_sum.atk16 b/src/test_sum.atk16 deleted file mode 100644 index 3f69a55..0000000 --- a/src/test_sum.atk16 +++ /dev/null @@ -1,3 +0,0 @@ - ldi RA 10 ; RA := 10 - ldi RB 20 ; RB := 20 - add RA RB RC ; RC := RA + RB diff --git a/src/test_utils.py b/src/test_utils.py deleted file mode 100644 index 1db23b2..0000000 --- a/src/test_utils.py +++ /dev/null @@ -1,93 +0,0 @@ -import random -from dataclasses import dataclass -import tempfile -import sys -import os - -def make_test_file(name: str, table: str) -> str: - return f""" - - 2 - - - - Testcase - - - Label - {name} - - - Testdata - - {table} - - - - - - - - - - """ - -@dataclass -class Param: - name: str - min: int - max: int - -class TestGroup: - def __init__(self, inputs: list[Param], outputs: list[str]): - self.inputs = inputs - self.outputs = outputs - self.cases = [] - - def generate_cases(self, n = 1000): - for _ in range(n): - result = {} - for param in self.inputs: - val = random.randrange(param.min, param.max + 1) - result[param.name] = val - - self.cases.append(result) - - def process(self): - raise NotImplemented() - - def to_table(self) -> str: - names: list[str] = [] - for param in self.inputs: - names.append(param.name) - for output in self.outputs: - names.append(output) - - ret = " ".join(names) - ret += "\n" - - for case in self.cases: - row_vals = [] - for param_name in names: - row_vals.append(str(case[param_name])) - - ret += " ".join(row_vals) - ret += "\n" - - return ret - -def run_test(name: str, table: str): - if len(sys.argv) != 2: - print(f"usage: {sys.argv[0]} ") - sys.exit(1) - - circuit_path = sys.argv[1] - _, test_path = tempfile.mkstemp(".dig") - - fc = make_test_file(name, table) - with open(test_path, "w") as f: - f.write(fc) - - stream = os.popen(f"make run-single-test circ={circuit_path} tests={test_path}") - output = stream.read() - print(output) -- cgit v1.3