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:
@@ -369,13 +369,15 @@ set_false_path -from $osd_cfg_src -to $osd_cfg_dst
|
||||
# Cut the async INTO stage 0 only (setup+hold); the sync[0]->sync[1..] MTBF
|
||||
# leg stays timed. Nonzero-check WARN (the whole path is absent in non-LPDDR
|
||||
# profiles), not fatal.
|
||||
# (b) the 37-bit STABLE first-failure bundle {scan_y[10], nf_v[10], nf_s0[10],
|
||||
# vphase[4], base, lookahead, line_valid}. It is written once per enabled
|
||||
# session and held quiescent until the bridge captures it on the synced-valid
|
||||
# edge -> the raw HOLD check is false; cut HOLD only + bound bit spread
|
||||
# (set_max_skew 2ns) + bound net arrival (set_net_delay -max 2ns), same recipe
|
||||
# as the tile_ram_cdc bundle above. FATAL count checks so a rename can't
|
||||
# silently orphan the exception (src==37 exact; dst nonzero).
|
||||
# (b) the 31-src STABLE first-failure bundle {scan_y[10], nf_v[10], pmax[4],
|
||||
# vphase[4], base, lookahead, line_valid} (Ch443f: nf_s0[10] -> pmax[4];
|
||||
# diag_first[29:20] now carries the qualified-miss persistence max, upper 6
|
||||
# bits const 0 so the bridge dst reg stays 10-bit / 37-keeper). It is written
|
||||
# once per enabled session and held quiescent until the bridge captures it on
|
||||
# the synced-valid edge -> the raw HOLD check is false; cut HOLD only + bound
|
||||
# bit spread (set_max_skew 2ns) + bound net arrival (set_net_delay -max 2ns),
|
||||
# same recipe as the tile_ram_cdc bundle above. FATAL count checks so a rename
|
||||
# can't silently orphan the exception (src==31 exact; dst nonzero).
|
||||
foreach s {scan_diag_uf_sync scan_diag_rderr_sync scan_diag_valid_sync} {
|
||||
set s0 [get_keepers -nowarn "*u_hps_bridge|$s\[0\]"]
|
||||
if { [get_collection_size $s0] == 0 } {
|
||||
@@ -384,14 +386,41 @@ foreach s {scan_diag_uf_sync scan_diag_rderr_sync scan_diag_valid_sync} {
|
||||
set_false_path -to $s0
|
||||
}
|
||||
}
|
||||
set scan_diag_src [get_keepers -nowarn {*u_lpddr_scan_lb|diag_scan_y_q[*] *u_lpddr_scan_lb|diag_nf_v_q[*] *u_lpddr_scan_lb|diag_nf_s0_q[*] *u_lpddr_scan_lb|diag_vphase_q[*] *u_lpddr_scan_lb|diag_base_q *u_lpddr_scan_lb|diag_look_q *u_lpddr_scan_lb|diag_lv_q}]
|
||||
# Ch443f: live per-frame pmax magnitude (4-bit bus) is a plain advisory 2-FF sync
|
||||
# (video_clk uf_pmax_q -> bridge scan_diag_pmax_s0[*]); cut the async INTO stage 0
|
||||
# only, leaving s0->s1 timed. Bus bits may be momentarily incoherent — harmless,
|
||||
# it feeds 0x120[15:12] read across many frames, not the coherent capture bundle.
|
||||
set pmax_s0 [get_keepers -nowarn {*u_hps_bridge|scan_diag_pmax_s0[*]}]
|
||||
if { [get_collection_size $pmax_s0] == 0 } {
|
||||
post_message -type warning "Ch443f SDC WARN: scan_diag_pmax_s0 matched 0 keepers (renamed / no LPDDR scanout) — stage-0 cut NOT applied"
|
||||
} else {
|
||||
set_false_path -to $pmax_s0
|
||||
}
|
||||
# Ch443f: coherent readiness GRAY code (axi next_fetch -> next_fetch_gray comb ->
|
||||
# video nf_gray_s0[*]). Async into stage 0 -> cut setup+hold into nf_gray_s0; the
|
||||
# s0->s1 MTBF leg stays timed. Gray changes ONE bit per increment, but bound the
|
||||
# source->stage0 bit spread (max_skew + net_delay 2ns) so the lone multi-bit event
|
||||
# (frame-restart reset to V_SOURCE_START, which fs_edge_v overrides on the video
|
||||
# side anyway) cannot spread across more than one video sample. FATAL count guard.
|
||||
set nfg_dst [get_keepers -nowarn {*u_lpddr_scan_lb|nf_gray_s0[*]}]
|
||||
set nfg_src [get_keepers -nowarn {*u_lpddr_scan_lb|next_fetch[*]}]
|
||||
if { [get_collection_size $nfg_dst] == 0 } {
|
||||
post_message -type info "Ch443f SDC: next_fetch Gray readiness CDC inactive in this profile (0 stage-0 dst)"
|
||||
} else {
|
||||
if { [get_collection_size $nfg_src] == 0 } { error "Ch443f SDC FATAL: nf_gray_s0 present but u_lpddr_scan_lb|next_fetch[*] matched 0 keepers (renamed? Gray CDC source orphaned)" }
|
||||
set_false_path -to $nfg_dst
|
||||
set_max_skew -from $nfg_src -to $nfg_dst 2.0
|
||||
set_net_delay -max -from $nfg_src -to $nfg_dst 2.0
|
||||
post_message -type info "Ch443f SDC: next_fetch Gray readiness CDC async-in cut + 2ns max_skew/net_delay ([get_collection_size $nfg_src] src -> [get_collection_size $nfg_dst] stage-0 dst)"
|
||||
}
|
||||
set scan_diag_src [get_keepers -nowarn {*u_lpddr_scan_lb|diag_scan_y_q[*] *u_lpddr_scan_lb|diag_nf_v_q[*] *u_lpddr_scan_lb|diag_pmax_q[*] *u_lpddr_scan_lb|diag_vphase_q[*] *u_lpddr_scan_lb|diag_base_q *u_lpddr_scan_lb|diag_look_q *u_lpddr_scan_lb|diag_lv_q}]
|
||||
set scan_diag_dst [get_keepers -nowarn {*u_hps_bridge|scan_diag_scan_y_q[*] *u_hps_bridge|scan_diag_nf_v_q[*] *u_hps_bridge|scan_diag_nf_s0_q[*] *u_hps_bridge|scan_diag_vphase_q[*] *u_hps_bridge|scan_diag_base_q *u_hps_bridge|scan_diag_look_q *u_hps_bridge|scan_diag_lv_q}]
|
||||
set scan_diag_src_n [get_collection_size $scan_diag_src]
|
||||
set scan_diag_dst_n [get_collection_size $scan_diag_dst]
|
||||
if { $scan_diag_src_n == 0 } {
|
||||
post_message -type info "Ch442 SDC: scanout diagnostic CDC inactive in this profile (0 src -> no LPDDR scanout)"
|
||||
} else {
|
||||
if { $scan_diag_src_n != 37 } { error "Ch442 SDC FATAL: scanout diag bundle source count $scan_diag_src_n != 37 (10+10+10+4+1+1+1; renamed/optimized? hold cut + net_delay would orphan)" }
|
||||
if { $scan_diag_src_n != 31 } { error "Ch442/443f SDC FATAL: scanout diag bundle source count $scan_diag_src_n != 31 (10+10+4+4+1+1+1 = scan_y+nf_v+pmax+vphase+base+look+lv; renamed/optimized? hold cut + net_delay would orphan)" }
|
||||
if { $scan_diag_dst_n == 0 } { error "Ch442 SDC FATAL: scanout diag bundle dest u_hps_bridge|scan_diag_*_q EMPTY (renamed? hold cut would orphan)" }
|
||||
set_false_path -hold -from $scan_diag_src -to $scan_diag_dst
|
||||
set_max_skew -from $scan_diag_src -to $scan_diag_dst 2.0
|
||||
|
||||
Reference in New Issue
Block a user