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:
@@ -0,0 +1,168 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user