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>
3.6 KiB
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_TOPelaborate cleanly under Icarus (unavailable vendor IP treated as black boxes); no RTL binding or syntax errors. git diff --checkand 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.