fs2port/port/tools/verify/snapDiff.py

43 lines
2.3 KiB
Python

#!/usr/bin/env python3
# Compare per-tick RAM snapshots from the oracle and the port and report
# the first snapshot where non-scratch game state differs.
# usage: snapDiff.py oracle.snaps port.snaps every [maxShow] [all] (all = do not stop at the first divergence)
import sys, re, bisect
a = open(sys.argv[1], 'rb').read(); b = open(sys.argv[2], 'rb').read()
every = int(sys.argv[3]); maxShow = int(sys.argv[4]) if len(sys.argv) > 4 else 25
showAll = len(sys.argv) > 5 and sys.argv[5] == 'all'
n = min(len(a), len(b)) // 65536
syms = []
for line in open('port/include/fs2Symbols.h'):
m = re.match(r'#define SYM_(\w+)\s+0x([0-9A-F]{4})', line)
if m: syms.append((int(m.group(2), 16), m.group(1)))
syms.sort(); addrs = [s[0] for s in syms]
def name(addr):
i = bisect.bisect_right(addrs, addr) - 1
off = addr - syms[i][0]
return syms[i][1] + (('+%d' % off) if off else '')
regions = [(0x0000, 0x0100), (0x0140, 0x0400), (0x0800, 0x0AB8), (0x0DB8, 0x1000),
(0x1E00, 0x1E10), (0x2000, 0x6000), (0xA7E0, 0xB3E0),
(0xD9E5, 0xD9EA), (0xDFB0, 0xDFBA), (0xE046, 0xE04B), (0xE675, 0xE67F),
(0xE800, 0xF000), (0xF242, 0xF260), (0xF715, 0xF71C), (0xF8E6, 0xF8E7),
(0xF9B3, 0xF9B4), (0xFAE9, 0xFAEC), (0xFC00, 0xFD00)]
scratch = set(list(range(0xA5, 0xB0)) + list(range(0xB0, 0xB4)) + list(range(0xB6, 0xC2)) + list(range(0xC2, 0xCA)) + [0xE5, 0xF1, 0xF2] + list(range(0xF4, 0xFA)) + list(range(0x3C, 0x40)) + list(range(0x98, 0x9C)) + [0x21, 0x22, 0x25, 0x26, 0x27, 0x53, 0x54, 0xAD, 0xAF, 0x1A, 0x1D, 0x20, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3])
for k in range(n):
sa = a[k*65536:(k+1)*65536]; sb = b[k*65536:(k+1)*65536]
diffs = []
for lo, hi in regions:
for i in range(lo, hi):
if sa[i] != sb[i] and i not in scratch:
diffs.append(i)
print('tick %3d: %d differing state bytes' % ((k + 1) * every, len(diffs)))
if diffs:
shown = 0; i = 0
while i < len(diffs) and shown < maxShow:
j = i
while j + 1 < len(diffs) and diffs[j + 1] == diffs[j] + 1: j += 1
s0, s1 = diffs[i], diffs[j]
m = min(8, s1 - s0 + 1)
print(' $%04X-$%04X (%3d) %-36s oracle=%s port=%s' % (s0, s1, s1 - s0 + 1, name(s0), sa[s0:s0+m].hex(), sb[s0:s0+m].hex()))
shown += 1; i = j + 1
if not showAll:
break