Files
retroDE_ps2/docs/ch436_linear_scanout_prefit.md
thejayman77 ba74bbd5aa 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>
2026-07-20 19:56:46 -04:00

169 lines
8.2 KiB
Markdown

# Ch436 — vertical-linear authentic-display reconstruction prefit
## Root cause
The accepted Ch435 framebuffer is byte-identical between production RTL and
the DE25, and its mean RGB is already close to the PCSX2 frame. The remaining
high-frequency defect is also present in the independent software
reconstruction, so it is not a board-transfer or framebuffer-write error.
The Ch418 presentation path reduced the captured 512x448 display to the
board's 640x480 raster with nearest-neighbour selection:
- `source_x = floor(output_x * 4 / 5)`;
- `source_y = 32 + floor(output_y * 14 / 15)`.
That repeats source samples at both axes and exposes the already-granular base
scene more harshly than linear display reconstruction.
## RTL correction
`gs_lpddr_scanout_lb` now optionally uses the existing 15-state vertical
presentation phase as the exact interpolation numerator. It reads the
current and already-prefetched next row from the two alternating line buffers.
This adds no LPDDR traffic, line-buffer storage, or scheduler/render ordering
change.
The AXI prefetch side is notified of a source-row advance during horizontal
blanking. This gives it the full blank interval to refill the retired parity
buffer before the next active line requires the adjacent row. The directed
test explicitly models that interval and checks all 600 samples against the
same rounded separable equations as RTL, with zero errors or underflow.
Legacy profiles retain nearest/1:1 behavior through a default-off parameter.
Only the full-frame SH3 profile enables vertical linear reconstruction.
Horizontal presentation retains the proven Ch418 nearest mapper.
An initially simulated horizontal-linear extension duplicated the line-buffer
storage to obtain an `x+1` read port. Quartus implemented those mirrors as
30,720 registers instead of M20Ks, making the design require 6,270 LABs on a
4,680-LAB device. That architecture was removed completely before this
prefit candidate; none of the mirrored arrays or horizontal blend logic remain.
## Measured preview and regression evidence
On the accepted Ch435 board framebuffer, the exact RTL presentation model
improves the PCSX2 comparison from nearest MAE/RMSE `14.7226/22.3097` to
`14.2678/21.3085`. Mean RGB remains effectively unchanged at
`(26.38, 23.33, 21.19)`, so this is a spatial reconstruction improvement, not
a brightness retune.
Passing directed regressions:
- `tb_gs_lpddr_scanout_lb_hstretch`: 600 checked, zero errors, zero underflow;
- `tb_gs_lpddr_scanout_lb`: pass;
- `tb_gs_lpddr_scanout_lb_psm32`: 49,152 checked, zero errors/underflow;
- `tb_gs_lpddr_scanout_lb_psm32_256`: 196,608 checked, zero errors/underflow.
The framebuffer itself remains unchanged by construction, so the existing
Ch435 22-epoch native-FBMSK and 311-epoch full-scene scoreboards remain the
render-data acceptance baselines. The next owner GUI fit must establish RAM
cost and signoff timing before board deployment.
## First owner fit — resources recovered, narrow EMIF setup miss
The vertical-only candidate fit successfully and recovered the exact Ch435
memory/DSP budget: 5,327,792 block-memory bits, 344 / 358 RAM blocks, and
160 / 376 DSPs. The 25 MHz presentation domain was comfortably clean at
`+4.611 ns`; hold, recovery, removal, and minimum-pulse checks were also clean.
The RBF is not deployable because EMIF setup finished at `-0.086 ns`. The
actual post-fit top paths contained two unrelated 310 MHz routing families:
- the high-fanout synchronized EMIF calibration reset driving duplicated
texture-cache `drain_idx_q` payload registers (`-0.086 ns`);
- one request-FIFO `raddr_q` copy driving the complete 93-bit by 16K physical
RAM address network (`-0.073 ns` / `-0.062 ns`).
Neither path contains the vertical filter or its 25 MHz arithmetic. This is
therefore a structural timing repair, not a presentation rollback or another
placement-only reroll.
## First timing-repair fit — rejected RAM banking
The texture fill's selected word/index boundary is now control-free and
unreset. `F_WRITE` is reachable only after `F_DRAIN` has loaded both payload
registers, so their reset values were unobservable; removing reset eliminates
the EMIF calibration-reset launch family without changing fill ordering.
The first repair also split the production request memory into three explicit
31-bit by 16K banks. Although the logical storage remained 1,523,712 bits,
each bank rounded up to 25 physical M20Ks. The request memory therefore used
75 blocks instead of the packed macro's 59, raising the complete design from
344 to 360 / 358 blocks. Fitter correctly rejected it before routing. This
banked-memory architecture has been removed completely.
## Current zero-RAM-cost compile candidate
The request FIFO is back to its original single packed 93-bit by 16K memory,
restoring the proven 59-block request-macro shape and expected 344 / 358 total
RAM budget. Its existing unreset RAM-facing `raddr_q` now carries a
`maxfan=64` synthesis directive. Quartus therefore duplicates only the
address launch register as needed; the storage remains one efficiently packed
memory and the pointer/read latency are unchanged.
Verification after both cuts:
- asynchronous FIFO: 3,284 writes/reads exact, zero errors;
- texture cache: 64 words exact, refill error injection exact;
- Z/color emitter: 1,500 fragments across three epochs, zero errors;
- complete 311-epoch `zsrt139f52` production replay: 2,339,914 fragments fed,
2,286,292 passed Z, zero drops/overflows/AXI errors, final Z mismatch
`0 / 307,200`, final color mismatch `0 / 245,760`;
- framebuffer SHA-256 remains exactly
`d0047677371a0f6e4e319458926f604a8599c92baaf34d09b8e1fd452e31662b`,
byte-identical to both accepted Ch435 board dumps;
- relevant `git diff --check`: PASS.
This zero-RAM-cost RTL is ready for a new owner-controlled Quartus 26.1 GUI
compile. Acceptance requires all timing classes nonnegative, the request FIFO
to return to the 59-block packed macro / 344-block total design budget, and the
retired reset-to-`drain_idx_q` / high-fanout request-address families to be
absent. Do not deploy either prior Ch436 RBF.
## Accepted fit
The owner-controlled Quartus 26.1 GUI compile completed successfully on
2026-07-19. The packed request-memory shape and the complete Ch435 memory/DSP
budget were restored. All timing classes are nonnegative:
- EMIF setup WNS `+0.050 ns`, TNS `0.000 ns`;
- 25 MHz design setup WNS `+2.387 ns`, TNS `0.000 ns`;
- reference-clock setup WNS `+8.985 ns`, TNS `0.000 ns`;
- hold minimum `0.000 ns`, with zero TNS;
- recovery minimum `+1.054 ns`;
- removal minimum `+0.163 ns`;
- minimum-pulse-width minimum `+0.200 ns`.
Final resources are 38,522 / 46,800 ALMs (82%), 5,327,792 / 7,331,840
block-memory bits (73%), 344 / 358 RAM blocks (96%), and 160 / 376 DSPs
(43%). Quartus explicitly ignored the `maxfan` directive because every load
is a RAM address. The request-address family remains the clean EMIF limiter
at `+0.050 ns`; the reset-to-`drain_idx_q` family is absent. Closure therefore
comes from the valid reset cut and the resulting legal placement, not from a
claimed address-register duplication.
The accepted RBF is 4,100,096 bytes with SHA-256
`1c8945e3e8ad85d91a682aa7a068cee487a1459a7f2b899600b24ff7d9751294`.
## Hardware acceptance
The RBF checksum was verified on the DE25-Nano, the accepted Ch435 image was
preserved as `retroDE_ps2.pre_ch436.core.rbf`, and `core_loader.sh` loaded the
new artifact successfully with `fpga0: operating`. Live preflight passed:
- `CORE_ID=0x50533200`, ABI `0x00000100`, status `0x0000001f`;
- HDMI initialization complete and no I2C error;
- frame counter advanced from `0x0000117c` to `0x00001302`;
- raster-overflow count remained zero.
The complete 311-epoch `zsrt139f52` scene then passed every texture CRC,
runtime-palette sum, staged-record count, fresh-drain, and zero-fragment-drop
gate. The scheduler dumped all 307,200 framebuffer words and ended
`DONE rc=0`. Board SHA-256 is
`d0047677371a0f6e4e319458926f604a8599c92baaf34d09b8e1fd452e31662b`,
byte-identical to the complete production simulation and both accepted Ch435
board dumps. HDMI is live on the Ch436 vertical-linear presentation of that
accepted f52 framebuffer. Ch436 is timing-, simulation-, and
hardware-accepted.