Files
retroDE_ps2/docs/ch422_registered_bilinear_output_prefit.md
T
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

3.6 KiB

Ch422 — registered bilinear output boundary (prefit)

Trigger

Ch421 closed the 310 MHz EMIF/request family at +0.155 ns, but its owner GUI fit exposed a design-clock path from a captured bilinear tap through both lerp levels, the texture output mux, TEX0 vertex modulation, and finally raster_pixel_color_q. The worst of ten identical-family paths had 30 logic levels, 41.955 ns data delay, and -1.993 ns slack against the 40 ns clock.

Root cause

gs_texture_unit already captured tex_color_blend into tex_color_hold while leaving BS_DONE. However, during that same BS_DONE cycle its external tex_color selected the live combinational blend and out_valid asserted. Consequently, the perspective palette-bilinear emit path could consume the unregistered value and append four channel-modulation multipliers before the raster_pixel_color_q register. The intended hold register was present but was bypassed at the only cycle that mattered for this caller.

Structural cut

The bilinear FSM now has a distinct BS_OUT state after BS_DONE:

  1. BS_DONE evaluates the unchanged two-stage bilinear math and captures it in tex_color_hold;
  2. BS_OUT asserts out_valid and exposes only tex_color_hold;
  3. the FSM then returns to BS_IDLE.

This adds one internal sampler cycle but changes no pixel arithmetic and no external handshake. Existing consumers already wait on out_valid or the busy level, so their natural stalls absorb the cycle. The former 30-level tap-to-emit path is split at tex_color_hold: bilinear arithmetic ends there, while TEX0 modulation starts from a register on the following cycle.

Prefit verification

  • standalone PSMCT32/PSMT8/PSMT4 bilinear suite: all 12 cases PASS;
  • tile PSMCT32 bilinear integration: PASS;
  • tile palette-bilinear integration: PASS;
  • full 283-epoch production-control replay: PASS;
  • 1,177,489 fragments fed, 984,845 passed Z, zero drops/errors;
  • final Z mismatch 0 / 307,200, color mismatch 0 / 235,963;
  • framebuffer SHA-256 remains exactly a88f1f6c926dd0db2b72ae2873c399e7dc5666f8003190184c34d360b13a5f44.

Owner fit gate

Ready for one owner-controlled Quartus 26.1 GUI compile. Acceptance requires:

  • no g_bilinear.tap[*] -> raster_pixel_color_q[*] setup family;
  • bilinear tap paths terminate at tex_color_hold and close at 25 MHz;
  • the already-clean 310 MHz EMIF/request family remains non-negative;
  • setup, hold, recovery, removal, and minimum pulse all close;
  • RAM inference and device fit remain within the existing budget.

Do not deploy the timing-unclean Ch421 RBF. Deploy and board-test Ch422 only if the complete timing report is clean.

Owner fit result

The owner-controlled Quartus 26.1 GUI fit confirmed that the Ch422 structural cut worked. The design clock closed at +8.604 ns, the reference clock closed at +7.564 ns, and hold, recovery, removal, and minimum-pulse checks were clean. The former bilinear tap-to-raster_pixel_color_q family was absent.

The only remaining failure was the 310 MHz EMIF clock at WNS -0.012 ns, TNS -0.047 ns, across six endpoints. Five endpoints were color-align tuple data register enables (ca_wdata_q[21/24/25/28/30]|ena) reached through ca_tail -> ca_full -> feed_ok. The sixth was req_stage_packet[79]|ena, whose enable cone included the synchronized EMIF calibration reset. These are independent control-to-data-enable artifacts; Ch423 removes both in one combined structural closeout.

Ch422 is therefore functionally verified and its intended timing family is closed, but its RBF remains non-deployable because the complete fit was not timing-clean.