Walking the bin-page DMA chains enumerated 898 SEND payload programs per frame:
4 = the standard end-of-frame pipeline; ~860 = the scene's per-primitive
coefficient blocks at 0x815f000+, far beyond the old dump window. Their
geometry sits in plain screen-space IEEE floats (+0x14/+0x18 and +0x24/+0x28):
433 star positions + 389 streaks radiating from a convergence point = the
Star Trek warp-speed starfield, reconstructed from micro-code compiled by the
original firmware on the emulated i860. Readout §06 now renders the warp field
from the embedded position/segment data. Tools: dumpcontent.py (payload-region
dump), content_frame.py (chain walk + payload parse + reconstruction).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cross-checks against the vendor source settle the semantics: the 0x3xx words
are pixel-memory bit addresses / opcode fields (EOF.S emits them as hardcoded
constants; DIVPXMAP.H maps dvpx_* bit addresses 0-207 incl. eofr/g/b at
184/192/200), 0xec00 is a hardcoded control constant (EOF.S:2313), and the
whole 2,541-word payload set is 98.98% identical between trek and klngvid =
the standard screen program shared across captures. §06 now presents the
render as an emit-stream structural map with the demo-specific geometry still
to be located (beyond the 0x8014000-0x8018000 window; bin pages / far heap are
the candidates). The EOF.S<->EOF.C correlation method for the exact per-macro
decode is proven (send_em catalog: 30 emit sites with inline constants).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
trekframe.py parses the captured payload blocks (0x100 headers, rowid words
0x300|row, packed edge fields) into per-scanline spans and composites them onto
an 832x512 canvas -- 21 blocks / 124 spans from the trek demo's compiled stream:
distinct multi-colored objects + slanted band elements. dumppay.py dumps the
payload region at chosen draws (scene verified byte-identical draws 1-300 =
compile-once static showcase). Readout gains §06 with the frame rendered from
the span data. First-approximation decode (edge-field scaling still being
pinned) -- but every mark is a span the firmware's rasteriser emitted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
payload_scan_mid.py scans a mid-mission frame (snapfull1, cmd 19,889): identical
9 coordinates as cmd 735 (65.5/72/181/236, all x[66,236]). So cap7 redraws the
same static surface patch every frame across its whole length -- no terrain, no
battle, ever. Corrects the earlier "mid-mission frames have battle scenes" guess:
a full battle scene lives in a different capture entirely. Readout last-mile
updated. The decode + array render fully account for cap7's content.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
payload_scan.py scans all writes into the payload region across the draw: 14,223
writes, every recoverable screen coordinate in x[66,236] = the object's range,
nothing near 0/400/832. So this death-cam frame carries no geometry beyond the
object -- the ~64 triangles account for essentially all payload writes; the rest
is a background clear. The "ground and sky still to render" was a wrong premise
for THIS frame: the array's object render IS this frame's geometry. Wider battle
scenes with terrain live in mid-mission frames (a separate capture). Readout §05
+ last-mile updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
frame_primitives.py decodes every coeff-copy word over the draw: 1051 SEND,
334 SENDE, 384 TILE, 327 GOTO, 231 STOP across 105 tiles -- but only 2 distinct
SEND payload addresses (0x08015xxx/0x08017xxx). That's double-buffering: the
firmware compiles each primitive into an alternating coeff block and SENDs it,
so the content changes over time while the addresses don't. A from-scratch full
frame must snapshot each primitive's payload at its SEND, then run all of them.
Readout §05 + notes updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
edge_decode.py: the edge payloads' non-float words carry the plane constant/
vertex terms as .8 fixed-point screen coordinates (0x0000ec00 = 60416 = 236.0,
a screen-x in the object's range), not IEEE floats -- which is why they weren't
in the float list. Locates the last missing piece for edge reconstruction:
A/B slope (float, verified 0.2%) + C (fixed-point coord). Readout §02 notes it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
edge_verify.py: the edge SEND payload float 0.12527 matches the object's own
screen-space edge normal (0.12555, computed from the captured vertices) to
0.2%, and 0.1262 to 0.5%. Edges are pure screen geometry (no z-scale ambiguity),
so this is a hard confirmation that the compiled micro-code carries the real
coefficients. Readout §02 states the 0.2% match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
igc_array.py gains readout_depth() -> the 24-bit Z stored in pixel memory as a
depth image (near=bright), i.e. the plane the decoded SENDE z-sweep interpolates.
Readout §05 now shows the depth buffer next to the tile footprint, ties the
z-decode to a visible array output, and reframes the "remaining work" as numeric
reconstruction across regions (the coefficients are already cross-validated).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The payload floats group into clean x2 doubling chains (0.0079 0.016 0.032 ...
1.009) = a coefficient stored as its binary place values C*2^k across the
bit-planes, exactly how a bit-serial adder holds a number. Recovered base
coefficients correlate with the object's own screen-space edge/z slopes
(decode_corr.py, chain_decode.py), so igc_array.py's inputs are cross-validated
against the compiled stream. Fixed-point scales from FOOTER.SS (Czscale=2^20,
Ctexscale=2^16). Readout §02 + decode notes updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
§02 now shows the actual per-region DMA command list captured from the emulator
(region 0x0801fa40: SEND/SENDE/TXDN/TILE/GOTO) and the real SENDE payload with
its embedded float coefficients (bit-serial MEMpluseqMEM sweep). §05 + the
last-mile list updated: the micro-code is partly decoded (lists clean, payloads
carry recoverable floats), remaining work is the control-word field split.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signal-chain Pixel-Planes stage flips to "simulated"; new section shows the
64x128 tile footprint the array lit for the object (18/50), the 26-byte
pixel-memory bit layout (Z24 + RGB), and states the validation + the honest
remaining gap (the compiled micro-code binary, still undecoded, that carries
the ground/sky).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The 45 VSTRIP vertices captured off the i860 sort back into an exact 9x5
model-space grid (x,z in even 2-unit steps, y = height at every node; all
45 cells filled). cap7's death-camera views it nearly edge-on, which is why
the raw screen projection looks like a folded sliver. gridsurf.py rebuilds
the true grid connectivity (2 tris/quad) and shades it from the firmware's
own per-vertex normals -> a clean solid surface. render-readout.html now
leads with that true-3D reconstruction and shows the grazing projection +
wireframe as "how the death-camera saw it".
Also resolved a long-standing red herring: the (1,1,10,10) extent bounds
that earlier sessions chased as the "empty-bins bug" appear identically in
the working frame -- they're the per-frame marker rect, not the geometry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Captures the object cap7's death-camera view draws (4 VSTRIP strips, 45
verts) with its per-vertex normals straight off the emulated i860, and
shades it in software with a barycentric z-buffered fill (shade_render.py).
This is our rasteriser showing the firmware's geometry lit by the firmware's
own normals -- not the board's bit-serial Pixel-Planes array (that stays the
Tier-1 build). cap7-geometry.json is the portable capture; render-readout.html
is the published readout with the shaded frame as its hero.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>