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:
2026-07-20 19:56:46 -04:00
parent ec82764bef
commit ba74bbd5aa
476 changed files with 696247 additions and 130119 deletions
@@ -0,0 +1,81 @@
# Ch420 — request FIFO dedicated read-address stage (prefit)
## Trigger
Ch419 removed both intended timing families and reduced setup from
`-0.388 ns / -7.218 ns` to `-0.115 ns / -1.150 ns`. Its completed fit exposed
one uniform remaining family: request FIFO `rbin[6]` directly driving the wide
banked RAM's `portbaddr[6]` network.
This is not a new functional cone and not a reason to reroll placement. The
paths have zero logic levels, fan-out 713, and spend `2.892 ns` of `3.192 ns`
in one interconnect route.
## Structural cut
Registered-read mode in `gs_async_fifo` now has a dedicated RAM-facing
`raddr_q` stage, marked `dont_merge, preserve` so it cannot collapse back into
the binary CDC pointer.
`raddr_q` captures `rbin_nxt` while the synchronous RAM reads the prior
`raddr_q`. Before each edge, `raddr_q` equals the current head address, so the
returned entry and accepted-pop latency are unchanged for isolated and
back-to-back reads. The added boundary only separates pointer/empty logic from
the physical address fan-out and gives the fitter a placeable/duplicable RAM-
local launch register.
The stage intentionally has no reset or clock enable. The FIFO remains empty
for multiple read clocks while the write pointer crosses its two synchronizer
flops, so the address has settled to zero before any legal pop. Avoiding reset
and enable prevents recreating the prior high-fanout RAM-control failures.
## Prefit verification
- async FIFO randomized CDC test: 3,284 writes and reads exact, no duplicate or
drop;
- Z/color emit: 1,500 fragments across three epochs exact, including directed
`ZTST=ALWAYS`;
- concurrent scanout/reload/probe: 16,384 pixels exact;
- 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` and color mismatch `0 / 235,963`;
- framebuffer SHA-256 remains exactly
`a88f1f6c926dd0db2b72ae2873c399e7dc5666f8003190184c34d360b13a5f44`;
- relevant `git diff --check`: PASS.
## Owner fit gate
Ready for one owner-controlled Quartus 26.1 GUI compile. Acceptance requires:
- the direct `rbin -> request RAM portbaddr` family is absent, not merely
exchanged for an equally long `rbin -> raddr_q` or `raddr_q -> portbaddr`
family;
- setup, hold, recovery, removal, and minimum pulse all close;
- request FIFO RAM inference and the 336 / 358 RAM-block budget remain intact.
Do not deploy the RBF until this report is clean. After timing acceptance, run
the already-staged Ch419 283-epoch board scene and require exact equality with
the production framebuffer hash above.
## Owner fit result — 2026-07-18 11:59
The fitter preserved `raddr_q`, and the direct `rbin -> portbaddr` family is
absent from the violated paths. Setup did not close:
- WNS `-0.273 ns`, TNS `-1.613 ns`;
- hold `0.000 ns`; all other timing checks clean;
- 38,227 ALMs and 336 / 358 RAM blocks.
The ten reported violations are the next request boundary, not either half of
the new address stage. They launch at the request RAM output and terminate at
the two packet-type validity registers:
```
u_zc_emit|u_req|mem...portbdataout
-> req_stage_frag_valid / req_stage_marker_valid
```
The worst path is `3.443 ns`, with the RAM output `uTco` accounting for
`1.396 ns` and three downstream decode/routing levels accounting for the rest.
Ch421 removes packet contents from stage-occupancy control and captures the
complete packet across one explicit boundary.