fs2port/port/tools/codeMap.py

64 lines
2.8 KiB
Python
Executable file

#!/usr/bin/env python3
# Static 6502 code discovery for an overlay image: follows jsr/jmp/branches
# from the given entry points (plus optional executed-PC seeds) and prints
# code ranges, data gaps and the out-of-window call targets.
# usage: codeMap.py image.bin base_hex entry_hex[,entry_hex...] [pcs.txt]
import sys
img=open(sys.argv[1],'rb').read(); base=int(sys.argv[2],16)
entries=[int(x,16) for x in sys.argv[3].split(',')]
seeds=set()
if len(sys.argv)>4:
for line in open(sys.argv[4]):
v=int(line.strip().lstrip('$'),16)
if base<=v<base+len(img): seeds.add(v)
# opcode lengths / kinds
LEN={}
for op in range(256): LEN[op]=None
def setl(ops,n):
for o in ops: LEN[o]=n
imm=[0x69,0x29,0xC9,0xE0,0xC0,0x49,0xA9,0xA2,0xA0,0x09,0xE9]
zp=[0x65,0x25,0x06,0x24,0xC5,0xE4,0xC4,0xC6,0x45,0xE6,0xA5,0xA6,0xA4,0x46,0x05,0x26,0x66,0xE5,0x85,0x86,0x84]
zpx=[0x75,0x35,0x16,0xD5,0xD6,0x55,0xF6,0xB5,0xB4,0x56,0x15,0x36,0x76,0xF5,0x95,0x94]
zpy=[0xB6,0x96]
indx=[0x61,0x21,0xC1,0x41,0xA1,0x01,0xE1,0x81]
indy=[0x71,0x31,0xD1,0x51,0xB1,0x11,0xF1,0x91]
absl=[0x6D,0x2D,0x0E,0x2C,0xCD,0xEC,0xCC,0xCE,0x4D,0xEE,0x4C,0x20,0xAD,0xAE,0xAC,0x4E,0x0D,0x2E,0x6E,0xED,0x8D,0x8E,0x8C]
absx=[0x7D,0x3D,0x1E,0xDD,0xDE,0x5D,0xFE,0xBD,0xBC,0x5E,0x1D,0x3E,0x7E,0xFD,0x9D]
absy=[0x79,0x39,0xD9,0x59,0xB9,0xBE,0x19,0xF9,0x99]
impl=[0x0A,0x00,0x18,0xD8,0x58,0xB8,0xCA,0x88,0xE8,0xC8,0x4A,0xEA,0x48,0x08,0x68,0x28,0x2A,0x6A,0x40,0x60,0x38,0xF8,0x78,0xAA,0xA8,0xBA,0x8A,0x9A,0x98]
br=[0x10,0x30,0x50,0x70,0x90,0xB0,0xD0,0xF0]
setl(imm,2);setl(zp,2);setl(zpx,2);setl(zpy,2);setl(indx,2);setl(indy,2);setl(absl,3);setl(absx,3);setl(absy,3);setl(impl,1);setl(br,2)
LEN[0x6C]=3
code=set(); starts=set(); ext={}; work=list(entries)+sorted(seeds)
def rd(a): return img[a-base]
while work:
pc=work.pop()
while base<=pc<base+len(img) and pc not in starts:
op=rd(pc); n=LEN[op]
if n is None: break # illegal -> treat as data
starts.add(pc)
for i in range(n): code.add(pc+i)
if op in br:
t=pc+2+((rd(pc+1)^0x80)-0x80); work.append(t); pc+=2; continue
if op==0x20 or op==0x4C:
t=rd(pc+1)|(rd(pc+2)<<8)
if base<=t<base+len(img): work.append(t)
else: ext.setdefault(t,set()).add(pc)
if op==0x4C: break
pc+=3; continue
if op in (0x60,0x40,0x00,0x6C): break
pc+=n
rs=[]
for a in sorted(code):
if rs and a==rs[-1][1]+1: rs[-1][1]=a
else: rs.append([a,a])
print('code bytes:',len(code),'of',len(img))
print('code ranges:',' '.join('%04X-%04X'%(a,b) for a,b in rs))
gaps=[]
prev=base
for a,b in rs:
if a>prev: gaps.append((prev,a-1))
prev=b+1
if prev<base+len(img): gaps.append((prev,base+len(img)-1))
print('data gaps:',' '.join('%04X-%04X(%d)'%(a,b,b-a+1) for a,b in gaps if b-a>=0))
print('external targets:',' '.join('%04X'%t for t in sorted(ext)))