99 lines
3.8 KiB
Python
99 lines
3.8 KiB
Python
"""A tiny Motorola 6809 machine-code emitter (just what the CoCo viewer needs).
|
|
|
|
No 6809 assembler is installed, so -- as with the TI's TMS9900 emitter -- we emit
|
|
opcodes directly. Supports labels + 8-bit relative-branch backpatching.
|
|
Index-register codes for ,R+ postbytes: X=0x80, Y=0xA0, U=0xC0, S=0xE0.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
_IDX = {"x": 0x80, "y": 0xA0, "u": 0xC0, "s": 0xE0}
|
|
|
|
|
|
class Asm:
|
|
def __init__(self, base: int):
|
|
self.base = base
|
|
self.code = bytearray()
|
|
self.labels: dict[str, int] = {}
|
|
self._fix: list[tuple[int, str]] = [] # (pos of rel byte, label)
|
|
|
|
def pos(self) -> int:
|
|
return self.base + len(self.code)
|
|
|
|
def label(self, name: str):
|
|
self.labels[name] = self.pos()
|
|
|
|
def _b(self, *bs):
|
|
self.code += bytes(bs)
|
|
|
|
def _w(self, v): # 16-bit, big-endian
|
|
self.code += bytes([(v >> 8) & 0xFF, v & 0xFF])
|
|
|
|
# ---- inherent ----
|
|
def nop(self): self._b(0x12)
|
|
def clra(self): self._b(0x4F)
|
|
def clrb(self): self._b(0x5F)
|
|
def deca(self): self._b(0x4A)
|
|
def decb(self): self._b(0x5A)
|
|
def inca(self): self._b(0x4C)
|
|
def incb(self): self._b(0x5C)
|
|
def rts(self): self._b(0x39)
|
|
def sync(self): self._b(0x13)
|
|
|
|
# ---- immediate ----
|
|
def lda_imm(self, v): self._b(0x86, v & 0xFF)
|
|
def ldb_imm(self, v): self._b(0xC6, v & 0xFF)
|
|
def anda_imm(self, v): self._b(0x84, v & 0xFF)
|
|
def ora_imm(self, v): self._b(0x8A, v & 0xFF)
|
|
def cmpa_imm(self, v): self._b(0x81, v & 0xFF)
|
|
def cmpb_imm(self, v): self._b(0xC1, v & 0xFF)
|
|
def orcc(self, v): self._b(0x1A, v & 0xFF)
|
|
def andcc(self, v): self._b(0x1C, v & 0xFF)
|
|
|
|
def ldd_imm(self, v): self._b(0xCC); self._w(v)
|
|
def subd_imm(self, v): self._b(0x83); self._w(v)
|
|
def ldx_imm(self, v): self._b(0x8E); self._w(v)
|
|
def ldu_imm(self, v): self._b(0xCE); self._w(v)
|
|
def ldy_imm(self, v): self._b(0x10, 0x8E); self._w(v)
|
|
def lds_imm(self, v): self._b(0x10, 0xCE); self._w(v)
|
|
def cmpx_imm(self, v): self._b(0x8C); self._w(v)
|
|
def cmpu_imm(self, v): self._b(0x11, 0x83); self._w(v)
|
|
|
|
# ---- extended (16-bit address) ----
|
|
def lda_ext(self, a): self._b(0xB6); self._w(a)
|
|
def sta_ext(self, a): self._b(0xB7); self._w(a)
|
|
def ldb_ext(self, a): self._b(0xF6); self._w(a)
|
|
def stb_ext(self, a): self._b(0xF7); self._w(a)
|
|
def std_ext(self, a): self._b(0xFD); self._w(a)
|
|
def jmp_ext(self, a): self._b(0x7E); self._w(a)
|
|
def jsr_ext(self, a): self._b(0xBD); self._w(a)
|
|
def jmp_ind(self, a): self._b(0x6E, 0x9F); self._w(a) # JMP [addr] (indirect)
|
|
|
|
# ---- indexed auto-increment: LDA ,R+ / STA ,R+ ----
|
|
def lda_postinc(self, r): self._b(0xA6, _IDX[r])
|
|
def sta_postinc(self, r): self._b(0xA7, _IDX[r])
|
|
def ldb_postinc(self, r): self._b(0xE6, _IDX[r])
|
|
def stb_postinc(self, r): self._b(0xE7, _IDX[r])
|
|
|
|
# ---- 8-bit relative branches ----
|
|
def _branch(self, op, label):
|
|
self._b(op)
|
|
self._fix.append((len(self.code), label))
|
|
self._b(0x00) # placeholder
|
|
|
|
def bra(self, label): self._branch(0x20, label)
|
|
def bne(self, label): self._branch(0x26, label)
|
|
def beq(self, label): self._branch(0x27, label)
|
|
def bpl(self, label): self._branch(0x2A, label)
|
|
def bmi(self, label): self._branch(0x2B, label)
|
|
def bcc(self, label): self._branch(0x24, label)
|
|
def bcs(self, label): self._branch(0x25, label)
|
|
|
|
def resolve(self) -> bytes:
|
|
for pos, label in self._fix:
|
|
target = self.labels[label]
|
|
rel = target - (self.base + pos + 1)
|
|
if not -128 <= rel <= 127:
|
|
raise ValueError(f"branch to {label} out of range ({rel})")
|
|
self.code[pos] = rel & 0xFF
|
|
return bytes(self.code)
|