Commit the vrend410 firmware asset + RE tooling; gitignore run artifacts

- vrend410.mng: the production firmware, a HARD dependency of the committed
  live pipeline (emu_main.py MAPS['vrend410'].fw loads it) -- the repo couldn't
  run the live renderer without it.
- txdn_probe.py / texstore_trace.py / texel_trace.py: standalone reverse-
  engineering probes (texture-source/DRAM-write/texel tracing) documenting the
  texid-binding and texel-format investigations.
- .gitignore: exclude the firmware-decomp run artifacts (emu860c.pyd rebuildable
  from source, *.log/*.pkl/*.png renderer outputs + caches), editor junk, and
  the game runtime state/logs written by running the pod.

Left untouched deliberately: the parallel Mech session's in-progress
restoration/source410/BT/{EMITTER,BTPLAYER}.CPP edits (theirs to commit) and
the tracked game runtime state (LAST.EGG/CTMIX.CFG etc. -- transient).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-20 11:43:46 -05:00
co-authored by Claude Opus 4.8
parent b447e71864
commit a89d08e1c9
5 changed files with 192 additions and 0 deletions
+22
View File
@@ -15,3 +15,25 @@ __pycache__/
# 4.10 source reconstruction build outputs (rebuild: bash restoration/source410/build410.sh all)
/restoration/build410/
# firmware-decomp build/run artifacts
# emu860c.pyd: rebuild via the gcc line in emu860c/emu860c.c's header
# *.log/*.pkl/*.png: renderer run outputs + caches (regenerated by the scripts)
/emulator/firmware-decomp/emu860c/*.pyd
/emulator/firmware-decomp/emu860c/*.log
/emulator/firmware-decomp/emu860c/*.pkl
/emulator/firmware-decomp/emu860c/*.png
/emulator/firmware-decomp/igc_stream.bin
# editor / build junk
/restoration/.obj.obj
/.finf/
# game runtime state written by running the pod (logs, egg backups)
/ALPHA_1/REL410/BT/LOG
/ALPHA_1/REL410/BT/NN.LOG
/ALPHA_1/REL410/BT/RUN.LOG
/ALPHA_1/REL410/RP/NN.LOG
/ALPHA_1/VWETEST/VGLTEST/REPORT/TEST.LOG
/ALPHA_1/WEAPONLO.TXT
/ALPHA_1/REL410/BT/TESTARN.EGG.pre_pilot
@@ -0,0 +1,62 @@
"""Find where the production build stores texels: run the battle wire to the
first sizable set_texmap_texels + its 0x1a bulk run, watching ALL DRAM writes
during those commands -> the texel destination + layout + format."""
import sys, os, struct, collections
HERE=os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0,HERE); sys.path.insert(0,os.path.dirname(HERE))
sys.path.insert(0,r'C:\VWE\TeslaRel410\dpl3-revive\patha')
import emu860, emu_main, emu860c
from driver import boot, CpuShim
from vrboard import A
ANAME={int(a):a.name for a in A}
emu860.Mem.log=lambda self,*a,**k:None
data=open(r'C:/VWE/TeslaRel410/emulator/render-bridge/captures/netdeath-20260708.fifodump','rb').read()
recs=[]; off=0
while True:
i=data.find(b'VPXM',off)
if i<0: break
ln=struct.unpack_from('<I',data,i+4)[0]; body=data[i+8:i+8+ln]; off=i+8+ln
if len(body)>=4:
a=struct.unpack_from('<I',body,0)[0]
if a<0x100: recs.append((a,body[4:]))
# find first set_texmap_texels with header n_texels>0 (mode field) then following 0x1a runs
def w32(p,o): return struct.unpack_from('<I',p,o)[0]
tex_idx=None
for i,(a,p) in enumerate(recs):
if ANAME.get(a)=='set_texmap_texels' and len(p)>=20:
h=[w32(p,4*k) for k in range(5)]
# header: remote, n_texels, u, v, mode
if h[1]>16 and h[2]*h[3]==h[1]:
tex_idx=i; hdr=h; break
print("first real texmap @cmd %d: remote=%#x n=%d u=%d v=%d mode=%d"%((tex_idx,)+tuple(hdr)))
r=boot(fw='vrend410', queue=recs); shim=CpuShim()
RECV=emu_main.MAPS['vrend410']['receive']
# advance to just before tex_idx
while r.qi < tex_idx:
reason,_=emu860c.run(500_000_000)
if reason==3: continue
pc=emu860c.getstate()['pc']; h=r.hooks.get(pc)
if h is None: break
if h: h(shim)
# now watch writes across tex_idx and the next ~10 commands (the 0x1a bulk)
emu860c.watch_add(0x08000000, 0x0c000000)
emu860c.watch_drain()
stop_qi=tex_idx+12
while r.qi < stop_qi:
reason,_=emu860c.run(200_000_000)
if reason==3: continue
pc=emu860c.getstate()['pc']; h=r.hooks.get(pc)
if h is None: break
if h: h(shim)
raw=emu860c.watch_drain()
vals=struct.unpack('<%dI'%(len(raw)//4), raw)
addrs=vals[0::2]
pages=collections.Counter(a>>12 for a in addrs)
print("write pages during texmap upload (top 12):")
for pg,n in pages.most_common(12):
print(" %#x000 : %d"%(pg,n))
# dump a sample of the biggest page's writes to see texel format
top=pages.most_common(1)[0][0]<<12
sample=[(addrs[k], vals[2*k+1]) for k in range(len(addrs)) if (addrs[k]>>12)==(top>>12)][:8]
print("sample writes @%#x:"%top)
for a,v in sample: print(" %#010x <- %08x"%(a,v))
@@ -0,0 +1,55 @@
"""Where does the production build store 0x1a texels? Watch DRAM writes during
one texture's header+bulk upload -> the storage base per handle."""
import sys, os, struct, collections
HERE=os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0,HERE); sys.path.insert(0,os.path.dirname(HERE))
sys.path.insert(0,r'C:\VWE\TeslaRel410\dpl3-revive\patha')
import emu860, emu_main, emu860c
from driver import boot, CpuShim
from vrboard import A
ANAME={int(a):a.name for a in A}
emu860.Mem.log=lambda self,*a,**k:None
data=open(r'C:/VWE/TeslaRel410/emulator/render-bridge/captures/netdeath-20260708.fifodump','rb').read()
recs=[]; off=0
while True:
i=data.find(b'VPXM',off)
if i<0: break
ln=struct.unpack_from('<I',data,i+4)[0]; body=data[i+8:i+8+ln]; off=i+8+ln
if len(body)>=4:
a=struct.unpack_from('<I',body,0)[0]
if a<0x100: recs.append((a,body[4:]))
# first 0x1a header (cmd 55, handle 0xc)
tex_start=None
for i,(a,p) in enumerate(recs):
if a==0x1a and len(p)==32:
tex_start=i; hdr=[struct.unpack_from('<I',p,4*k)[0] for k in range(8)]; break
print("texture upload @cmd %d handle=%#x u=%d v=%d"%(tex_start,hdr[0],hdr[2],hdr[3]))
r=boot(fw='vrend410', queue=recs); shim=CpuShim()
while r.qi < tex_start:
reason,_=emu860c.run(500_000_000)
if reason==3: continue
pc=emu860c.getstate()['pc']; h=r.hooks.get(pc)
if h is None: break
if h: h(shim)
emu860c.watch_add(0x08000000,0x0c000000); emu860c.watch_drain()
# run through the whole texture (header + 64 rows)
stop=tex_start+66
while r.qi < stop:
reason,_=emu860c.run(200_000_000)
if reason==3: continue
pc=emu860c.getstate()['pc']; h=r.hooks.get(pc)
if h is None: break
if h: h(shim)
raw=emu860c.watch_drain()
vals=struct.unpack('<%dI'%(len(raw)//4),raw)
addrs=vals[0::2]; wvals=vals[1::2]
pages=collections.Counter(a>>12 for a in addrs)
print("write pages during upload:")
for pg,n in pages.most_common(8):
lo=min(a for a in addrs if a>>12==pg); hi=max(a for a in addrs if a>>12==pg)
print(" %#x000 : %d writes span %#x..%#x"%(pg,n,lo,hi))
# find contiguous run matching texel pattern (0x00BBGGRR grayscale)
top=pages.most_common(1)[0][0]
run=[(addrs[k],wvals[k]) for k in range(len(addrs)) if addrs[k]>>12==top][:6]
print("sample @page %#x000:"%top)
for a,v in run: print(" %#010x <- %08x"%(a,v))
@@ -0,0 +1,53 @@
"""Capture the full per-tile DMA stream (incl TXDN, opcode 3) for one battle
draw -> the texture source addresses, to key the texid->texture binding."""
import sys, os, struct, collections
HERE=os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0,HERE); sys.path.insert(0,os.path.dirname(HERE))
sys.path.insert(0,r'C:\VWE\TeslaRel410\dpl3-revive\patha')
import emu860, emu_main, emu860c
from driver import boot, CpuShim
from vrboard import A
ANAME={int(a):a.name for a in A}
emu860.Mem.log=lambda self,*a,**k:None
data=open(r'C:/VWE/TeslaRel410/emulator/render-bridge/captures/netdeath-20260708.fifodump','rb').read()
recs=[]; off=0
while True:
i=data.find(b'VPXM',off)
if i<0: break
ln=struct.unpack_from('<I',data,i+4)[0]; body=data[i+8:i+8+ln]; off=i+8+ln
if len(body)>=4:
a=struct.unpack_from('<I',body,0)[0]
if a<0x100: recs.append((a,body[4:]))
TARGET=6234
r=boot(fw='vrend410', queue=recs); shim=CpuShim()
RECV=emu_main.MAPS['vrend410']['receive']
while r.qi < TARGET:
reason,_=emu860c.run(500_000_000)
if reason==3: continue
pc=emu860c.getstate()['pc']; h=r.hooks.get(pc)
if h is None: break
if pc==RECV and r.qi>=TARGET-1 and ANAME.get(r.queue[r.qi][0])=='draw_scene':
emu860c.watch_add(0x08020000,0x08160000); emu860c.watch_drain()
h(shim)
while True:
reason,_=emu860c.run(500_000_000)
if reason==3: continue
if emu860c.getstate()['pc']==RECV: break
hh=r.hooks.get(emu860c.getstate()['pc'])
if hh: hh(shim)
else: break
break
if h: h(shim)
raw=emu860c.watch_drain()
vals=struct.unpack('<%dI'%(len(raw)//4),raw)
# DMA pairs {addr, opcode}; opcodes: 1/9 SEND, 2 TILE, 3 TXDN, 0 GOTO, 6 FLUSH, f STOP
opnames={0:'GOTO',1:'SEND',2:'TILE',3:'TXDN',6:'FLUSH',8:'WAIT',9:'SENDE',0xf:'STOP'}
txdn=collections.Counter(); tiles=[]
for i in range(0,len(vals)-1,2):
a,op=vals[i],vals[i+1]; c=(op>>28)&0xf
if c==3: txdn[a]+=1
elif c==2: tiles.append(a)
print("distinct TXDN source addresses: %d"%len(txdn))
for a,n in txdn.most_common(12):
print(" TXDN src %#010x : %d tiles"%(a,n))
print("tiles: %d"%len(tiles))
Binary file not shown.