Ch443f: coherent Gray readiness CDC + qualified scanout underflow detector

Harden the LPDDR scanout underflow diagnostic (Codex direction). Keeps the
Ch443e 4-buffer + lead-2 fix; adds no 5th buffer.

RTL (gs_lpddr_scanout_lb):
- Replace the raw-binary next_fetch readiness sync with a reset-aware GRAY
  code. next_fetch is monotonic between frames, so one Gray bit changes per
  increment; the 2-FF-synced + decoded nf_v is always a real prior frontier
  (monotone, burst-safe), never a torn multi-bit combination. (A plain
  toggle-per-change handshake dropped bursts when two increments landed in one
  sync window; that is why the earlier attempt under-read nf_v and false-tripped.)
  fs_edge_v overrides the lone multi-bit reset transient.
- Qualify the underflow: only a miss persisting >= QUAL_CYCLES (4) sets sticky
  underflow. uf_pmax_q records the longest streak and uf_qual_q whether any
  qualified, so a host can distinguish a 1-cycle CDC lag from a real late row.
- Atomic snapshot: scan_y/nf_v/pmax/causes/vphase/line_valid all latched the
  same video cycle on the first qualified miss.

ABI: 0x120 adds [15:12]=live pmax (2-FF synced via scan_diag_pmax_i). 0x124
[29:20] now carries pmax-at-capture (was nf_s0). Bridge dst reg kept 10-bit.

SDC: scanout diag bundle source count 37 -> 31 (nf_s0[10] -> pmax[4]); new
async-in cut + max_skew/net_delay for the next_fetch Gray CDC; stage-0 cut for
the live pmax sync.

Tests: new tb_gs_scanout_cdc_qual (async-clock focused: no false event from the
readiness transition or ordinary sync latency; sub-QUAL transient does not
qualify; genuine late row qualifies with a self-consistent atomic snapshot;
frame reset + mod-4 reuse re-arm the detector). tb_gs_scanout_diag updated for
the pmax field. Tie off scan_diag_pmax_i (+ pre-existing clut_* gap from the
fog baseline) in the four .* bridge/integration TBs.

Regressions green: scanout (cdc_qual, binomial_lookahead, diag, restart,
lpddr_scanout_lb x3), regbuf (r/aw/w), bridge + 3 pad integration TBs, and the
f52 top-level golden FB (Z 0/307200, COLOR 0/245760 mismatch, drops=0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-23 23:17:41 -04:00
parent 2e2c1e9ca6
commit 064484c50d
11 changed files with 418 additions and 63 deletions
+10 -1
View File
@@ -339,6 +339,7 @@ module ps2_hps_bridge (
input logic scan_diag_valid_i, // first-failure captured, held to !enable (video_clk level; bundled-data valid)
input logic [29:0] scan_diag_first_i, // SNAPSHOT {nf_s0[9:0],nf_v[9:0],scan_y[9:0]} (stable while valid -> 0x124)
input logic [6:0] scan_diag_stat_i, // SNAPSHOT {vphase[3:0],line_valid,lookahead,base} (stable while valid -> 0x120)
input logic [3:0] scan_diag_pmax_i, // Ch443f LIVE per-frame max miss streak (2-FF synced -> 0x120[15:12])
// ---- Ch322: LPDDR write-probe (HPS stages texture words) + texture-cache fill ----
// 0x040 LPDDR_WRADDR (W): set the LPDDR byte address (auto-increments +4 per data write).
@@ -657,6 +658,7 @@ module ps2_hps_bridge (
logic [1:0] scan_diag_uf_sync;
(* altera_attribute = "-name SYNCHRONIZER_IDENTIFICATION FORCED", dont_merge, preserve *)
logic [1:0] scan_diag_rderr_sync;
logic [3:0] scan_diag_pmax_s0, scan_diag_pmax_s1; // Ch443f — 2-FF sync of the live pmax magnitude
(* altera_attribute = "-name SYNCHRONIZER_IDENTIFICATION FORCED", dont_merge, preserve *)
logic [2:0] scan_diag_valid_sync; // 3-deep so the RISING synced edge latches the snapshot
logic scan_diag_snap_valid_q; // DEST valid: set WITH payload capture, cleared on synced source-valid deassert
@@ -954,7 +956,10 @@ module ps2_hps_bridge (
case (addr[4:2])
// 0x120 SCAN_DIAG_STATUS: [0]valid [1]underflow [2]read-error-nonzero
// [3]cause_base(scan_y>=nf_v) [4]cause_lookahead [5]line_valid [11:8]filter vphase.
3'h0: reg_read = {20'd0, scan_diag_vphase_q, 2'd0,
// Ch443f: [15:12] = live per-frame max miss streak (pmax); [0] valid now = a
// QUALIFIED (persistent) miss captured. Classify: valid=0 + small pmax => CDC-lag
// transient; valid=1 / large pmax => real starvation.
3'h0: reg_read = {16'd0, scan_diag_pmax_s1, scan_diag_vphase_q, 2'd0,
scan_diag_lv_q, scan_diag_look_q, scan_diag_base_q,
scan_diag_rderr_sync[1], scan_diag_uf_sync[1], scan_diag_snap_valid_q};
// 0x124 SCAN_DIAG_FIRST: [9:0]scan_y [19:10]nf_v [29:20]nf_s0.
@@ -1122,6 +1127,8 @@ module ps2_hps_bridge (
lpddr_scan_err_sync <= 2'b00;
scan_diag_uf_sync <= 2'b00;
scan_diag_rderr_sync <= 2'b00;
scan_diag_pmax_s0 <= 4'd0;
scan_diag_pmax_s1 <= 4'd0;
scan_diag_valid_sync <= 3'b000;
scan_diag_snap_valid_q<= 1'b0;
scan_diag_base_q <= 1'b0;
@@ -1167,6 +1174,8 @@ module ps2_hps_bridge (
// Ch442 — independent 2-FF syncs of the two split live flags (never the raw counter).
scan_diag_uf_sync <= {scan_diag_uf_sync[0], scan_diag_uf_i};
scan_diag_rderr_sync <= {scan_diag_rderr_sync[0], scan_diag_rderr_nz_i};
scan_diag_pmax_s0 <= scan_diag_pmax_i; // Ch443f — 2-FF sync of the small live magnitude
scan_diag_pmax_s1 <= scan_diag_pmax_s0;
// Bundled-data capture: sync the valid, and on its RISING synced edge the snapshot
// (held stable in the video domain since first-failure) is quiescent -> latch coherently.
scan_diag_valid_sync <= {scan_diag_valid_sync[1:0], scan_diag_valid_i};