diff --git a/emulator/firmware-decomp/emu_replay.py b/emulator/firmware-decomp/emu_replay.py new file mode 100644 index 0000000..e39fc43 --- /dev/null +++ b/emulator/firmware-decomp/emu_replay.py @@ -0,0 +1,104 @@ +"""Replay a captured VelociRender wire through the REAL firmware in emu860. + +Feeds each captured (action, payload) command to the firmware's own handler +(payload pointer in r16, per the PGI calling convention), building the scene up +in the emulated i860's memory, then runs draw_scene -- capturing the IGC +coefficient stream the firmware emits (the Tier-1 handoff). + +Bypasses the transputer/CCB/interrupt path (see HARDWARE-ARCHITECTURE.md): we +call the handlers directly, which is valid because they read the raw wire payload. + + python emu_replay.py [capture.raw.bin] [--verbose] +""" +import sys, os, struct +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +sys.path.insert(0, r'C:\VWE\TeslaRel410\dpl3-revive\patha') +import emu860 +from vrboard import Assembler, A, BOOT_ACTIONS + +MNG = r'C:\VWE\TeslaRel410\sda4\RPLIVE\VREND.MNG' + +def s26(v): return v - 0x4000000 if v & 0x2000000 else v + +# Confirmed WIRE-action -> handler map (vaddr). IMPORTANT: the firmware's +# dispatch jump table (file 0x47cb8) is indexed by an INTERNAL command code, NOT +# the wire action -- velocirender_input remaps wire->internal first (e.g. wire +# draw_scene=9 -> internal index 12; flush=3 -> 30; statistics=15 -> 31; while +# create/list_add/dcs_link are identity). So we can't index that table by the +# capture's action. These are matched by function identity instead (create's +# prologue verified reads type/handle; statistics verified returns; draw_scene, +# flush, list_add, dcs_link identified in the dispatch analysis). +# TODO: reverse the wire->internal remap in velocirender_input to complete the +# map for the high-frequency per-frame commands (0x09 draw, 0x1d artics, 0x2a). +WIRE_HANDLERS = { + A.create: 0xf040c180, + A.flush: 0xf040cfd8, + A.dcs_link: 0xf040dc70, + A.list_add: 0xf040d4d0, + A.draw_scene: 0xf040e340, + A.statistics: 0xf040e940, + A.set_texmap_texels: 0xf040a030, + # A.init handler + the 0x1d/0x2a artic handlers: need the remap (see TODO). +} + +def extract_handlers(cpu): + return dict(WIRE_HANDLERS) + +def parse_capture(path): + data = open(path, 'rb').read() + start = None + for i in range(0, len(data) - 8): + w = struct.unpack_from('