Per-vertex GS fog end-to-end (gs_stub emit incl. persp_emit5, gs_prim_list_feeder XYZ2->XYZF2 on PRIM.FGE, gs_make_sh3_scheduler_fixture.py F/FGE packing), new fog TBs, fidelity attribution tooling. Functional baseline before removing the dead bilinear lerp8 clamps (Codex: 161-node comb loop -> -0.042ns setup fail). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.5 KiB
Ch417 — native 12.4 attribute gradients
Objective
Close the main fidelity debt left by Ch416: coverage already samples native 12.4 GS screen coordinates at pixel centers, but color, Z, UV, and STQ planes were still solved from integer vertex coordinates. This chapter makes the attribute setup and evaluation use the same native geometry as coverage while leaving draw population, texture state, blending, fog, and ordering unchanged.
RTL cut
- Triangle orientation and the post-swap gradient determinant now use the full 12.4 vertex coordinates. Coordinate deltas are signed 17-bit values and the determinant is signed 35-bit.
- The shared gradient numerators are signed 64-bit. Because the determinant is in sixteenths-of-a-pixel squared, the numerator is shifted by 20 rather than 16 to produce the existing Q16.16 per-pixel gradient.
- The gradient FIFO sideband retains the full 35-bit determinant through the time-shared setup engine and its single sequential divider.
- Color, Z, affine UV, and perspective STQ evaluation now use the native
pixel-center offset
((pixel << 4) + 8) - vertex12.4. Products are shifted by 20 to return to the existing attribute domains. - Affine UV filtering consumes the resulting Q16.16 fractional texel bits. This keeps bilinear sampling aligned with the corrected attribute plane.
Two correctness defects exposed by the new directed tests were repaired in the same path:
- The packed attribute-prefetch word was missing the LPDDR ABE bit in its
unpack destination. Every following field was consequently displaced by
one bit, including the vertex-coordinate context. The unpack now includes
gw_d_lpddr_abeand exactly matches the stored word width. - The opaque affine fragment-Z output retained the reset value instead of the
interpolated triangle Z. The emit sideband now selects
s2_interp_zfor an active affine triangle and retains the flat sprite value otherwise.
Directed evidence
- Legacy raster regression: 16/16 pixels PASS.
- New native-gradient triangle at
(0.75,0.75),(3.75,0.75), and(0.75,3.75): exact R values 72/104/136 and exact Z values 1225/1325/1425 at the three covered pixel centers. - Triangle interpolation regression: 31 interior color samples within the established tolerance and 62 exact Z checks, PASS.
- Shared gradient divider regression: PASS.
- Affine textured triangle: 31/31 UV texels exact, PASS.
- Perspective PSMCT32 demo: 96/96 samples exact, PASS.
- Combined texture/alpha/Z demo: PASS.
- PSMT8 runtime-CLUT triangle: affine, perspective, ABE, and MODULATE paths PASS.
- Authentic three-epoch integration: 5,909 fragments fed, 5,909 Z-passing, zero drops, 0/307,200 final Z mismatches, and 0/5,858 color mismatches. The corrected affine Z sideband admits two fragments that Ch416 rejected.
Full-scene simulation gate
The 263-epoch scene uses the same bit-exact divide arithmetic as production.
SH3_FAST_GRAD selects a one-cycle setup path for quick framebuffer iteration;
the final pre-fit gate uses SH3_BOARD_GRAD, the production combinational
divider and its five-cycle registered settle window. The widened 64/35-bit
divide therefore has a 200 ns functional and STA contract at 25 MHz. The
sequential-divider implementation also passes its focused regression.
The full chronological gate passes:
- 1,145,412 fragments fed and 971,347 Z-passing;
- zero fragment drops, request-FIFO high-water mark 1, no color overflow, and no AXI response errors;
- 263 markers and 263 ordered read drains (the first drain begins from the reset frame, hence 262 frame-count advances);
- 0/307,200 final Z mismatches and 0/235,951 written-color mismatches.
The dedicated production-control rerun also passes all 263 epochs with
GRAD_SEQ_DIVIDER=0 and GRAD_DIV_CYCLES=5: the same 1,145,412 fed /
971,347 passing fragments, zero drops, request-FIFO high-water 1, all 263
ordered drains, and exact final Z/color. Its framebuffer is byte-identical to
the fast arithmetic run (3d22b442...), proving that the five-cycle settle FSM
changes latency only.
The focused production board-path regression was corrected in Ch417: its old
GRAD_BOARDPATH branch accidentally selected the sequential divider. It now
selects the actual board combinational divider at five cycles and passes all
252/252 interior perspective samples with zero errors. The directed subpixel
gradient test also runs at five cycles and passes exact R/Z checks; its timeout
is derived from the 14-step gradient setup latency rather than a fixed delay.
The first owner Analysis & Synthesis attempt exposed a Quartus-specific width
limit before fitting: signed 64/64 inference prepended a sign-magnitude bit
and requested unsupported LPM_WIDTHN=65 (Error 272006). Ch417b now divides
an explicitly unsigned 64-bit numerator magnitude by the native unsigned
35-bit determinant magnitude and restores the quotient sign afterward. This
retains signed truncation-toward-zero exactly while fixing the inferred LPM at
64/35. All focused gates and the complete 263-epoch production-control gate
were rerun after this change; the framebuffer remains byte-identical at
3d22b442....
The compiled Verilator run completed the full gate. The original Icarus run independently matched every count through epoch 59 before it was retired after the faster run passed, including the first Z-rejecting epochs. The two engines therefore agree across both the all-pass prefix and mixed pass/reject behavior.
The Ch417 framebuffer improves against the bilinearly resized PCSX2 reference from Ch416 MAE 20.4941 / RMSE 30.0163 to MAE 20.1177 / RMSE 29.4268. Lit RGB pixels rise from 199,104 to 199,827. Ch417 versus Ch416 measures MAE 2.9100 / RMSE 9.4742, with 135,574 pixels unchanged exactly.
Artifact SHA-256 identities:
- Ch417 RTL framebuffer MEM:
3d22b4421194d444677f3bc9f938e43fd856c6615b92585a10209093d982a625; - Ch417 RTL framebuffer PNG:
b55b411cc5f6679e6a1ed708ef21ad5eaf5750abb233c6e433ab03594ec9c01e.
Owner fit gate
The owner-controlled Quartus 26.1 GUI flow completed successfully at
2026-07-18 07:21 EDT. Synthesis confirms that the repaired divider is exactly
the intended unsigned LPM_WIDTHN=64, LPM_WIDTHD=35, with no pipeline
inserted. Final STA attached the Ch417 setup=5/hold=4 destination constraint
to 49 routed grad_result_q registers (including retimed internal divider
launches), giving the widened cone its 200 ns functional contract.
Final signoff is clean:
- setup +0.140 ns;
- hold 0.000 ns;
- recovery +0.998 ns;
- removal +0.143 ns;
- minimum pulse width +0.200 ns.
The fit uses 38,461 / 46,800 ALMs (82%), 5,261,744 / 7,331,840 memory bits
(72%), 336 / 358 RAM blocks (94%), and 160 / 376 DSP blocks (43%). The split
RBF SHA-256 is
ef0ecc585b6e0506f30f56bbea44ba56023a305e9d22052877b0e51b1b65e643.
Board acceptance
The timing-clean RBF was installed and loaded on the Terasic board; the FPGA
manager reported operating before and after the run. The previous installed
image was preserved remotely as retroDE_ps2.pre_ch417b.core.rbf.
The live 263-epoch scheduler completed with rc=0. Every texture CRC,
runtime-palette sum, staging-record count, ordered drain, AXI response, and
fragment-drop gate passed. The final capture contains 307,200 words, sum32
0xc552c256, xor32 0x90a0ec16, 235,280 nonzero words, and bounds
(0,0)..(511,479).
Most importantly, the board framebuffer, fast RTL framebuffer, and complete
five-cycle production-control framebuffer are byte-for-byte identical. All
three have SHA-256
3d22b4421194d444677f3bc9f938e43fd856c6615b92585a10209093d982a625.
Ch417 is therefore accepted in hardware.