aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/assembler.py339
-rw-r--r--src/test.atk162
-rw-r--r--src/test_fibo.atk1647
-rwxr-xr-xsrc/ucode.py41
4 files changed, 244 insertions, 185 deletions
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
+ if c in constants:
+ return constants[c]
+
+ return c
-# 1st pass, gather labels
+# 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