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>
53 lines
2.2 KiB
Python
53 lines
2.2 KiB
Python
"""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)")
|