Snapshot: fog implementation + fidelity tooling baseline (pre bilinear-clamp fix)

Per-vertex GS fog end-to-end (gs_stub emit incl. persp_emit5, gs_prim_list_feeder
XYZ2->XYZF2 on PRIM.FGE, gs_make_sh3_scheduler_fixture.py F/FGE packing), new fog
TBs, fidelity attribution tooling. Functional baseline before removing the dead
bilinear lerp8 clamps (Codex: 161-node comb loop -> -0.042ns setup fail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-20 19:56:46 -04:00
parent ec82764bef
commit ba74bbd5aa
476 changed files with 696247 additions and 130119 deletions
+25 -3
View File
@@ -88,13 +88,22 @@ module gs_texture_cache #(
(* ramstyle = "M20K" *) logic [31:0] tex_mem [0:TEX_WORDS-1];
// ================= fill side (axi_clk) =================
typedef enum logic [2:0] { F_IDLE, F_AR, F_R, F_DRAIN, F_DONE } fstate_t;
typedef enum logic [2:0] { F_IDLE, F_AR, F_R, F_DRAIN, F_WRITE, F_DONE } fstate_t;
fstate_t fst;
logic [$clog2(N_BEATS):0] beat; // 0..N_BEATS
logic [255:0] fill_data_q;
logic [2:0] fill_lane;
logic [WIDX_BITS-1:0] fill_word_base;
wire [WIDX_BITS-1:0] fill_word_idx = fill_word_base + WIDX_BITS'(fill_lane);
// Ch358 (Codex) — registered RESOLVED drain word + RAM index. The 26.1 STA showed fill_lane launching into
// tex_mem's data port: the dynamic 256->32 mux (fill_data_q[fill_lane*32+:32]) fed the RAM write directly.
// F_DRAIN now only registers the SELECTED word/index; F_WRITE commits that register to tex_mem next cycle
// (2 cycles/lane — harmless one-shot fill time). fill_crc accumulates the COMMITTED word, semantics unchanged.
// These payload registers are deliberately unreset. F_WRITE is reachable only after F_DRAIN has loaded both,
// so reset values are unobservable; keeping them out of the 4k-fanout EMIF calibration reset removes that reset
// from the duplicated RAM-address launch registers at 310 MHz.
logic [31:0] drain_word_q;
logic [WIDX_BITS-1:0] drain_idx_q;
// fill_start is an EDGE/TOGGLE (bridge toggles it on each arm), CDC-synced here so the
// cache is RE-FILLABLE: each arm reloads the texture (lets the HPS re-stage a different
// texture without a board reset). 3-FF sync + edge-detect, like the read/write probes.
@@ -142,8 +151,12 @@ module gs_texture_cache #(
end
end
F_DRAIN: begin
tex_mem[fill_word_idx] <= fill_data_q[fill_lane*32 +: 32];
fill_crc <= fill_crc + fill_data_q[fill_lane*32 +: 32]; // sum32 over the words written
fst <= F_WRITE;
end
F_WRITE: begin
// COMMIT half: registered word -> M20K; CRC over the word actually committed.
tex_mem[drain_idx_q] <= drain_word_q;
fill_crc <= fill_crc + drain_word_q; // sum32 over the words written
if (fill_lane == 3'd7) begin
fill_beats <= fill_beats + 32'd1;
fill_bytes <= fill_bytes + 32'd32;
@@ -158,6 +171,7 @@ module gs_texture_cache #(
end
end else begin
fill_lane <= fill_lane + 3'd1;
fst <= F_DRAIN;
end
end
F_DONE: begin
@@ -180,6 +194,14 @@ module gs_texture_cache #(
end
end
// Control-free payload boundary: observability is controlled by the reset FSM, not by reset on the data itself.
always_ff @(posedge axi_clk) begin
if (fst == F_DRAIN) begin
drain_word_q <= fill_data_q[fill_lane*32 +: 32];
drain_idx_q <= fill_word_idx;
end
end
// ================= sampler side (sample_clk) =================
// 1-cycle REGISTERED read, identical timing to vram_bram_stub.read2:
// present (tex_rd_addr) when tex_rd_en, data lands next cycle.