#!/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")
