aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJan Tuomi <jans.tuomi@gmail.com>2023-04-10 13:15:59 +0300
committerJan Tuomi <jans.tuomi@gmail.com>2023-04-10 13:15:59 +0300
commitf07900a66952edb27114b8bdd68efc397b995796 (patch)
treecbb13e08b222cab594332ae11d863e793528799a /src
parenta58375eee5d607fbb44620752195eafb9407685e (diff)
Add ext system
Diffstat (limited to 'src')
-rwxr-xr-xsrc/assembler.py215
-rw-r--r--src/assembler_eval.py39
-rw-r--r--src/assembler_ops.py108
-rw-r--r--src/ext_std.py24
-rw-r--r--src/test.atk162
-rwxr-xr-xsrc/ucode.py2
6 files changed, 205 insertions, 185 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)
diff --git a/src/assembler_eval.py b/src/assembler_eval.py
new file mode 100644
index 0000000..3473ab8
--- /dev/null
+++ b/src/assembler_eval.py
@@ -0,0 +1,39 @@
+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",
+}
+
+labels: dict[str, int] = {}
+
+def eval_symbol(c: str) -> str:
+ if c in labels:
+ return str(labels[c])
+
+ if c in constants:
+ return constants[c]
+
+ return c
+
+def eval_expr(expr: str) -> int:
+ expr = eval_symbol(expr)
+ return eval(expr, labels.copy()) # eval as Python expr
diff --git a/src/assembler_ops.py b/src/assembler_ops.py
new file mode 100644
index 0000000..538dd78
--- /dev/null
+++ b/src/assembler_ops.py
@@ -0,0 +1,108 @@
+from typing import Callable
+from assembler_eval import *
+
+def make_alr(address: int, 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(address: int, 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(address: int, 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(address: int, 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(address: int, 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(address: int, 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(address: int, flag_s: str, addr_reg: str) -> list[int]:
+ """brr 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(address: int, ) -> list[int]:
+ """HLT 1111 XXXX XXXX XXXX"""
+ word = (0b1111 << 12)
+ return [word]
+
+operations: dict[str, Callable[..., list[int]]] = {
+ "alr": make_alr,
+ "alr": make_alr,
+ "ali": make_ali,
+ "ldr": make_ldr,
+ "str": make_str,
+ "ldi": make_ldi,
+ "jpr": make_jpr,
+ "jpi": make_jpi,
+ "brr": make_br,
+ "bri": make_bri,
+ "hlt": make_hlt,
+} \ No newline at end of file
diff --git a/src/ext_std.py b/src/ext_std.py
new file mode 100644
index 0000000..017f40a
--- /dev/null
+++ b/src/ext_std.py
@@ -0,0 +1,24 @@
+from assembler_ops import *
+
+def make_add(address:int, left: str, right: str, target: str) -> list[int]:
+ return make_alr(address, "al_plus", left, right, target)
+
+def make_sub(address: int, left: str, right: str, target: str) -> list[int]:
+ return make_alr(address, "al_minus", left, right, target)
+
+def make_inc(address: int, reg: str) -> list[int]:
+ return make_ali(address, "al_plus", reg, "1", reg)
+
+def make_dec(address: int, reg: str) -> list[int]:
+ return make_ali(address, "al_minus", reg, "1", reg)
+
+def make_mov(address: int, from_reg: str, to_reg: str) -> list[int]:
+ return make_ali(address, "al_plus", from_reg, "0", to_reg)
+
+operations = {
+ "add": make_add,
+ "sub": make_sub,
+ "inc": make_inc,
+ "dec": make_dec,
+ "mov": make_mov,
+}
diff --git a/src/test.atk16 b/src/test.atk16
index 1a7c773..1507430 100644
--- a/src/test.atk16
+++ b/src/test.atk16
@@ -1,5 +1,7 @@
; 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
diff --git a/src/ucode.py b/src/ucode.py
index a847a35..10dd853 100755
--- a/src/ucode.py
+++ b/src/ucode.py
@@ -59,7 +59,7 @@ ucode = [
not_branch([*fetch, R1_OE|PC_IE, US_RS, 0, 0, 0, 0]),
# JPI 0110 XXXI IIII IIII
not_branch([*fetch, IM_M|LI_OE|PC_IE, US_RS, 0, 0, 0, 0]),
- # BR 0111 XFFR RRXX XXXX
+ # BRR 0111 XFFR RRXX XXXX
branch([*fetch, US_RS, 0, 0, 0, 0, 0],
[*fetch, R1_OE|PC_IE, US_RS, 0, 0, 0, 0]),
# BRI 1000 XFFI IIII IIII