Ch443c: per-frame scanout diagnostic + frame-restart latency fix

The Ch443 board A+B diagnostic captured a WARM-UP miss, not a displayed-
frame miss: the line-buffer reader is enabled by video_src_emif
immediately, but the HDMI mux only switches to it at the next vsync, and
the diagnostic (cleared only on !enable) froze that pre-display capture.
scan_y=32/nf=32 was the expected pre-display warm-up, and line_valid is
sticky so it only meant SOME row had loaded, not that row 32 was valid.

Two fixes (all accepted Ch443 timing repairs kept: AW buffer, F_SETTLE +
drain multicycle, tile max-skew, monolithic tex_mem):

1. Per-frame diagnostic: clear diag_valid_q on fs_edge_v as well as
   !enable (mirrors underflow_v). Discards the warm-up capture and
   records the first miss, if any, AFTER the real frame boundary.

2. Frame-restart latency: in L_R, after the single-beat response is
   accepted, if fs_pending || fs_edge_e, abandon the remainder of the
   obsolete row -- no beat commit, no next old-row AR, no publish/
   increment -- and return to L_IDLE, which restarts at V_SOURCE_START.
   Protocol-safe (the accepted AXI transaction is complete); removes up
   to a full row of restart latency during vertical blanking, so the
   restarted prefetch leads the first displayed row.

New tb_gs_scanout_restart proves: mid-fetch frame-start accepts the
in-flight response, issues NO further old-row AR, restarts at row 32,
loads rows 32/33 before active consumption, and no post-restart
underflow. Regressions green: scanout_lb {,_binomial,_hstretch,
_psm32_256,_fb}, scanout_diag (per-frame), ps2_hps_bridge, and the
complete f52 replay BYTE-IDENTICAL (Z 0/307200, COLOR 0/245760).

Also commits the previously-untracked Ch443 board A+B evidence
(docs/hardware/ch443_board_validation/: verdict, 3-session raw, board
FB, RBF sha). No Quartus/board/push from here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-22 18:10:55 -04:00
parent 4358bc328b
commit 846eee06b6
7 changed files with 307452 additions and 27 deletions
@@ -0,0 +1,13 @@
SESSION 1
0x02C=0x000000F1
0x120=0x0000003B
0x124=0x02008020
SESSION 2
0x02C=0x000000F1
0x120=0x0000003B
0x124=0x02008020
SESSION 3
0x02C=0x000000F1
0x120=0x0000003B
0x124=0x02008020
DONE
@@ -0,0 +1,45 @@
# Ch443 board A+B diagnostic — verdict (zsrt139f52, 2026-07-22)
Image: `retroDE_ps2.ch443.core.rbf` SHA `d15deb42c99212d49715335d460357dc3f2487e14cf49bd60c7ad63ba52b9990`
(26.1.0 Build 110 GUI fit of commit 4358bc3; non-canonical diagnostic candidate). Canonical
`retroDE_ps2.core.rbf` untouched; Ch441 restored after capture.
## Fit acceptance (all met)
Timing: 0 violated setup/hold paths, EMIF setup +0.177; AWREADY family absent; drain multicycle
bound (`Ch443 SDC: texture drain_idx_q -> tex_mem 2-cycle setup / 1-cycle hold (16 src -> 2053 dst)`);
monolithic **128-M20K** `tex_mem`; RAM 317/358 (89%), ALM 85%.
## Board render
f52 replay `DONE rc=0`, zero drops, texture CRC `0x13cfe390` == expected, FB **byte-identical to
golden** (SHA `d0047677…`, sum32 `0xaad0b94d`). The AW buffer + F_SETTLE 2-cycle drain + monolithic
tex_mem are all functionally correct on silicon.
## A+B diagnostic — 3 independent source-enable sessions, BIT-IDENTICAL each time
| reg | raw | decode |
|-----|-----|--------|
| 0x02C LPDDR_STATUS | `0x000000F1` | idle, scan_cache_valid, **scan_rd_err(bit5)=1**, frame_drained, clear_done |
| 0x120 SCAN_DIAG_STATUS | `0x0000003B` | valid=1, **underflow=1**, **read-error-nonzero=0**, cause_base=1, cause_lookahead=1, line_valid=1, vphase=0 |
| 0x124 SCAN_DIAG_FIRST | `0x02008020` | **scan_y=32, nf_v=32, nf_s0=32** |
## VERDICT
The `LPDDR_STATUS[5]` `0xF1` symptom is definitively a **line-buffer prefetch UNDERFLOW, NOT an AXI
read error** — `0x120` shows underflow=1 with read-error-nonzero=**0**. This resolves the three-way
ambiguity Codex flagged: it is cause #1 (starvation-class), not cause #2 (AXI read errors).
The first failure is pinned to **scan_y = 32 = V_SOURCE_START** (SH3 DISPFB2.DBY=32, the first
displayed source row) — exactly the production cold-start row-32 miss predicted. `nf_v = nf_s0 = 32`
= `next_fetch` at its frame-start reset value, i.e. the prefetch had not advanced past row 32 when
row 32 was first displayed. Both cause bits assert (base + lookahead), consistent with the vertical
filter. line_valid=1 confirms the EMIF read path works — this is a first-displayed-row ordering race,
not total starvation. Deterministic across 3 independent sessions ⇒ a reproducible STRUCTURAL
first-row prefetch boundary, not a random glitch.
## Caveat (per Codex) + next
A single snapshot NARROWS but does not by itself PROVE sustained starvation vs a `next_fetch` CDC-lag
at reset (nf_v=32 is exactly the reset value). What is now PROVEN: (a) not an AXI read error; (b) the
first miss is the cold-start row-32 boundary; (c) deterministic. Definitive starvation-vs-CDC
separation needs the deferred follow-up (gray-code `next_fetch` across the sync, or a 2-cycle
compare-agreement, or multi-frame captures). The FB (memory) is byte-perfect; whether this scanout
underflow produces visible HDMI top-row corruption needs an actual HDMI capture (not a memory dump).
Evidence: `ch443_ab_3session_raw.txt`, `sh3_zsrt139f52_ch443_board_fb.mem`, `ch443_rbf.sha256`.
@@ -0,0 +1 @@
d15deb42c99212d49715335d460357dc3f2487e14cf49bd60c7ad63ba52b9990 docs/hardware/ch443_board_validation/retroDE_ps2.ch443.core.rbf
File diff suppressed because it is too large Load Diff