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>
rtl/gif_gs
GIF path and Graphics Synthesizer logic. Matches docs/contracts/gif_gs.md.
Current contents
-
gs_stub.sv— GS shell with two architecturally distinct write ports (Ch75 namespace split):reg_wr_*— privileged-block writes (16-bit offset within0x12000000). LatchesBGCOLOR(offset0x00E0) intobg_{r,g,b}; other offsets emitEV_MODE.gif_reg_*— GIF A+D register-number writes (8-bit reg# + 64-bit data). DecodesPRIM=0x00,RGBAQ=0x01,XYZF2=0x04,XYZ2=0x05,FRAME_1=0x4C,ZBUF_1=0x4Einto per-register 64-bit latches; unknown reg numbers emitEV_MODE.- No VRAM, no drawing yet — that is the next architectural step.
-
gif_path_stub.sv— Wave 2 minimal GIF packet logger; project-local single-qword register-write format. Used bytb_bgcolor_via_dma. -
gif_packed_stub.sv— real PS2 GIFtag parser (Ch72-Ch75). Handles PACKED (FLG=0), REGLIST (FLG=1), IMAGE (FLG=2), DISABLE (FLG=3). TheREAL_AD_REG_MAPparameter selects the A+D dispatch port:REAL_AD_REG_MAP=0(default, back-compat) — drivesgs_stub.reg_wr_*using a project-local 16-bit offset carried inin_data[79:64].REAL_AD_REG_MAP=1— drivesgs_stub.gif_reg_*using the real PS2 8-bit reg# carried inin_data[71:64]. Source-of-truth: PCSX2GSRegs.h.
BGCOLOR reset value
At reset, bg_{r,g,b} default to 0x40 each (mid-grey) rather than black.
Rationale: this makes "gs_stub reset but no BGCOLOR write yet" visually
distinct from "video output disabled / black frame" in Milestone A. Override
is a BGCOLOR write from the test harness.
Pitfall: namespace conflation
Ch74 conflated GIF A+D reg numbers with GS privileged-block offsets and
mapped e.g. 0x14→PMODE@0x0000. That is fiction — those are separate
namespaces. Ch75 split them. ZBUF_1 is 0x4E, not 0x4F (that's
ZBUF_2). When adding a new GIF-context register, source the reg# from
PCSX2 GSRegs.h, never from the privileged-block map.