Files
retroDE_ps2/docs/hardware/ch443d_board_validation/ch443d_perframe_verdict.md
T
thejayman77 2e2c1e9ca6 Ch443e: binomial 4th line buffer + prefetch lead-2 (fix lookahead underflow)
The Ch443d board per-frame diagnostic identified the real displayed-frame
failure as a BINOMIAL vertical-lookahead starvation: displaying source
row r while interpolating r-1/r/r+1, the prefetch led by only one row
(next_fetch <= disp_row+1), so the lookahead row r+1 was still in flight
when the 3x3 filter read it (board: scan_y=33, nf_v=34, cause_lookahead=1,
read-error=0, deterministic every frame).

Fix (BINOMIAL_3X3_FILTER only; legacy 2/3-buffer, lead-1 paths unchanged):
- Add a 4th rotating line buffer (lb3) with its own RAM-local write/read/
  cache registers. The 3x3 filter needs r-1/r/r+1 resident (3 buffers), so
  leading by 2 (fetch r+2 while displaying r) without overwriting r-1
  requires a 4th buffer.
- Prefetch lead-2 for binomial: disp_row_limit_e = disp_row+2. The in-flight
  r+2 lands in the 4th buffer (b+2 mod 4), always distinct from prev/cur/next
  (b-1/b/b+1 mod 4), so it never clobbers a row being read.
- Modulo-4 rotation everywhere: V_SOURCE_BUF%4, stretch_buf_q, next_fetch_buf,
  reset alignment at V_SOURCE_START, and the read-cache prev/cur/next case
  extended to 4 branches with (b-1)/b/(b+1) mod 4 selection + first/last-row
  clamps preserved.

New tb_gs_scanout_binomial_lookahead reproduces the board condition under
realistic EMIF latency (LAT=7) + backpressure and proves: NO binomial
lookahead underflow, correct 3x3 output across modulo-4 wrap + clamps (full
oracle, 1280 px), and coverage that mid-frame rows past V_SOURCE_START+1
with vphase!=0 were exercised under prefetch pressure.

All green: binomial (4-buffer, identical output), lookahead (new),
scanout_lb {,_hstretch,_psm32_256,_fb}, scanout_restart, scanout_diag,
ps2_hps_bridge, and the complete f52 replay BYTE-IDENTICAL (Z 0/307200,
COLOR 0/245760). Also commits the Ch443d board evidence that identified
this defect. No Quartus/board/push from here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 15:24:37 -04:00

2.7 KiB

Ch443d board verdict — per-frame scanout diagnostic (zsrt139f52, 2026-07-23)

Image: retroDE_ps2.ch443d.core.rbf SHA 87c382f1... (26.1 GUI compile of 0c9b2bf = 6319d7c RTL + SEED 3). Non-canonical candidate; Ch441 restored after capture.

Fit + render (accepted)

Seed-3 GUI compile: EMIF setup +0.132, all timing classes >=0, 0 violated, no AWREADY/texcache-fill/drain/scanout-diag families, RAM 317/358. Board f52 replay byte-identical to golden (FB d0047677, texture CRC 0x13cfe390, 0 drops).

Per-frame diagnostic (8 samples over many displayed frames, stable)

reg raw decode
0x02C 0xF1 scan underflow (bit5)=1, bresp=0
0x120 0x0D33 valid=1, underflow=1, read-error=0, cause_base=0, cause_lookahead=1, line_valid=1, vphase=13
0x124 0x02208821 scan_y=33, nf_v=34, nf_s0=34

VERDICT — the REAL displayed-frame failure (NOT the warm-up, NOT a read error)

The Ch443c per-frame clear + restart-latency fix worked as intended: the pre-display warm-up capture (previously scan_y=32/nf=32/base) is GONE. The diagnostic now reports the true steady-state failure, and it is a vertical LINEAR-FILTER LOOKAHEAD starvation:

  • scan_y=33 is resident (33 < nf_v=34 -> base cause correctly 0).
  • At vphase=13 the V_LINEAR_FILTER interpolates between source rows 33 and 34, so it needs the LOOKAHEAD row scan_y+1 = 34. But nf_v=34 means next_fetch is AT row 34 -> row 34 is being fetched, NOT yet resident -> scan_y+1 >= nf_v -> lookahead cause fires -> underflow.
  • read-error=0: not an AXI error. Deterministic every frame: structural, not a CDC glitch.

Root cause: the prefetch throttle leads by exactly ONE row (next_fetch <= disp_row+1), but the vertical linear filter needs the lookahead row (disp_row+1) FULLY resident. The prefetch is one row short of the filter's requirement, so displaying row 33 while row 34 is still loading races the filter's read of row 34.

Open question + fix direction (for Codex)

  • Leading by 2 (disp_row+2) would make the lookahead row resident in time, but V_LINEAR uses only 2 line buffers (parity) -- disp_row and disp_row+2 share a buffer, so leading by 2 needs a 3rd line buffer (as BINOMIAL already has) or a different prefetch/latency structure.
  • The FB (memory) is byte-perfect; whether this lookahead underflow is HDMI-VISIBLE (a subtle artifact at inter-row filter boundaries) needs an actual HDMI capture -- the flag is conservative (fires when the lookahead row's fetch is in-flight, which may still complete before the specific pixels are read).

Evidence: ch443d_perframe_diag_8samples.txt, sh3_zsrt139f52_ch443d_board_fb.mem, ch443d_rbf.sha256.