aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_asm
diff options
context:
space:
mode:
authorJan Tuomi <jans.tuomi@gmail.com>2024-02-24 19:04:00 +0200
committerJan Tuomi <jans.tuomi@gmail.com>2024-02-24 19:04:00 +0200
commit0a2cf66672364ed555c85682e948cff0b54c8f35 (patch)
tree249a426faf5e7ba0d218176f651dca6c635a3705 /atk16_asm
parent416e896956d3b05793337da6609fe1544797c0a9 (diff)
Fix bugs, add basic debugger
Diffstat (limited to 'atk16_asm')
-rw-r--r--atk16_asm/asm_ops.py48
-rw-r--r--atk16_asm/parser.py138
2 files changed, 165 insertions, 21 deletions
diff --git a/atk16_asm/asm_ops.py b/atk16_asm/asm_ops.py
index 394a643..293b1cc 100644
--- a/atk16_asm/asm_ops.py
+++ b/atk16_asm/asm_ops.py
@@ -10,6 +10,13 @@ OpExpansionDict = dict[str, ExpandFn]
class Meta:
address: int
+generate_unique_label_counter = 0
+def generate_unique_label(prefix: str) -> str:
+ global generate_unique_label_counter
+ label = f"{prefix}_{generate_unique_label_counter}"
+ generate_unique_label_counter += 1
+ return label
+
def make_alr(meta: Meta, symbols: Symbols, alu_op: str, left: str, right: str, target: str) -> int:
"""ALR 0000 TTTL LLRR RSSS"""
target_e = eval_expr(symbols, target, bits=3)
@@ -215,25 +222,25 @@ def expand_sinc(imm: str) -> ExpandResult:
def expand_sdec(imm: str) -> ExpandResult:
return expand_subi("SP", imm, "SP")
-def expand_csr(addr_reg: str, stratch_reg: str) -> ExpandResult:
+def expand_callr(addr_reg: str) -> ExpandResult:
return [
- ["lpc", stratch_reg],
- *expand_addi(stratch_reg, "4", stratch_reg),
- *expand_spu(stratch_reg),
+ ["lpc", "RG"],
+ *expand_addi("RG", "4", "RG"),
+ *expand_spu("RG"),
["jpr", addr_reg]
]
-def expand_csi(addr_imm: str, stratch_reg: str) -> ExpandResult:
+def expand_calli(addr_imm: str) -> ExpandResult:
+ ret_label = generate_unique_label(prefix="calli_return")
return [
- ["lpc", stratch_reg],
- *expand_addi(stratch_reg, "4", stratch_reg),
- *expand_spu(stratch_reg),
- ["jpi", addr_imm]
+ ["ldi", ret_label, "RG"],
+ *expand_spu("RG"),
+ ["jpi", addr_imm],
+ ["@label", ret_label]
]
-def expand_rsr(stratch_reg: str) -> ExpandResult:
- return expand_spo(stratch_reg) + [["jpr", stratch_reg]]
-
+def expand_return() -> ExpandResult:
+ return expand_spo("RG") + [["jpr", "RG"]]
def stack_stash(*rs: str) -> ExpandResult:
result: ExpandResult = []
@@ -245,17 +252,17 @@ def stack_stash(*rs: str) -> ExpandResult:
def stack_restore(*rs: str) -> ExpandResult:
result: ExpandResult = []
for r in rs:
- prefix = expand_spu(r)
+ prefix = expand_spo(r)
result = prefix + result
return result
def set_graphics_mode(mode: str) -> ExpandResult:
return [
- ["ldi", "vt_gr_mode_addr", "RA"],
- ["ldr", "RA", "RA"],
- ["ldi", mode, "RB"],
- ["str", "RB", "RA"],
+ ["ldi", "vt_gr_mode_addr", "RF"],
+ ["ldr", "RF", "RF"],
+ ["ldi", mode, "RG"],
+ ["str", "RG", "RF"],
]
expansions: OpExpansionDict = {
@@ -298,11 +305,10 @@ expansions: OpExpansionDict = {
"spo": expand_spo,
"sinc": expand_sinc,
"sdec": expand_sdec,
- "csr": expand_csr,
- "csi": expand_csi,
- "rsr": expand_rsr,
+ "callr": expand_callr,
+ "calli": expand_calli,
+ "return": expand_return,
"stack_stash": stack_stash,
"stack_restore": stack_restore,
"set_graphics_mode": set_graphics_mode,
}
-
diff --git a/atk16_asm/parser.py b/atk16_asm/parser.py
new file mode 100644
index 0000000..4823450
--- /dev/null
+++ b/atk16_asm/parser.py
@@ -0,0 +1,138 @@
+from typing import Callable, Literal, cast
+from dataclasses import dataclass
+import re
+
+RegisterValue = Literal["RA", "RB", "RC", "RD", "RE", "RF", "RG", "RH"]
+REGISTERS: list[RegisterValue] = ["RA", "RB", "RC", "RD", "RE", "RF", "RG", "RH"]
+@dataclass
+class RegisterRef:
+ """Reference to a register, e.g. RA"""
+ reg: RegisterValue
+
+ def __str__(self) -> str:
+ return self.reg
+
+@dataclass
+class Immediate:
+ """Immediate value, e.g. 0x1234"""
+ value: int
+ base: Literal["dec", "hex", "bin"]
+
+ def __str__(self) -> str:
+ if self.base == "dec":
+ return str(self.value)
+ elif self.base == "hex":
+ return f"0x{self.value:>04x}"
+ elif self.base == "bin":
+ return f"0b{self.value:>016b}"
+
+ raise Exception("Invalid base: {self.base}")
+
+@dataclass
+class Label:
+ """Label declaration, e.g. @loop"""
+ label: str
+
+ def __str__(self) -> str:
+ return f"@{self.label}"
+
+@dataclass
+class LabelRef:
+ """Label reference, e.g. &loop"""
+ label: str
+
+ def __str__(self) -> str:
+ return f"&{self.label}"
+
+FlagValue = Literal[0, 1, 2, 3]
+FLAGS = ["carry", "overflow", "zero", "sign"]
+@dataclass
+class Flag:
+ """ALU Flag, e.g. zero"""
+ num: FlagValue
+
+ @staticmethod
+ def from_str(flag: str) -> "Flag":
+ return Flag(cast(FlagValue, FLAGS.index(flag)))
+
+ def __str__(self) -> str:
+ return FLAGS[self.num]
+
+ALUCodeValue = Literal[0, 1, 2, 3, 4, 5, 6, 7]
+ALU_CODES = ["al_plus", "al_minus", "al_and", "al_or", "al_xor", "al_sll", "al_slr", "al_sar"]
+@dataclass
+class ALUCode:
+ """ALU operation code, e.g. al_plus"""
+ code: ALUCodeValue
+
+ @staticmethod
+ def from_str(code: str) -> "ALUCode":
+ return ALUCode(cast(ALUCodeValue, ALU_CODES.index(code)))
+
+ def __str__(self) -> str:
+ return ALU_CODES[self.code]
+
+@dataclass
+class Expr:
+ """Python expression that can be evaluated to an immediate value"""
+ expr: str
+
+ def __str__(self) -> str:
+ return f"${{{self.expr}}}"
+
+@dataclass
+class Directive:
+ """Directive, e.g. #address"""
+ directive: str
+
+ def __str__(self) -> str:
+ return f"#${self.directive}"
+
+@dataclass
+class StringLiteral:
+ """String literal, e.g. "hello world" """
+ string: str
+
+ def __str__(self) -> str:
+ return f'"{self.string}"'
+
+@dataclass
+class Symbol:
+ """Symbol, e.g. loop"""
+ symbol: str
+
+ def __str__(self) -> str:
+ return self.symbol
+
+Term = RegisterRef | Immediate | LabelRef | Label | Flag | ALUCode | Expr | Directive | StringLiteral | Symbol
+
+symbol_pattern = "[a-zA-Z_][a-zA-Z0-9_]*"
+
+def parse(tokens: list[str]) -> list[Term]:
+ def parse_token(term: str, idx: int) -> Term:
+ if term in REGISTERS:
+ return RegisterRef(term)
+ elif term in FLAGS:
+ return Flag.from_str(term)
+ elif term.startswith("${") and term.endswith("}"):
+ return Expr(term[2:-1])
+ elif term.startswith("\"") and term.endswith("\""):
+ return StringLiteral(term[1:-1])
+ elif term.startswith("&"):
+ return LabelRef(term[1:])
+ elif term.startswith("@"):
+ return Label(term[1:])
+ elif term.startswith("#"):
+ return Directive(term[1:])
+ elif term.startswith("0x"):
+ return Immediate(int(term.replace("_", ""), 16), "hex")
+ elif term.startswith("0b"):
+ return Immediate(int(term.replace("_", ""), 2), "bin")
+ elif term.isdigit():
+ return Immediate(int(term.replace("_", ""), 10), "dec")
+ elif re.match(symbol_pattern, term) is not None:
+ return Symbol(term)
+ else:
+ raise Exception(f"Invalid term \"{term}\" at index {idx} in {tokens}")
+
+ return [parse_token(token, idx) for idx, token in enumerate(tokens)]