From 5b6637fb92c54b8f367ec8751f53f6f238d8dbed Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Sun, 9 Apr 2023 18:26:25 +0300 Subject: Remake ALU --- src/assembler.py | 341 +++++++++++++++++++++++++++------------------------- src/test.atk16 | 2 +- src/test_fibo.atk16 | 47 ++++++++ src/ucode.py | 41 ++++--- 4 files changed, 245 insertions(+), 186 deletions(-) create mode 100644 src/test_fibo.atk16 (limited to 'src') diff --git a/src/assembler.py b/src/assembler.py index 5802983..7deb0f0 100755 --- a/src/assembler.py +++ b/src/assembler.py @@ -25,8 +25,8 @@ src_lines = src.splitlines() def parse(line: str) -> list[str]: depth = 0 - result = [] - acc = "" + result: list[str] = [] + acc: str = "" for c in line: if c.isspace() and depth == 0: result.append(acc) @@ -47,42 +47,47 @@ 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]) - match c: - # Registers - case "rz": return "0" - case "ra": return "1" - case "rb": return "2" - case "rc": return "3" - case "rd": return "4" - case "pa": return "5" - case "pb": return "6" - # ALU instructions - case "al_clear": return "0" - case "al_b_minus_a": return "1" - case "al_a_minus_b": return "2" - case "al_a_plus_b": return "3" - case "al_a_xor_b": return "4" - case "al_a_or_b": return "5" - case "al_a_and_b": return "6" - case "al_preset": return "7" - case "al_logical_shift_right": return "8" - case "al_arithmetic_shift_right": return "9" - case "al_logical_shift_left": return "10" - # ALU flags - case "f_carry": return "0" - case "f_overflow": return "1" - case "f_zero": return "2" - case "f_sign": return "3" - case _: return c - -# 1st pass, gather labels + if c in constants: + return constants[c] + + return c + +# 1st pass, gather labels, set options +options: dict[str, str] = { + "stack_pointer": "6" # RG +} labels: dict[str, int] = {} -address = 0 +address: int = 0 for (lineNo, line) in enumerate(src_lines): line = line.split(";")[0].strip() @@ -95,11 +100,116 @@ for (lineNo, line) in enumerate(src_lines): case "@label": labels[args[0]] = address continue + case "@opt": + opt_name = args[0] + opt_value = constants.get(args[1], args[1]) + options[opt_name] = opt_value + case _: + pass address += 1 # 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 -= address + 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 -= address + 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) +# words_inc: list[int] = make_inc(stack_pointer, stack_pointer) +# words_str: list[int] = make_str(reg, stack_pointer) +# return words_inc + words_str + address = 0 nop = bytearray([0b1000_0000, 0]) result = bytearray() @@ -115,85 +225,52 @@ for (lineNo, line) in enumerate(src_lines): case "@address": address = eval_expr(args[0]) continue - case "@label": + case "@label" | "@opt": continue # Instructions - case "alu": - # S (alu op) - # L (lhs) - # R (rhs) - # T (target) - word = (0b0000 << 12) + \ - (eval_expr(args[0]) << 3) + \ - (eval_expr(args[1]) << 9) + \ - (eval_expr(args[2]) << 6) + \ - (eval_expr(args[3]) << 0) - case "als": - # S (alu op) - # L (lhs) - # R (rhs) - # T (target) - word = (0b0001 << 12) + \ - (eval_expr(args[0]) << 3) + \ - (eval_expr(args[1]) << 9) + \ - (eval_expr(args[2]) << 6) + \ - (eval_expr(args[3]) << 0) + case "alr": + words = make_alr(*args) + case "ali": + words = make_ali(*args) case "ldr": - # R (address) - # T (target) - word = (0b0010 << 12) + \ - (eval_expr(args[0]) << 9) + \ - (eval_expr(args[1]) << 0) + words = make_ldr(*args) case "str": - # R (address) - # T (value to store) - word = (0b0011 << 12) + \ - (eval_expr(args[0]) << 9) + \ - (eval_expr(args[1]) << 6) + words = make_str(*args) case "ldi": - # T (target) - # I (immediate) - word = (0b0100 << 12) + \ - (eval_expr(args[0]) << 0) + \ - (eval_expr(args[1]) << 3) - case "jmp": - # R (reg holding address) - word = (0b0101 << 12) + \ - (eval_expr(args[0]) << 9) + words = make_ldi(*args) + case "jpr": + words = make_jpr(*args) + case "jpi": + words = make_jpi(address, *args) case "br": - # F (flag selector) - # R (reg holding address) - word = (0b0110 << 12) + \ - (eval_expr(args[0]) << 9) + \ - (eval_expr(args[1]) << 6) + words = make_br(*args) + case "bri": + words = make_bri(address, *args) case "hlt": - word = 0b1111 << 12 + words = make_hlt() # Pseudoinstructions case "add": - word = (0b0000 << 12) + \ - (eval_expr(args[0]) << 9) + \ - (eval_expr(args[1]) << 6) + \ - (eval_expr("al_a_plus_b") << 3) + \ - (eval_expr(args[2]) << 0) + words = make_alr("al_plus", *args) case "sub": - word = (0b0000 << 12) + \ - (eval_expr(args[0]) << 9) + \ - (eval_expr(args[1]) << 6) + \ - (eval_expr("al_a_minus_b") << 3) + \ - (eval_expr(args[2]) << 0) + 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": - word = (0b0000 << 12) + \ - (eval_expr("rz") << 9) + \ - (eval_expr(args[0]) << 6) + \ - (eval_expr("al_a_plus_b") << 3) + \ - (eval_expr(args[1]) << 0) + 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: - word = eval_expr(keyword) + words = [eval_expr(keyword)] except: raise Exception(f"Invalid assembly at {infile_path}:{lineNo + 1}\n\n{line}") @@ -204,79 +281,13 @@ for (lineNo, line) in enumerate(src_lines): if address == label_addr: print(f"{label}:") - print(f"{address:>08x} 0x{word:>04x} {line}") - result[2 * address + 0] = ((word >> 8) & 0xff) - result[2 * address + 1] = ((word >> 0) & 0xff) - address += 1 + for word in words: + print(f"{address:>08x} 0x{word:>04x} {line}") + result[2 * address + 0] = ((word >> 8) & 0xff) + result[2 * address + 1] = ((word >> 0) & 0xff) + address += 1 with open(outfile_path, "wb") as f: f.write(result) print(f"Wrote {len(result)} bytes to {outfile_path}") - -with open(f"{outfile_path}.logisim.txt", "w") as f: - f.write("v2.0 raw\n") - run_length = 0 - run_last = "" - for i in range(len(result) // 2): - b0 = result[2 * i + 0] - b1 = result[2 * i + 1] - word = f"{b0:>02x}{b1:>02x}\n" - - if word != run_last and run_length <= 1: - f.write(f"{run_last}") - run_length = 1 - run_last = word - elif word != run_last and run_length > 1: - f.write(f"{run_length}*{run_last}") - run_length = 1 - run_last = word - else: - run_length += 1 - - if run_length <= 1: - f.write(f"{run_last}") - else: - f.write(f"{run_length}*{run_last}") - -print(f"Wrote Logisim image format to {outfile_path}.logisim.txt") - -with open(f"{outfile_path}.ver.txt", "w") as f: - f.write("addr/data: 15 16") - run_length = 0 - run_last = "" - written = -1 - - def update_layout(): - if run_last == "": return - if written % 8 == 0: - f.write("\n") - else: - f.write(" ") - - for i in range(len(result) // 2): - b0 = result[2 * i + 0] - b1 = result[2 * i + 1] - word = f"{b0:>02x}{b1:>02x}" - - if word != run_last and run_length <= 1: - f.write(f"{run_last}") - run_length = 1 - run_last = word - written += 1 - update_layout() - elif word != run_last and run_length > 1: - f.write(f"{run_length}*{run_last}") - run_length = 1 - run_last = word - written += 1 - update_layout() - else: - run_length += 1 - - if run_length <= 1: - f.write(f"{run_last}") - else: - f.write(f"{run_length}*{run_last}") - -print(f"Wrote verification test format to {outfile_path}.ver.txt") diff --git a/src/test.atk16 b/src/test.atk16 index 364480b..da7c7c8 100644 --- a/src/test.atk16 +++ b/src/test.atk16 @@ -3,7 +3,7 @@ ; ROM (and program execution) starts at offset 0x0 @address 0x0 ldi RA program - jmp RA + jpr RA @label ram_offset 0x8000 ; store ram offset for later memory access diff --git a/src/test_fibo.atk16 b/src/test_fibo.atk16 new file mode 100644 index 0000000..7f1abb9 --- /dev/null +++ b/src/test_fibo.atk16 @@ -0,0 +1,47 @@ +@opt stack_pointer RG + +@label program + ; call fibo subroutine with parameter 10 + ldi RA 10 + csr fibo + hlt + +@label fibo + ; function fibo + ; parameters: + ; RA n : u16 + ; return value: + ; RA fibo(n) : u16 + + spu RB ; prelude + spu RC + + ldi RC 2 ; if n < 2, return n + sub RA RC RA + bri f_sign fibo_early + + spu RD ; prelude + spu RE + + ldi RE 1 ; constant 1 + ldi RB 0 ; a = 0 + ldi RC 1 ; b = 1 +@label fibo_loop + add RB RC RD ; v = a + b + mov RC RB ; a = b + mov RD RC ; b = v + sub RA RE RA ; n -= 1 + bri f_zero fibo_done ; loop while n > 0 + jpi fibo_loop + +@label fibo_early + spo RC + spo RB + rsr +@label fibo_done + ldr RD RA + spo RE + spo RD + spo RC + spo RB + rsr diff --git a/src/ucode.py b/src/ucode.py index 9d7c55c..3c34a71 100755 --- a/src/ucode.py +++ b/src/ucode.py @@ -20,23 +20,23 @@ MEM_IE = 0b0000_0000_0001_0000 MEM_OE = 0b0000_0000_0010_0000 RW_IE = 0b0000_0000_0100_0000 R1_OE = 0b0000_0000_1000_0000 -R2_OE = 0b0000_0001_0000_0000 +R2_OE = 0b0000_0001_0000_0000 # needed? IR_IE = 0b0000_0010_0000_0000 -L9_OE = 0b0000_0100_0000_0000 -unused1 = 0b0000_1000_0000_0000 +unused = 0b0000_0100_0000_0000 +LI_OE = 0b0000_1000_0000_0000 ALU_OE = 0b0001_0000_0000_0000 FR_IE = 0b0010_0000_0000_0000 HALT = 0b0100_0000_0000_0000 US_RS = 0b1000_0000_0000_0000 BRANCH_FLAG_STATES_N = 2 -UCODE_N = 2**3 +UCODE_N: int = 2**3 CONTROL_WORD_SIZE = 2 -def not_branch(bs): +def not_branch(bs: list[int]) -> list[list[int]]: return BRANCH_FLAG_STATES_N * [bs] -def branch(false_branch, true_branch): +def branch(false_branch: list[int], true_branch: list[int]) -> list[list[int]]: return [false_branch, true_branch] fetch = [PC_OE|MAR_IE, MEM_OE|IR_IE|PC_CO] @@ -45,25 +45,26 @@ def nop(): return not_branch([*fetch, US_RS, 0, 0, 0, 0, 0]) ucode = [ - # ALU 0000 LLLR RRSS STTT + # ALR 0000 TTTL LLRR RSSS not_branch([*fetch, ALU_OE|FR_IE|RW_IE, US_RS, 0, 0, 0, 0]), - # ALS 0001 LLLR RRSS STTT + # ALI 0001 TTTL LLII ISSS not_branch([*fetch, ALU_OE|FR_IE|RW_IE, US_RS, 0, 0, 0, 0]), - # LDR 0010 RRRX XXXX XTTT + # LDR 0010 TTTR RRXX XXXX not_branch([*fetch, R1_OE|MAR_IE, MEM_OE|RW_IE, US_RS, 0, 0, 0]), - # STR 0011 RRRT TTXX XXXX - not_branch([*fetch, R1_OE|MAR_IE, R2_OE|MEM_IE, US_RS, 0, 0, 0]), - # LDI 0100 IIII IIII ITTT - not_branch([*fetch, H9_OE|RW_IE, US_RS, 0, 0, 0, 0]), - # JMP 0101 RRRX XXXX XXXX + # STR 0011 TTTR RRXX XXXX + not_branch([*fetch, R1_OE|MAR_IE, R1_OE|MEM_IE, US_RS, 0, 0, 0]), + # LDI 0100 TTTI IIII IIII + not_branch([*fetch, LI_OE|RW_IE, US_RS, 0, 0, 0, 0]), + # JPR 0101 XXXR RRXX XXXX not_branch([*fetch, R1_OE|PC_IE, US_RS, 0, 0, 0, 0]), - # BR 0110 XFFR RRXX XXXX + # JPI 0110 XXXI IIII IIII + not_branch([*fetch, LI_OE|PC_IE, US_RS, 0, 0, 0, 0]), + # BR 0111 XFFR RRXX XXXX branch([*fetch, US_RS, 0, 0, 0, 0, 0], - [*fetch, R2_OE|PC_IE, US_RS, 0, 0, 0, 0]), - # NOP 0111 XXXX XXXX XXXX - nop(), - # NOP 1000 XXXX XXXX XXXX - nop(), + [*fetch, R1_OE|PC_IE, US_RS, 0, 0, 0, 0]), + # BRI 1000 XFFI IIII IIII + branch([*fetch, US_RS, 0, 0, 0, 0, 0], + [*fetch, LI_OE|PC_IE, US_RS, 0, 0, 0, 0]), # NOP 1001 XXXX XXXX XXXX nop(), # NOP 1010 XXXX XXXX XXXX -- cgit v1.3