Files
CydandClaude Fable 5 1323397a50 pvision solved (texture-value ramp) + i860/hardware reverse-engineering
Predator/IR vision: reverse-engineered from the original firmware and
confirmed by the build team -- it is the Division board's TEXTURE-VALUE RAMP
mode (a "check your texture maps" diagnostic the devs hijacked), NOT a
grayscale squash or a false-colour palette. Located in VREND.MNG (effect
handler @0xe6c0, wire action 0x1b, type -1 ON / -2 OFF); ramp colours from
VR_DRAW.C. Renderer reworked to match: vrview_gl now does the 4-ramp
lerp(color0,color1,luminance(texel)) in the mesh pass (grayscale+defog
removed). Live-rendered on a new night-clear arena egg; crew A/B verdict
pending.

Firmware-decomp toolchain (emulator/firmware-decomp/), all built from the
project's own artifacts and validated:
- coff860.py    i860 COFF reader (symbols/sections), names match AS860 source
- derive860.py  derives the i860 opcode map from matched .S<->.O pairs
- dis860.py     i860 disassembler (98% on clean ground truth; proven on
                VREND.MNG -- velocirender_statistics decodes correctly)
- sigmatch860.py reloc-invariant signature matcher onto the stripped image
- i860-encoding.md / FIRMWARE-SYMBOLS.txt / README.md

PVISION-IMPLEMENTATION-GUIDE.md: self-contained hand-off for the BT411 team.

HARDWARE-ARCHITECTURE.md + hardware-photos/ (15 board shots): the Division
VelociRender card is a 2-board stack driving a 3-processor pipeline --
INMOS IMS T425-J25S (comms/control, runs vrendmon.btl) + Intel i860 XP-50 (FP
geometry, runs vrender.mng) + Division PXPL IGC 5.2 ASIC with ~48x PXPL EMC
5.1 (UNC Pixel-Planes-5 SIMD array; "EMC" = the firmware's configEMCs) +
Analog Devices ADV7150 RAMDAC + NTSC. Plus the VWE Video Distribution Board
(P/N 1404: AMD MACH130 + 3x Brooktree Bt477) for the 3-VGA-head cockpit split.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 22:29:53 -05:00

65 lines
2.8 KiB
Python

"""Minimal i860 COFF (magic 0x014d) reader: dump file header, sections, and the
symbol table (function/global names + section + value). Deterministic -- no
instruction decoding -- so it is a trustworthy reference map of the firmware
objects. Validates the format by checking the symbol names look like the known
AS860/PGI source (e.g. _createBang, _PAZsfx)."""
import sys, struct, glob, os
def rd(b, off, fmt): return struct.unpack_from(fmt, b, off)
def parse(path):
d = open(path, 'rb').read()
magic, nscns, timdat, symptr, nsyms, opthdr, flags = rd(d, 0, '<HHIIIHH')
out = {'path': path, 'magic': magic, 'nscns': nscns, 'nsyms': nsyms,
'symptr': symptr, 'opthdr': opthdr, 'flags': flags,
'sections': [], 'syms': []}
# section headers
base = 20 + opthdr
for i in range(nscns):
o = base + i * 40
name = d[o:o+8].split(b'\0')[0].decode('latin1')
paddr, vaddr, size, scnptr, relptr, lnnoptr, nreloc, nlnno, sflags = \
rd(d, o + 8, '<IIIIIIHHI')
out['sections'].append((name, vaddr, size, scnptr, nreloc, sflags))
# symbol table (18-byte SYMENT) + string table right after
strbase = symptr + nsyms * 18
def symname(o):
z, offs = rd(d, o, '<II')
if z == 0: # name is an offset into the string table
e = d.index(b'\0', strbase + offs)
return d[strbase + offs:e].decode('latin1')
return d[o:o+8].split(b'\0')[0].decode('latin1')
i = 0
while i < nsyms:
o = symptr + i * 18
nm = symname(o)
value, scnum, typ, sclass, naux = rd(d, o + 8, '<iHHBB')
out['syms'].append((nm, value, scnum, typ, sclass, naux))
i += 1 + naux
return out
SCLASS = {2: 'EXT', 3: 'STAT', 6: 'LABEL', 100: '.bb', 101: '.file'}
def report(o, want_funcs=True):
print(f"\n=== {os.path.basename(o['path'])} magic={o['magic']:#06x} "
f"nscns={o['nscns']} nsyms={o['nsyms']} ===")
for (name, vaddr, size, scnptr, nreloc, sf) in o['sections']:
print(f" sect {name:<10} vaddr={vaddr:#010x} size={size:#08x} "
f"reloc={nreloc}")
# external/static functions (scnum>0, class EXT/STAT), text-ish
funcs = [(nm, v, sc) for (nm, v, sn, ty, sc, na) in o['syms']
if sn > 0 and sc in (2, 3) and not nm.startswith('.')]
print(f" -- {len(funcs)} defined EXT/STAT symbols:")
for nm, v, sc in sorted(funcs, key=lambda x: x[1]):
print(f" {v:#010x} {SCLASS.get(sc,sc):<5} {nm}")
if __name__ == '__main__':
pats = sys.argv[1:] or [r'C:\VWE\TeslaRel410\sda4\DPL3\VRENDER\*.O']
files = []
for p in pats: files += glob.glob(p)
for f in sorted(files):
try:
report(parse(f))
except Exception as e:
print(f"\n=== {f}: PARSE FAILED: {e} ===")