Files
retroDE_ps2/rtl/gif_gs
thejayman77 4e8c3a16b8 Ch444: serialize gradient numerator bank — reclaim ~half the FPGA's DSP
The per-triangle gradient engine already time-shared ONE divider across all
GRAD_STEPS attributes, but computed every grad_load_num[0:GRAD_STEPS-1] numerator
IN PARALLEL — ~44 wide multiplies (~100 physical DSP) for once-per-triangle setup
consumed one-at-a-time. Pure redundant hardware; the design was DSP-maxed
(187/188, 99%) so nothing new could fit (fog needed 191/188).

Replace the parallel bank + the grad_num_q[] pre-latch array with grad_num_step:
computes ONLY the current grad_step's numerator from ONE mux-selected pair of
signed multipliers (attribute triple by grad_step>>1, axis by grad_step[0]; shared
da1/da2, two shared products, signed subtract, <<<20). grad_word_q/grad_slot are
held stable the whole solve, so it is bit-identical to the old grad_num_q[grad_step].
Removed grad_num_dadx/dady (inlined once). FSM sequencing and throughput unchanged.

Width note: da1/da2 are 33-bit (products 50-bit), NOT operand-width 32-bit — the
original (a1-a0) lived in a signed-64-bit expression context and never wrapped;
full-32-bit Z with |a1-a0|>2^31 needs the wider intermediate. tb_gs_grad_num_equiv
(extreme signed corners + 200k random = 494770 checks, 0 errors) caught a 32-bit
first cut that f52's real data never exercised.

Resource (26.1 Seed-3 fit): DSP needed 168->83 / final placement 187->119, i.e.
99% -> 44%, ~85 blocks reclaimed (Codex gate >=70 met). ALM 40458->38784 (86->83%).
RAM 322/358 unchanged. Timing CLEAN: setup +0.077, all classes >=0, 0 violated.

Verification: tb_gs_grad_num_equiv 0/494770; f52 replay BYTE-IDENTICAL golden
d0047677 (drops=0, occupancy unchanged); gradient/perspective/texture regressions
(tri_interp, grad_divider, persp_uv, zbuffer, fog_persp, textured_triangle,
triangle/perspective/combined/gouraud demos) all PASS. Byte-identical => the
screen is unchanged; this is the resource unlock for fog + coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 05:28:12 -04:00
..

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 within 0x12000000). Latches BGCOLOR (offset 0x00E0) into bg_{r,g,b}; other offsets emit EV_MODE.
    • gif_reg_* — GIF A+D register-number writes (8-bit reg# + 64-bit data). Decodes PRIM=0x00, RGBAQ=0x01, XYZF2=0x04, XYZ2=0x05, FRAME_1=0x4C, ZBUF_1=0x4E into per-register 64-bit latches; unknown reg numbers emit EV_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 by tb_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). The REAL_AD_REG_MAP parameter selects the A+D dispatch port:

    • REAL_AD_REG_MAP=0 (default, back-compat) — drives gs_stub.reg_wr_* using a project-local 16-bit offset carried in in_data[79:64].
    • REAL_AD_REG_MAP=1 — drives gs_stub.gif_reg_* using the real PS2 8-bit reg# carried in in_data[71:64]. Source-of-truth: PCSX2 GSRegs.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.