# Detect the w65816 codegen bug where a far pointer's 16-bit OFFSET half is # built from the pointer's BANK register. # # The bank register is the DP slot the prologue fills with `stx ` (the # incoming pointer arrives as offset-in-A, bank-in-X). Flagging a # `lda ... sta 0xe0` means the pointer used for the following # [dp],y access has the bank value in its offset half -- it reads a stray # address. Correct code reloads A with the offset (pla / txa / lda n,s) # before storing to 0xe0. import re, sys BOILER = re.compile(r'(sty\s+0xfa|ldy\s+0xfa|ldy\s+#|sta\s+\[0x[0-9a-f]+\], y|lda\s+\[0x[0-9a-f]+\], y|nop)') def scan(path): lines = [l.strip() for l in open(path).read().split("\n")] # function start lines starts = [i for i, l in enumerate(lines) if re.match(r'^[A-Za-z_][A-Za-z0-9_]*:', l)] bounds = list(zip(starts, starts[1:] + [len(lines)])) hits = [] for s, e in bounds: name = lines[s].split(":")[0] bank = None for i in range(s, min(s + 40, e)): m = re.match(r'stx\s+(0x[0-9a-f]+)$', lines[i]) if m: bank = m.group(1) break if bank is None: continue for i in range(s, e): if not re.match(r'sta\s+0x(e0|e4|e8|ec)$', lines[i]): continue j = i - 1 while j > s and BOILER.match(lines[j]): j -= 1 if lines[j] == "lda\t%s" % bank or lines[j] == "lda %s" % bank: hits.append((name, i + 1, bank, lines[i])) return hits bad = 0 for p in sys.argv[1:]: h = scan(p) if h: bad += len(h) print("%s: %d" % (p, len(h))) for fn, ln, bk, u in h: print(" %-28s line %-6d bank=%s -> %s" % (fn, ln, bk, u)) print("total suspect pointer builds: %d" % bad)