Files
retroDE_ps2/docs/ch438_binomial_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

5.5 KiB

Ch438 — source-space 3x3 binomial scanout (pre-fit)

Why this chapter

Ch437 proved exact horizontal and vertical linear presentation, but the complete f52 framebuffer still contains high-frequency speckle that the PCSX2 reference does not. Adding more draws does not address that deficit. An offline filter sweep identified a source-space separable [1 2 1]/4 low-pass followed by the authentic nearest presentation map as the best small, bounded scanout change.

The renderer and LPDDR framebuffer are unchanged. Ch438 only changes pixels at the final HDMI scanout boundary, so the accepted f52 framebuffer SHA remains the rollback and equivalence anchor.

RTL architecture

  • gs_lpddr_scanout_lb.sv adds opt-in BINOMIAL_3X3_FILTER.
  • SH3 full-frame scanout disables the Ch436/437 linear filters and enables the binomial filter.
  • A third rotating line buffer retains source rows y-1, y, and y+1.
  • Each physical line RAM still has one unconditional registered video read, the Quartus-safe inference form established in Ch437.
  • Six 256-bit register-cache slots retain the even/odd beats for all three rows.
  • Horizontal and vertical passes each compute (a + 2*b + c + 2) >> 2.
  • Horizontal edges clamp at source columns 0 and 511. Vertical edges clamp at source rows 32 and 479.
  • The filtered source pixel is presented with the captured nearest maps: sx=floor(x*4/5) and sy=32+floor(y*14/15).
  • The AXI prefetcher still stays one source row ahead; its physical write target now rotates 0/1/2 rather than alternating 0/1.

Expected fit delta from the accepted Ch437 build is one 640-pixel physical RAM bank (approximately five M20Ks in the established 256-bit implementation), two additional 256-bit beat-cache registers, and small shift/add logic. Ch437 used 344/358 RAM blocks, so the expected result is about 349/358.

Exact preview result

Input framebuffer:

  • captures/gs/silenthill3/extracted/sh3_zsrt139f52_ch435_board.png
  • Its underlying f52 board dump is byte-identical to the accepted Ch436/437 framebuffer (d0047677371a0f6e4e319458926f604a8599c92baaf34d09b8e1fd452e31662b).

Reference: captures/gs/silenthill3/pcsx2_ref_224139.png.

Scanout MAE RMSE
Ch437 separable linear 13.9525 20.6568
Ch438 3x3 binomial + nearest 13.1111 19.1051

Preview: captures/gs/silenthill3/extracted/recon/sh3_zsrt139f52_ch438_binomial_preview.png

Preview SHA-256: 5a0402c523b64e252746067488177b08f0d23ab8a4a7dc09857e914c07f269f1

The preview is generated by tools/preview_scanout_ch438.py, which reproduces the RTL's rounding after each separable pass.

Pre-fit verification

  • make -C sim tb_gs_lpddr_scanout_lb_binomial
    • 2,400/2,400 output pixels exact
    • zero underflow
    • zero read errors
  • make -C sim tb_gs_lpddr_scanout_lb_hstretch
    • Ch437 compatibility: 2,400/2,400 exact
    • zero underflow/read errors
  • make -C sim tb_gs_lpddr_scanout_lb
    • legacy scanout PASS under its established one-pixel-per-line simulation alignment allowance
    • zero underflow/read errors
  • Targeted Verilator lint of the binomial parameterization: no errors, latches, multidriven signals, combinational loops, or range errors.
  • Repository git diff --check: clean.

The repository-wide make lint still stops at the pre-existing unsupported default-valued rewind_i input in sif_dma_ee_ram_bridge_stub.sv; the targeted scanout lint is clean and this unrelated baseline issue was not changed.

Owner fit gate

Ready for a fresh Quartus 26.1 GUI compile. Accept only if:

  1. fit succeeds;
  2. all setup/hold/recovery/removal/pulse-width checks are clean;
  3. RAM use remains at or below 358 blocks;
  4. all three scanline arrays infer as RAM rather than register banks.

First fit and timing-root correction

The first Ch438 GUI fit completed successfully and confirmed the scanout resource projection:

  • 38,904 ALMs
  • 57,173 registers
  • 349/358 RAM blocks
  • 160 DSP blocks

All non-setup checks were clean, but EMIF setup failed at -0.120 ns, TNS -3.122, across 64 endpoints. The actual top-ten family was unrelated to the new filter datapath:

  • launch: u_zc_emit|u_req|raddr_q[6]
  • capture: the deep request FIFO's packed mem_rtl_0 port-B address banks
  • launch-register fanout: 744
  • data path: one 2.886 ns route, zero logic levels

This is the established 93-bit x 16K request-FIFO physical-address family. The additional scanout RAM changed placement enough to expose it again.

The correction keeps the full 16K request depth and banks only the payload into two independently inferred RAM arrays. Each half has a separate preserved registered read address, reducing the single 744-load launch net to two roughly half-sized physical trees. FIFO order, pointer CDC, and registered-read latency are unchanged. The banked form is enabled only on u_zc_emit.u_req; all other gs_async_fifo users retain the monolithic default.

Post-cut verification:

  • default async FIFO stress: 3,285 writes/reads, zero errors;
  • monolithic registered-read stress: 3,285 writes/reads, zero errors;
  • banked registered-read stress: 3,285 writes/reads, zero errors;
  • full f52 production Verilator replay:
    • 311 epochs;
    • 2,339,914 fragments fed;
    • 2,286,292 passed;
    • zero drops, color overflow, BRESP errors, Z mismatches, or color mismatches;
    • PASS;
  • post-cut framebuffer SHA-256: d0047677371a0f6e4e319458926f604a8599c92baaf34d09b8e1fd452e31662b, byte-identical to the accepted Ch437 board framebuffer.

The first timing-red RBF (7fa4724f...) was not deployed. A fresh GUI compile is required for the banked-address correction.