#!/usr/bin/env python3 # Compare stsim output against a VICE trace segment. # compare.py [maxReports] import json, sys trace = [json.loads(l) for l in open(sys.argv[1])] start = int(sys.argv[2]) sim = [json.loads(l) for l in open(sys.argv[3])] maxRep = int(sys.argv[4]) if len(sys.argv) > 4 else 12 def fromTrace(r): g = bytes.fromhex(r['g7140']) pos = bytes.fromhex(r['pos']) hud = bytes.fromhex(r['hud']) # 0x0799 .. 0x07E6 def G(a): return g[a - 0x7140] def H(a): return hud[a - 0x0799] d = {} d['x'] = '%02X%02X.%02X' % (pos[9], pos[8], pos[7]) # 7D63 7D62 7D61 d['y'] = '%02X.%02X' % (pos[11], pos[10]) d['vx'] = '%02X%02X' % (G(0x714D), G(0x714C)) d['vy'] = '%02X%02X' % (G(0x714F), G(0x714E)) d['pad'] = G(0x7150) d['st'] = G(0x7163) d['ph'] = G(0x7164) d['in'] = '%02X' % G(0x7169) d['dir'] = '%02X' % G(0x716A) d['ptr0'] = '%02X' % G(0x7197) d['ptr1'] = '%02X' % G(0x7198) d['s1'] = '%02X%02X.%02X' % (G(0x7186), G(0x7176), G(0x717E)) d['en'] = '%02X' % G(0x7196) d['t4740']= r['t4740'].upper() d['rng'] = '%02X%02X' % (G(0x7171), G(0x7172)) d['fuel'] = G(0x71C9) d['slots']= G(0x715C) d['asi'] = pos[0x7D8E - 0x7D5A] if len(pos) > 0x7D8E - 0x7D5A else -1 d['score']= ''.join('%02X' % H(0x07C2 + k) for k in range(7)) d['fare'] = ''.join('%02X' % H(0x07E0 + k) for k in range(7)) d['fuelc']= ''.join('%02X' % H(0x07A6 + k) for k in range(12)) # sprite shadow positions $71A7.. interleaved X,Y for 8 sprites + msb $718D msb = G(0x718D) sx = '' for k in range(8): x = G(0x71A7 + 2*k) | (0x100 if (msb >> k) & 1 else 0) sx += '%03X%02X' % (x, G(0x71A8 + 2*k)) d['sprx'] = sx return d fields = ['x','y','vx','vy','pad','st','ph','in','dir','ptr0','ptr1','s1','en','t4740','rng','fuel','slots','score','fare','fuelc','sprx'] reports = 0 firstBad = None for s in sim: if 'end' in s: print('sim ended at tick', s['tick'], 'result', s['end']) break t = s['tick'] if start + t >= len(trace): print('trace exhausted at sim tick', t); break r = fromTrace(trace[start + t]) # Disabled sprites keep stale shadow values on the C64; only compare # positions/pointers of enabled ones. en = int(r['en'], 16) def spr(sx): return ''.join(sx[k*5:k*5+5] if (en >> k) & 1 else '-----' for k in range(8)) s2 = dict(s); r2 = dict(r) s2['sprx'] = spr(s['sprx']); r2['sprx'] = spr(r['sprx']) if not (en & 2): s2['ptr1'] = r2['ptr1'] = '--'; s2['s1'] = r2['s1'] = '--' bad = [f for f in fields if f in s2 and str(s2[f]) != str(r2[f])] s = s2; r = r2 if bad: if firstBad is None: firstBad = t if reports < maxRep: print(f'tick {t}: ' + ' '.join(f'{f}: sim={s[f]} c64={r[f]}' for f in bad)) reports += 1 if firstBad is None: print('ALL', len(sim), 'ticks match') else: print('first mismatch at tick', firstBad)