frame_geometry.py snapshots each SEND payload (deduped by content) and pulls
fixed-point screen coords. Honest outcome: only 11 sparse coords, all in the
object's x-range, no terrain -- the payloads store compiled edge/plane
coefficients, not extractable vertex lists, so "grep coords and plot" is a dead
end. A real from-scratch render needs the full plane-role assembly (slopes +
constants -> lines -> triangles -> array), which stays unsolved. Documented in
MICROCODE-DECODE-NOTES.md so the shortcut isn't retried.
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>
Full SENDE dump (ctrl_split.py) resolves into a regular 4-word instruction, one
per bit-plane: word0 = constant increment float, word1 = [length countdown,
source bit-addr] with op field 0x3a, word2 = the coefficient's place-value (the
x2 chain, -1.009..-0.00788), word3 = destination bit-plane (0x21..0x31 = a
17-bit fixed-point z/color). A MEMpluseqMEM bit-serial accumulation. SEND edge
payloads use the same value encoding with a different (header + 3-word group)
framing. Control-word split for the z/color path is now decoded; from-scratch
render still needs numeric reconstruction + plane mapping + the C term.
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>
The coefficient-copy (0xf0411cd4) writes per-region DMA command lists; captured
from the cap7 death-cam they decode cleanly against DMAENGN.H ({addr,opcode}
pairs, SEND/SENDE/TXDN/TILE/GOTO/FLUSH). Every region references the same
tile-relative payloads and differs only in TILE(id) + the GOTO link.
Dumping the SEND payloads shows they are NOT opaque: they interleave control
words with embedded IEEE floats = the edge/plane/colour coefficients, loaded as
a bit-serial MEMpluseqMEM sweep (regular 4-word instruction: increment float +
length/bit-address control + dest plane). So the micro-code decode is now
extraction + bit-serial execution, not blind ISA reversing -- the remaining
blocker is the control-word field split (igc_opco.h is not in the dump).
Full findings + next steps in MICROCODE-DECODE-NOTES.md; probes coefdump.py
(DMA lists) + payload_dump.py (payload floats), restore from snapv2.pkl.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>