diff --git a/emulator/firmware-decomp/content_frame.py b/emulator/firmware-decomp/content_frame.py new file mode 100644 index 0000000..dff8385 --- /dev/null +++ b/emulator/firmware-decomp/content_frame.py @@ -0,0 +1,91 @@ +"""THE TRUE FRAME, attempt 1: walk the bin-page chains (trek_wide30) region by region; +for each content SEND (payloads at 0x815xxxx+, from trek_content30) parse the payload, +extract float coefficients, reconstruct edge triples -> triangle vertices (pairwise +line intersection), place by the region's TILE origin, plot everything.""" +import pickle, struct, collections +S = r'C:\Users\cyd\AppData\Local\Temp\claude\c--VWE-TeslaRel410\4e848c76-6e89-4034-8047-d8d491cb32d8\scratchpad' +wide = pickle.load(open(S + r'\trek_wide30.pkl', 'rb'))['mem'] +content = pickle.load(open(S + r'\trek_content30.pkl', 'rb'))['mem'] + +def asf(w): + return struct.unpack('> 23) & 0xff + return 1 < e < 254 and 1e-6 < abs(asf(w)) < 1e6 + +# 1) per-region chains from bin pages: collect (send_addr, size) + tile id per page +OPS = {0x1: 'SEND', 0x9: 'SENDE', 0x2: 'TILE', 0x3: 'TXDN', 0x6: 'FLUSH', + 0x0: 'GOTO', 0xf: 'STOP', 0x8: 'WAIT'} +regions = [] # (page, tile_id, [(addr,size,op)]) +for page_base in sorted(set(a & ~0xfff for a in wide if a >= 0x0801e000)): + sends = []; tile = None + a = page_base + while a < page_base + 0x800: + w0 = wide.get(a); w1 = wide.get(a + 4) + if w0 is None or w1 is None: + a += 8; continue + code = (w1 >> 28) & 0xf + name = OPS.get(code) + if name in ('SEND', 'SENDE') and w0 >= 0x08000000: + sends.append((w0, w1 & 0x7f, name)) + elif name == 'TILE': + tile = w0 + a += 8 + if sends: + regions.append((page_base, tile, sends)) +print("regions with sends: %d" % len(regions)) + +# 2) parse content payloads: floats per block +def parse_payload(addr, size): + floats = [] + for i in range(size): + w = content.get(addr + i * 4) + if w is None: + w = wide.get(addr + i * 4) + if w is None: continue + if isf(w): + floats.append((i, asf(w))) + return floats + +# 3) reconstruct: for each region, each content send -> triangle from edge triples +def isect(e1, e2): + (a1, b1, c1), (a2, b2, c2) = e1, e2 + d = a1 * b2 - a2 * b1 + if abs(d) < 1e-9: return None + return ((b1 * c2 - b2 * c1) / d, (a2 * c1 - a1 * c2) / d) + +tris = [] # (tile, [(x,y)..]) +stats = collections.Counter() +sample_shown = 0 +for page, tile, sends in regions: + for addr, size, op in sends: + if 0x08014000 <= addr < 0x08018000: + stats['std'] += 1; continue + stats['content'] += 1 + fl = parse_payload(addr, size) + if sample_shown < 3 and len(fl) >= 6: + print("\nsample payload @%08x size=%d tile=%s floats:" % (addr, size, tile)) + for i, f in fl[:12]: + print(" +%02x %.6g" % (i * 4, f)) + sample_shown += 1 + # edge-triple attempt: first 9 floats as 3x(A,B,C) + vals = [f for _, f in fl] + if len(vals) >= 9: + e = [tuple(vals[k*3:k*3+3]) for k in range(3)] + pts = [isect(e[0], e[1]), isect(e[1], e[2]), isect(e[2], e[0])] + if all(p and -200 < p[0] < 200 and -200 < p[1] < 200 for p in pts): + tris.append((tile, pts)) +print("\nstats:", dict(stats), " reconstructed tris:", len(tris)) +if tris: + # place by tile origin: id=(row<<5)|col + W, H = 832, 512 + canvas = [[0]*104 for _ in range(40)] + for tile, pts in tris: + ox = ((tile or 0) & 0x1f) * 64; oy = (((tile or 0) >> 5) & 0x1f) * 128 + for x, y in pts: + gx = int((ox + x) / W * 103); gy = int((oy + y) / H * 39) + if 0 <= gx < 104 and 0 <= gy < 40: canvas[gy][gx] += 1 + print("vertex scatter (tile-placed):") + mx = max(max(r) for r in canvas) or 1 + for row in canvas: + print(" " + "".join(" .:-=+*#%@"[min(9, int(c/mx*9.99))] if c else " " for c in row)) diff --git a/emulator/firmware-decomp/dumpcontent.py b/emulator/firmware-decomp/dumpcontent.py new file mode 100644 index 0000000..6c408ad --- /dev/null +++ b/emulator/firmware-decomp/dumpcontent.py @@ -0,0 +1,45 @@ +"""Dump the payload region MEMORY (0x8014000-0x8018000) at draw ~30 and draw ~300 of +trek — the full compiled scene at two depths, independent of when writes occurred. +Saves trek_content30.pkl / trek_content300.pkl for frame assembly.""" +import sys, time, struct, pickle +sys.path.insert(0, r'C:\VWE\TeslaRel410\emulator\firmware-decomp') +sys.path.insert(0, r'C:\VWE\TeslaRel410\dpl3-revive\patha') +import emu860, dis860, emu_main +emu860.Mem.log = lambda self, *a, **k: None +S = r'C:\Users\cyd\AppData\Local\Temp\claude\c--VWE-TeslaRel410\4e848c76-6e89-4034-8047-d8d491cb32d8\scratchpad' +snap = pickle.load(open(S + r'\snap_trek0.pkl', 'rb')) +r = emu_main.MainRunner(r'C:\VWE\TeslaRel410\dpl3-revive\patha\trek.raw.bin', + fw='capfw7', max_cmds=30000) +cpu = r.cpu +cpu.mem.pages = {k: bytearray(v) for k, v in snap['pages'].items()} +cpu.ctrl.clear(); cpu.ctrl.update(snap['ctrl']) +cpu.r = list(snap['r']); cpu.f = list(snap['f']); cpu.cr = dict(snap['cr']); cpu.pc = snap['pc'] +cpu._apipe = list(snap['apipe']); cpu._mpipe = list(snap['mpipe']); cpu._fp_pipes() +cpu._lpipe = list(snap['lpipe']); cpu._gpipe = list(snap['gpipe']) +cpu._kr, cpu._ki, cpu._t = snap['kr'], snap['ki'], snap['t'] +cpu.lcc = snap['lcc']; r.qi = snap['qi']; r.heap = list(snap['heap']) + +def dump(tag): + words = {} + for a in range(0x0815e000, 0x08180000, 4): + w = cpu.mem.r32(a) + if w: + words[a] = w + pickle.dump({'mem': words, 'qi': r.qi}, + open(S + r'\trek_content%s.pkl' % tag, 'wb')) + print("dumped %d nonzero words at cmd %d -> trek_content%s.pkl" % + (len(words), r.qi, tag), flush=True) + +t0 = time.time(); startq = r.qi +targets = [(startq + 60, '30')] +ti = 0 +while time.time() - t0 < 800 and ti < len(targets): + if r.qi >= targets[ti][0]: + dump(targets[ti][1]); ti += 1 + continue + h = r.hooks.get(cpu.pc) + if h: + if h(cpu) == 'done': break + continue + if not cpu.step(): break +print("done at cmd %d in %.0fs" % (r.qi, time.time() - t0)) diff --git a/emulator/firmware-decomp/render-readout.html b/emulator/firmware-decomp/render-readout.html index 4c45536..85f2751 100644 --- a/emulator/firmware-decomp/render-readout.html +++ b/emulator/firmware-decomp/render-readout.html @@ -1,782 +1,779 @@ -VelociRender — firmware render output - - - -
-
VWE TESLA · Division VelociRender · i860 firmware emulator
-

The board's own firmware
is rendering again

-

A cycle-faithful Intel i860 interpreter now runs the game's - actual shipped firmware — booted, initialised, and fed a complete recorded - mission over the wire. It replays every command, emits the real - PXPL5 IGC render stream, and projects the scene geometry. Below is an object - it drew, its vertices and normals pulled straight off the emulated chip and - reconstructed in 3D — geometry this board's firmware has not computed in thirty years.

- -
- reconstructed · firmware geometry + normals - -
the object cap7 was drawing — its 45 projected vertices resolve into a - complete 9×5 height-field surface, rebuilt here in true 3D and lit by the board's own - per-vertex normals. Pulled live off the emulated i860.
-
- -
- -
trace · i860 execution → IGC command DMA
-
- -
-
26,422
wire commands replayed (whole mission)
-
8,562
draw_scene frames processed
-
191/192
screen regions binned with geometry
-
0
unimplemented ops remaining on the path
-
- -
-

01 The render signal chain

-

Nothing here is re-interpreted by us. Each stage is the firmware's own - code executing on the emulated i860 — from parsing the wire packet to writing - the bit-serial micro-program the Pixel-Planes array runs.

-
-
in
Wire
dN_receive → 42-action dispatch
-
cpu
i860
transform · clip · classify
-
geom
Binitize
per-region 64×128 bins
-
out
IGC DMA
SEND / TILE / FLUSH stream
-
px
Pixel-Planes
array model simulated · §05
-
-
- -
-

02 The output, decoded

-

The firmware DMAs the render to the card as an opcode stream - (DMAENGN.H). Both panels below are captured verbatim from the - emulator. Left: a real per-region command list — every region references the same - tile-relative payloads and differs only in its TILE id and the - GOTO link. Right: inside a SEND — the payload isn't opaque, it - interleaves control words with the actual float coefficients, swept bit-plane by - bit-plane into pixel memory.

-
-
-
-  region 0x0801fa40 · DMA list
-
# addr            opcode
-0x08015000  SEND(4)      ; edge coeffs
-0x00000000  FLUSH
-0x08015020  SENDE(0x45)  ; z / colour
-0x00000000  FLUSH
-0x08014100  TXDN
-0x08015260  SEND(0x21)
-0x08015380  SEND(0x29)
-0x00000020  TILE     ; tile id
-0x0801f008  GOTO     ; → next region
-
-
-
-  SENDE target 0x08015020 · payload
-
# bit-serial sweep (MEMpluseqMEM)
-+000  00000100   ; header
-+004  3a804834   ; = 9.79e-4  float
-+008  8401213a
-+00c  00000021   ; bit-plane 0x21
-+010  ba01253a   ; = −4.93e-4  += A
-+018  8381213a
-+01c  00000022   ; bit-plane 0x22 …
-
-
-

Pull the floats out of those payloads and they - line up into clean ×2 chains — - 0.0079 · 0.016 · 0.032 · 0.063 · 0.126 · 0.252 · 0.504 · 1.009 — - a coefficient stored as its binary place values C·2ᵏ, one per - bit-plane, exactly how a bit-serial adder holds a number. And the recovered values are the - object's own geometry: a payload edge coefficient (0.12527) lands on - the edge normal computed from the captured vertices (0.12555) to - 0.2%. The plane constants sit alongside as fixed-point screen coordinates - (0x0000ec00 = 236.0, a vertex x). The coefficients feeding the array - simulator (§05) are the ones the hardware actually shipped.

-
- -
-

03 Where the geometry landed

-

At the frame flush the firmware walks the screen-bin array and hands the - IGC one descriptor per 64×128 region. This grid is drawn from the real captured - descriptor scan — filled cells are regions that received transformed geometry. - A full mission view fills nearly the whole frame: ground plane and sky, exactly as expected.

-
- -
- region has geometry - empty region (shared page) - 96 × 2 descriptor grid · 191 of 192 filled -
-
-
- -
-

04 How the death-camera saw it

-

The surface above is the same 45 vertices, sorted back into model space — - they form an exact 9 × 5 height-field grid (x and z in even 2-unit steps, y the - height at every node; all 45 cells filled). What the board actually wrote to screen is - below: cap7's death-camera views that surface nearly edge-on, so the frame the i860 - projected is a thin, folded sliver. It is authentic output — just an awkward angle. Left, - that projection Gouraud-shaded; right, its raw VSTRIP wireframe.

-
-
- -
the board's screen-space frame — Gouraud-shaded, - grazing near-edge-on angle
-
-
- -
raw VSTRIP wireframe — 4 strips, 45 vertices, - exactly as the i860 emitted them
-
-
-
- -
-

05 The Pixel-Planes array, simulated

-

This is the final stage in silicon — and it now runs in software. The - PXPL5 IGC is a region rasteriser: the screen splits into - 64 × 128 tiles; every pixel carries a 26-byte bit-memory and an enable bit; all - pixels evaluate one linear tree in lockstep — - eval_ltree(x,y,A,B,C) = (int)(x·A + y·B + C). A triangle becomes - three edge trees into the enable register, then Z and R/G/B planes - interpolated per pixel and z-buffered in pixel memory (IGCOPS.C). - Fed the captured surface, the model lights the tiles below and renders pixels that match our - reference rasteriser to within edge anti-aliasing — the array reproduced faithfully.

-
-
- -
the depth buffer, read straight out of pixel memory — the 24-bit - Z plane the SENDE z-sweep interpolates (near = bright)
-
-
- -
the object's footprint — 18 of 50 64×128 tiles lit, - each a region of pixel processors
-
-
-
-
pixel memory · 26 bytes = 208 bits
-
- Z · 24bR·8G·8 - B·8enable + working bits -
-
    -
  • three edge trees → the enable register (the inside test)
  • -
  • Z / R / G / B are planes, evaluated per pixel by the linear tree
  • -
  • z-buffer via MEM2geMEM2; every write gated by enable
  • -
  • the depth image (left) is that Z plane, read back out of pixel memory
  • -
  • validated pixel-faithful to the reference — ~1%, at edges only
  • -
-
-

What this is not, yet: a full from-scratch run of - the compiled micro-code the DMA ships (§02) — the form the geometry takes on the wire to the - card. But that stream is now largely decoded: the command lists read cleanly, - the SENDE z-sweep resolves into a regular 4-word instruction, and its - coefficients are the same ones driving this depth buffer — the array's inputs are - cross-validated against the hardware's own compiled stream. And scanning - all 14,223 payload writes of this draw, every screen coordinate lands in the object's own - range (x 66–236) — this death-cam frame carries no geometry beyond - the object; the rest is a background clear. So the array's render above isn't one primitive of - many: for this frame, it is the geometry.

-
- -
-

06 A live scene emits — the Star Trek demo

-

The archive's trek capture — unreleased Star Trek - material — now replays and draws. After the dual-instruction-mode fix, its full - pipeline runs on the emulated i860: classify, LOD select, rasterise, and emit compiled - micro-code per 64×128 tile. Below is a structural map of that emit stream, read - back out of DRAM: 21 payload blocks, each a compiled primitive program — colors - distinguish blocks, position reflects each program's instruction fields. It is not yet - the screen image: cross-checking against the board's own source - (EOF.S / DIVPXMAP.H) shows the fields are - pixel-memory bit addresses and coefficients, whose exact per-macro layout is the decode in - progress — and this block set turns out to be the standard screen program shared - across captures (98.98% identical between the trek and Klingon demos), with the demo-specific - geometry still to be located in memory. What it proves stands: the full pipeline runs, the - emit stream is readable, and the compiled programs are being captured one by one.

-
- emit-stream structure · exact frame decode in progress - -
trek, draws 1–300 (compile-once showcase scene) — each colored - run is one compiled primitive program's field pattern in the emit stream.
-
-
- -
-

07 What it took to get here

-

The i860 core was corrected against the toolchain's own assembler output - and MAME's validated i860 model. A selection of the load-bearing fixes:

-
-
store encoding
i860 stores keep the source in bits 15:11 and split the offset — every function return went to 0 until this was found. Prologues now save r1.
-
op 0x13 escape
lock / calli / unlock share one opcode; everything decoded as calli, so every spinlock jumped to address 0. The phantom "exit stub."
-
FP pipeline
Exact PFAM/PFMAM dual-ops, per-stage precision, fdest bypass. The Newton–Raphson divide now yields 16 ÷ 16 = 1 through the pipes, unhooked.
-
pipelined pftrunc
Float→int through the adder pipe — a form no prior i860 emulator implemented. Killed an 8.3-million phantom-row loop.
-
IGC drain
Per-page completion is nonzero-on-done, and consumed pages reset their write index. Frames stopped saturating after ~1,400 draws.
-
-
- -
-
Landed - Firmware → render command stream, end to end
-
-
-

Verified working

-
    -
  • Cold boot of the capture's own firmware build on the emulated i860
  • -
  • Full recorded mission replays to completion — 26,422 commands
  • -
  • Scene graph, transform, frustum classify on real geometry
  • -
  • Real PXPL5 IGC opcode stream emitted and decoded (SEND / TILE / FLUSH)
  • -
  • Geometry binned into 191 screen regions
  • -
  • Object recovered and shaded — a 9×5 height-field surface, lit by the firmware's own normals (above)
  • -
  • Pixel-Planes array simulated (§05) — 64×128 tiles, per-pixel memory, edge trees + z-buffer, validated pixel-faithful
  • -
-
-
-

The last mile to pixels

-
    -
  • The array's computational model runs and matches the reference — the piece left is executing the board's own compiled micro-code
  • -
  • The per-region DMA command lists decode cleanly (§02) — SEND / SENDE / TXDN / TILE / GOTO, tile-relative
  • -
  • The SEND payloads carry real float coefficients in a regular bit-serial sweep — recoverable, not opaque
  • -
  • Coefficients verified to 0.2% against the geometry; for this frame, the object is the geometry (§05)
  • -
  • cap7 redraws this one object every frame — confirmed identical at cmd 735 and cmd 19,889, same 9 coordinates. A battle scene with terrain is a different capture entirely
  • -
-
-
-
- -
- VWE TESLA REL410 · firmware-decomp · emu860 - Tier 0 complete · Tier 1 array simulated · micro-code decode next -
-
- - +VelociRender — firmware render output + + + +
+
VWE TESLA · Division VelociRender · i860 firmware emulator
+

The board's own firmware
is rendering again

+

A cycle-faithful Intel i860 interpreter now runs the game's + actual shipped firmware — booted, initialised, and fed a complete recorded + mission over the wire. It replays every command, emits the real + PXPL5 IGC render stream, and projects the scene geometry. Below is an object + it drew, its vertices and normals pulled straight off the emulated chip and + reconstructed in 3D — geometry this board's firmware has not computed in thirty years.

+ +
+ reconstructed · firmware geometry + normals + +
the object cap7 was drawing — its 45 projected vertices resolve into a + complete 9×5 height-field surface, rebuilt here in true 3D and lit by the board's own + per-vertex normals. Pulled live off the emulated i860.
+
+ +
+ +
trace · i860 execution → IGC command DMA
+
+ +
+
26,422
wire commands replayed (whole mission)
+
8,562
draw_scene frames processed
+
191/192
screen regions binned with geometry
+
0
unimplemented ops remaining on the path
+
+ +
+

01 The render signal chain

+

Nothing here is re-interpreted by us. Each stage is the firmware's own + code executing on the emulated i860 — from parsing the wire packet to writing + the bit-serial micro-program the Pixel-Planes array runs.

+
+
in
Wire
dN_receive → 42-action dispatch
+
cpu
i860
transform · clip · classify
+
geom
Binitize
per-region 64×128 bins
+
out
IGC DMA
SEND / TILE / FLUSH stream
+
px
Pixel-Planes
array model simulated · §05
+
+
+ +
+

02 The output, decoded

+

The firmware DMAs the render to the card as an opcode stream + (DMAENGN.H). Both panels below are captured verbatim from the + emulator. Left: a real per-region command list — every region references the same + tile-relative payloads and differs only in its TILE id and the + GOTO link. Right: inside a SEND — the payload isn't opaque, it + interleaves control words with the actual float coefficients, swept bit-plane by + bit-plane into pixel memory.

+
+
+
+  region 0x0801fa40 · DMA list
+
# addr            opcode
+0x08015000  SEND(4)      ; edge coeffs
+0x00000000  FLUSH
+0x08015020  SENDE(0x45)  ; z / colour
+0x00000000  FLUSH
+0x08014100  TXDN
+0x08015260  SEND(0x21)
+0x08015380  SEND(0x29)
+0x00000020  TILE     ; tile id
+0x0801f008  GOTO     ; → next region
+
+
+
+  SENDE target 0x08015020 · payload
+
# bit-serial sweep (MEMpluseqMEM)
++000  00000100   ; header
++004  3a804834   ; = 9.79e-4  float
++008  8401213a
++00c  00000021   ; bit-plane 0x21
++010  ba01253a   ; = −4.93e-4  += A
++018  8381213a
++01c  00000022   ; bit-plane 0x22 …
+
+
+

Pull the floats out of those payloads and they + line up into clean ×2 chains — + 0.0079 · 0.016 · 0.032 · 0.063 · 0.126 · 0.252 · 0.504 · 1.009 — + a coefficient stored as its binary place values C·2ᵏ, one per + bit-plane, exactly how a bit-serial adder holds a number. And the recovered values are the + object's own geometry: a payload edge coefficient (0.12527) lands on + the edge normal computed from the captured vertices (0.12555) to + 0.2%. The plane constants sit alongside as fixed-point screen coordinates + (0x0000ec00 = 236.0, a vertex x). The coefficients feeding the array + simulator (§05) are the ones the hardware actually shipped.

+
+ +
+

03 Where the geometry landed

+

At the frame flush the firmware walks the screen-bin array and hands the + IGC one descriptor per 64×128 region. This grid is drawn from the real captured + descriptor scan — filled cells are regions that received transformed geometry. + A full mission view fills nearly the whole frame: ground plane and sky, exactly as expected.

+
+ +
+ region has geometry + empty region (shared page) + 96 × 2 descriptor grid · 191 of 192 filled +
+
+
+ +
+

04 How the death-camera saw it

+

The surface above is the same 45 vertices, sorted back into model space — + they form an exact 9 × 5 height-field grid (x and z in even 2-unit steps, y the + height at every node; all 45 cells filled). What the board actually wrote to screen is + below: cap7's death-camera views that surface nearly edge-on, so the frame the i860 + projected is a thin, folded sliver. It is authentic output — just an awkward angle. Left, + that projection Gouraud-shaded; right, its raw VSTRIP wireframe.

+
+
+ +
the board's screen-space frame — Gouraud-shaded, + grazing near-edge-on angle
+
+
+ +
raw VSTRIP wireframe — 4 strips, 45 vertices, + exactly as the i860 emitted them
+
+
+
+ +
+

05 The Pixel-Planes array, simulated

+

This is the final stage in silicon — and it now runs in software. The + PXPL5 IGC is a region rasteriser: the screen splits into + 64 × 128 tiles; every pixel carries a 26-byte bit-memory and an enable bit; all + pixels evaluate one linear tree in lockstep — + eval_ltree(x,y,A,B,C) = (int)(x·A + y·B + C). A triangle becomes + three edge trees into the enable register, then Z and R/G/B planes + interpolated per pixel and z-buffered in pixel memory (IGCOPS.C). + Fed the captured surface, the model lights the tiles below and renders pixels that match our + reference rasteriser to within edge anti-aliasing — the array reproduced faithfully.

+
+
+ +
the depth buffer, read straight out of pixel memory — the 24-bit + Z plane the SENDE z-sweep interpolates (near = bright)
+
+
+ +
the object's footprint — 18 of 50 64×128 tiles lit, + each a region of pixel processors
+
+
+
+
pixel memory · 26 bytes = 208 bits
+
+ Z · 24bR·8G·8 + B·8enable + working bits +
+
    +
  • three edge trees → the enable register (the inside test)
  • +
  • Z / R / G / B are planes, evaluated per pixel by the linear tree
  • +
  • z-buffer via MEM2geMEM2; every write gated by enable
  • +
  • the depth image (left) is that Z plane, read back out of pixel memory
  • +
  • validated pixel-faithful to the reference — ~1%, at edges only
  • +
+
+

What this is not, yet: a full from-scratch run of + the compiled micro-code the DMA ships (§02) — the form the geometry takes on the wire to the + card. But that stream is now largely decoded: the command lists read cleanly, + the SENDE z-sweep resolves into a regular 4-word instruction, and its + coefficients are the same ones driving this depth buffer — the array's inputs are + cross-validated against the hardware's own compiled stream. And scanning + all 14,223 payload writes of this draw, every screen coordinate lands in the object's own + range (x 66–236) — this death-cam frame carries no geometry beyond + the object; the rest is a background clear. So the array's render above isn't one primitive of + many: for this frame, it is the geometry.

+
+ +
+

06 The warp field — a Star Trek scene, recovered

+

The archive's trek capture — unreleased Star Trek + material — replays and draws after the dual-instruction-mode fix. Walking the + per-region DMA chains in the bin pages enumerated 898 compiled payload programs for + the frame: four are the standard end-of-frame pipeline (fog, texture, RGB — byte-identical + in every capture), and ~860 are the scene itself, per-primitive coefficient blocks + with their geometry sitting in plain screen-space floats. Plotted below: + 433 star positions and 389 streaks, radiating from a convergence point — the + warp-speed starfield, reconstructed from micro-code compiled by the board's own + firmware running on the emulated i860.

+
+ recovered from the frame's compiled payload programs + +
trek at warp — every point and streak is one primitive's + position read from its compiled coefficient block (fields +0x14/+0x18 and +0x24/+0x28, + plain IEEE floats in screen space).
+
+
+ +
+

07 What it took to get here

+

The i860 core was corrected against the toolchain's own assembler output + and MAME's validated i860 model. A selection of the load-bearing fixes:

+
+
store encoding
i860 stores keep the source in bits 15:11 and split the offset — every function return went to 0 until this was found. Prologues now save r1.
+
op 0x13 escape
lock / calli / unlock share one opcode; everything decoded as calli, so every spinlock jumped to address 0. The phantom "exit stub."
+
FP pipeline
Exact PFAM/PFMAM dual-ops, per-stage precision, fdest bypass. The Newton–Raphson divide now yields 16 ÷ 16 = 1 through the pipes, unhooked.
+
pipelined pftrunc
Float→int through the adder pipe — a form no prior i860 emulator implemented. Killed an 8.3-million phantom-row loop.
+
IGC drain
Per-page completion is nonzero-on-done, and consumed pages reset their write index. Frames stopped saturating after ~1,400 draws.
+
+
+ +
+
Landed + Firmware → render command stream, end to end
+
+
+

Verified working

+
    +
  • Cold boot of the capture's own firmware build on the emulated i860
  • +
  • Full recorded mission replays to completion — 26,422 commands
  • +
  • Scene graph, transform, frustum classify on real geometry
  • +
  • Real PXPL5 IGC opcode stream emitted and decoded (SEND / TILE / FLUSH)
  • +
  • Geometry binned into 191 screen regions
  • +
  • Object recovered and shaded — a 9×5 height-field surface, lit by the firmware's own normals (above)
  • +
  • Pixel-Planes array simulated (§05) — 64×128 tiles, per-pixel memory, edge trees + z-buffer, validated pixel-faithful
  • +
+
+
+

The last mile to pixels

+
    +
  • The array's computational model runs and matches the reference — the piece left is executing the board's own compiled micro-code
  • +
  • The per-region DMA command lists decode cleanly (§02) — SEND / SENDE / TXDN / TILE / GOTO, tile-relative
  • +
  • The SEND payloads carry real float coefficients in a regular bit-serial sweep — recoverable, not opaque
  • +
  • Coefficients verified to 0.2% against the geometry; for this frame, the object is the geometry (§05)
  • +
  • cap7 redraws this one object every frame — confirmed identical at cmd 735 and cmd 19,889, same 9 coordinates. A battle scene with terrain is a different capture entirely
  • +
+
+
+
+ +
+ VWE TESLA REL410 · firmware-decomp · emu860 + Tier 0 complete · Tier 1 array simulated · micro-code decode next +
+
+ +