44 lines
2 KiB
Python
44 lines
2 KiB
Python
#!/usr/bin/env python3
|
|
# findLoaderCalls.py - linear sweep of a memory image for calls into the disk loader entry points,
|
|
# recovering the immediate A/X/Y arguments that precede each call.
|
|
import sys
|
|
from m6502 import decode, IMM, ABS
|
|
|
|
ENTRIES = {0x0804:"read(A=count,Y=track,X=sector)", 0x0843:"write(A=count,Y=track,X=sector)",
|
|
0x085C:"setDest(X=lo,Y=hi)", 0x0863:"writeOne", 0x08EB:"readOne",
|
|
0xC004:"bootRead", 0xC034:"bootSetDest", 0xC08A:"bootReadOne", 0xC03B:"sendByte"}
|
|
|
|
def scan(mem, lo, hi, label):
|
|
hits = []
|
|
a = lo
|
|
while a < hi:
|
|
insn = decode(mem, a)
|
|
if insn.mnemonic in ("jsr","jmp") and insn.mode == ABS and insn.target in ENTRIES:
|
|
# walk back up to 12 bytes looking for immediate loads
|
|
regs = {}
|
|
b = a
|
|
for _ in range(8):
|
|
# find previous instruction by trying lengths 1..3 (heuristic: prefer the one that decodes to an imm load)
|
|
found = None
|
|
for ln in (2, 3, 1):
|
|
p = b - ln
|
|
if p < lo: continue
|
|
pi = decode(mem, p)
|
|
if pi.length == ln and pi.isLegal():
|
|
found = pi; break
|
|
if not found: break
|
|
if found.mnemonic in ("lda","ldx","ldy") and found.mode == IMM:
|
|
regs.setdefault(found.mnemonic[2].upper(), found.operand)
|
|
elif found.mnemonic in ("jsr","jmp","rts","rti") or found.mnemonic.startswith("b") and found.mode==12:
|
|
break
|
|
b = found.addr
|
|
hits.append((a, insn.mnemonic, insn.target, regs))
|
|
a += insn.length if insn.isLegal() else 1
|
|
for a, mn, t, regs in hits:
|
|
print(f"{label} ${a:04X}: {mn} ${t:04X} {ENTRIES[t]:<28} " + " ".join(f"{k}=${v:02X}" for k,v in sorted(regs.items())))
|
|
return hits
|
|
|
|
if __name__ == "__main__":
|
|
mem = open(sys.argv[1], "rb").read()
|
|
for lo, hi in [(0x0400,0x0800),(0x0800,0x8800),(0x8C00,0x9000),(0x9300,0xC400),(0xFBB8,0xFFD2)]:
|
|
scan(mem, lo, hi, "boot")
|