aboutsummaryrefslogtreecommitdiffstats
path: root/src/assembler.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/assembler.py')
-rwxr-xr-xsrc/assembler.py339
1 files changed, 175 insertions, 164 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")