Capture-embedded firmware extracted: cap7 carries the EXACT build the game ran
VR_COMMS.C boot_860() shows the host boots the render board by streaming the
whole .MNG over the wire: args860 ("i860 50MHz and kicking"), a 40-byte
code860 packet holding the 7-word header {csize,dsize,bsize,cstart,dstart,
bstart,entry}, then the code/data/bss segments. cap7's preamble is therefore
a complete firmware image -- and a DIFFERENT BUILD than sda4/RPLIVE/VREND.MNG
(text 0x31440 vs 0x39ec0), which explains the residual global-address
mismatches (version skew) when replaying cap7 against the sda4 build.
The wire header also confirms the link layout from the protocol itself:
cstart=0xf0400000, dstart=0x00001000, bstart=0x0001f4a0, entry=0xf0400000.
Note the streamed "bss" content is NOT zeros (10685/14272 nonzero bytes).
extract_capfw.py reassembles the image (capfw7.mng + capfw7.bss, committed);
it boots in emu860 to 0xf040062c then needs op 0x0d (new ctrl-reg variant).
run_to_draw.py = marathon runner with board-stream dump.
Next: re-derive the hook addresses (main/dN_receive/allocator/...) for the
capture build and replay cap7 against its own firmware, version-matched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,52 @@
|
||||
"""Extract the firmware image embedded in a wire capture's 860-boot preamble.
|
||||
|
||||
The dPL3 host boots the render board by STREAMING the whole .MNG over the wire
|
||||
(VR_COMMS.C boot_860): args860("i860 50MHz and kicking"), one 40-byte code860
|
||||
packet = the 7-word header {csize,dsize,bsize,cstart,dstart,bstart,entry},
|
||||
then code860/data860/bss860 segment packets. So every capture carries the
|
||||
EXACT firmware build the game ran -- run THAT for a version-matched replay
|
||||
(sda4/RPLIVE/VREND.MNG is a different build: text 0x39ec0 vs cap7's 0x31440).
|
||||
|
||||
Writes <out>.mng (12-byte header + text + data, emu860.load_mng format) and
|
||||
<out>.bss (the streamed bss-segment content -- NOT all zeros; load at bstart).
|
||||
|
||||
Usage: python extract_capfw.py <capture.raw.bin> <out-base>
|
||||
"""
|
||||
import sys, os, struct
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, r'C:\VWE\TeslaRel410\dpl3-revive\patha')
|
||||
from emu_replay import parse_capture
|
||||
from vrboard import A
|
||||
|
||||
cap = sys.argv[1] if len(sys.argv) > 1 else r'C:\VWE\TeslaRel410\dpl3-revive\patha\cap7.raw.bin'
|
||||
out = sys.argv[2] if len(sys.argv) > 2 else os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), 'capfw7')
|
||||
|
||||
cmds = parse_capture(cap)
|
||||
code, data, bss, hdr = [], [], [], None
|
||||
for a, pl in cmds:
|
||||
if a == A.code860:
|
||||
if hdr is None and len(pl) == 40:
|
||||
hdr = struct.unpack_from('<7I', pl, 0)
|
||||
continue
|
||||
code.append(pl)
|
||||
elif a == A.data860:
|
||||
data.append(pl)
|
||||
elif a == A.bss860:
|
||||
bss.append(pl)
|
||||
|
||||
csize, dsize, bsize, cstart, dstart, bstart, entry = hdr
|
||||
text, dat, bs = b''.join(code), b''.join(data), b''.join(bss)
|
||||
assert len(text) == csize and len(dat) == dsize and len(bs) == bsize, \
|
||||
f"stream/header mismatch: {len(text):#x}/{csize:#x} {len(dat):#x}/{dsize:#x} {len(bs):#x}/{bsize:#x}"
|
||||
|
||||
with open(out + '.mng', 'wb') as f:
|
||||
f.write(struct.pack('<III', csize, dsize, bsize))
|
||||
f.write(text)
|
||||
f.write(dat)
|
||||
with open(out + '.bss', 'wb') as f:
|
||||
f.write(bs)
|
||||
|
||||
print(f"{os.path.basename(cap)}: csize={csize:#x} dsize={dsize:#x} bsize={bsize:#x}")
|
||||
print(f" cstart={cstart:#010x} dstart={dstart:#010x} bstart={bstart:#010x} entry={entry:#010x}")
|
||||
print(f"-> {out}.mng (+ {out}.bss, {sum(1 for b in bs if b)} nonzero bytes)")
|
||||
@@ -0,0 +1,55 @@
|
||||
"""Marathon runner: authentic main() + cap7 through the first draw_scene frames.
|
||||
|
||||
Writes progress to stdout and dumps the captured IGC/board stream + a state
|
||||
summary when the command budget is reached (or on fault).
|
||||
"""
|
||||
import sys, os, time, struct
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import emu860, dis860, emu_main
|
||||
|
||||
CAP = sys.argv[1] if len(sys.argv) > 1 else r'C:\VWE\TeslaRel410\dpl3-revive\patha\cap7.raw.bin'
|
||||
MAXC = int(sys.argv[2]) if len(sys.argv) > 2 else 1600
|
||||
TIME_BUDGET = float(sys.argv[3]) if len(sys.argv) > 3 else 3300.0
|
||||
|
||||
emu860.Mem.log = lambda self, *a, **k: None
|
||||
r = emu_main.MainRunner(CAP, max_cmds=MAXC)
|
||||
cpu = r.cpu
|
||||
cpu.wr(1, cpu.RET_SENTINEL); cpu.wr(2, 0xc0000); cpu.wr(16, 0); cpu.wr(17, 0)
|
||||
cpu.pc = emu_main.MAIN
|
||||
|
||||
t0 = time.time(); last = t0
|
||||
result = 'time'
|
||||
while True:
|
||||
pc = cpu.pc
|
||||
if pc == cpu.RET_SENTINEL:
|
||||
result = 'main-returned'; break
|
||||
if pc < 0x100000:
|
||||
result = f'derail->{pc:#x}'; break
|
||||
h = r.hooks.get(pc)
|
||||
if h:
|
||||
if h(cpu) == 'done':
|
||||
result = 'queue-done'; break
|
||||
continue
|
||||
if not cpu.step():
|
||||
result = f'STOP {cpu.stopmsg}'; break
|
||||
now = time.time()
|
||||
if now - last > 60:
|
||||
last = now
|
||||
print(f" .. t={now-t0:6.0f}s steps={cpu.steps:,} cmds={r.qi} "
|
||||
f"igc={len(cpu.igc)} board={len(cpu.board_log)}", flush=True)
|
||||
if now - t0 > TIME_BUDGET:
|
||||
result = 'time-budget'; break
|
||||
|
||||
print(f"\nRESULT: {result}")
|
||||
print(f"steps={cpu.steps:,} cmds={r.qi}/{len(r.queue)} done={dict(r.done)}")
|
||||
print(f"replies={r.replies[:30]}")
|
||||
print(f"IGC writes={len(cpu.igc)} board-log={len(cpu.board_log)}")
|
||||
if cpu.stopmsg or result.startswith('derail'):
|
||||
for tpc, tw in cpu.tail[-16:]:
|
||||
m, ops = dis860.decode(tw, tpc)
|
||||
print(f" {tpc:#010x}: {tw:08x} {m} {ops}")
|
||||
out = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'igc_stream.bin')
|
||||
with open(out, 'wb') as f:
|
||||
for k, a, v in cpu.board_log:
|
||||
f.write(struct.pack('<BII', 1 if k == 'w' else 0, a, v))
|
||||
print(f"board stream -> {out} ({len(cpu.board_log)} entries)")
|
||||
Reference in New Issue
Block a user