Snapshot: fog implementation + fidelity tooling baseline (pre bilinear-clamp fix)

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>
This commit is contained in:
2026-07-20 19:56:46 -04:00
parent ec82764bef
commit ba74bbd5aa
476 changed files with 696247 additions and 130119 deletions
@@ -0,0 +1,85 @@
# Ch418 — authentic SH3 display presentation mapping (prefit)
## Objective
Fix the large presentation mismatch between the accepted Ch417 framebuffer and
the PCSX2 224139 frame without changing any rasterized framebuffer byte. Ch418
is scanout-only: it maps the captured GS display source onto the board's
640x480 HDMI/VGA active raster.
## Captured register evidence
The vendored PCSX2 `GSPrivRegSet` layout was used to decode the initial and all
eight per-vsync register snapshots in dump 224139. The active context is
DISPLAY2 (`PMODE.EN2=1`), stable in every snapshot:
- `DISPFB2 = 0x0001000000009000` (FBP rotates later), `FBW=8`, `PSM=1`,
`DBX=0`, `DBY=32`;
- `DISPLAY2 = 0x0037f9ff0203228c`, `DX=652`, `DY=50`, `MAGH=4`,
`MAGV=0`, `DW=2559`, `DH=895`.
Therefore the display source is 512 pixels wide (`FBW*64`) and 448 interlaced
source lines beginning at framebuffer line 32. DISPLAY2 expands each source
pixel to five VCKs (`MAGH+1`) across 2560 display clocks. Reducing that
captured display to the board raster gives the exact integer maps:
```
source_x = floor(output_x * 4 / 5) // 0..639 -> 0..511
source_y = 32 + floor(output_y * 14 / 15) // 0..479 -> 32..479
```
## RTL change
`gs_lpddr_scanout_lb` now has opt-in divider-free presentation mapping:
- a five-state horizontal phase accumulator implements 512 -> 640;
- a fifteen-state vertical phase accumulator implements 448 -> 480;
- vertical prefetch starts at captured `DBY=32`;
- buffer parity, prefetch throttling, and underflow checks use mapped source y;
- all default parameters retain the legacy 1:1 behavior.
Only `GS_SH3_LPDDR_FB_640` enables the mapping in the DE25 top. The OSD remains
in the 640x480 output domain and the LPDDR framebuffer/dump remains byte-exact
to Ch417.
The mapper contains no `/` or variable multiply in synthesizable RTL. Its
datapath is one small phase decrement and one coordinate increment per output
pixel/line, both in the 25 MHz video domain.
## Prefit verification
- New two-axis scanout oracle: 600/600 RGB pixels exact, including horizontal
repeats, vertical repeats, DBY offset, alternating line buffers, zero
underflow, and zero AXI read errors.
- Legacy PSMCT16 line-buffer regression: PASS, underflow=0, read errors=0.
- Legacy PSMCT32 line-buffer/concurrency regression: 49,152 pixels exact,
underflow=0, read errors=0, 325/325 probes good.
- The actual QSF profile macros plus `USE_QSYS_TOP` elaborate cleanly under
Icarus (unavailable vendor IP treated as black boxes); no RTL binding or
syntax errors.
- `git diff --check` and the preview utility's Python compile pass.
Expected HDMI preview:
`sim/data/top_psmct32_raster_demo/sh3_zsrt139f17_ch418_scanout.png`
Preview SHA-256:
`b710aa7a09db6992faacdaa5a6257d490f1d4fa0112f6c6d20fc388f4b580a63`
The preview moves the already-rendered lamppost and character onto the PCSX2
landmark positions. Full-frame RGB MAE rises from 20.12 to 21.02 because the
board is still missing large bright/background draws that the transform now
spreads over more output pixels; that global statistic is a coverage metric at
this stage, not an alignment metric. The mapping is justified by the captured
registers and visible landmark alignment, not by claiming a false MAE win.
## Owner fit gate
Ready for the owner-controlled Quartus 26.1 GUI compile. Required acceptance:
- Analysis & Synthesis succeeds with no inferred display divider;
- setup, hold, recovery, removal, and minimum pulse all close;
- after deployment, the unchanged 263-epoch board run still passes and the
framebuffer dump remains byte-identical to Ch417;
- HDMI shows the 512x448 captured source presented across 640x480.