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:
@@ -0,0 +1,119 @@
|
||||
// retroDE_ps2 — tb_gs_async_fifo (Ch357, Codex)
|
||||
//
|
||||
// Scoreboard for gs_async_fifo after the REGISTERED-empty change (rempty <= rempty_nxt, the read-side twin of the
|
||||
// registered wfull). Two ASYNCHRONOUS clocks. The writer pushes a strictly increasing sequence; the reader pops and
|
||||
// asserts each rdata equals the next expected value -> catches ANY duplicate (same value twice) or drop (skipped value)
|
||||
// and guarantees in-order delivery. Covers: continuous reads, final-entry empty assertion, asynchronous write arrival,
|
||||
// wrap/full backpressure, and randomized read/write gaps under async clocks.
|
||||
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module tb_gs_async_fifo #(
|
||||
parameter bit TEST_BANKED = 1'b0,
|
||||
parameter bit TEST_QUADRANT = 1'b0,
|
||||
parameter bit TEST_REGISTERED = TEST_BANKED || TEST_QUADRANT
|
||||
);
|
||||
localparam int WIDTH = 32;
|
||||
localparam int DEPTH = 8;
|
||||
|
||||
// Production request-FIFO corner: 40 MHz raster producer into the
|
||||
// ~310 MHz EMIF consumer. A slower-reader test cannot detect publishing
|
||||
// the write pointer before a staged RAM commit.
|
||||
logic wclk=0; always #12.5 wclk=~wclk; // 40 MHz
|
||||
logic rclk=0; always #1.6 rclk=~rclk; // 312.5 MHz, async to wclk
|
||||
logic wrst_n, rrst_n;
|
||||
|
||||
logic wr, wfull;
|
||||
logic [WIDTH-1:0] wdata;
|
||||
logic rd, dut_rd, rempty;
|
||||
logic [WIDTH-1:0] rdata;
|
||||
logic registered_pending;
|
||||
|
||||
gs_async_fifo #(.WIDTH(WIDTH), .DEPTH(DEPTH),
|
||||
.REGISTERED_READ(TEST_REGISTERED), .BANKED_READ(TEST_BANKED),
|
||||
.QUADRANT_READ(TEST_QUADRANT)) dut (
|
||||
.wclk(wclk), .wrst_n(wrst_n), .wr(wr), .wdata(wdata), .wfull(wfull),
|
||||
.rclk(rclk), .rrst_n(rrst_n), .rd(dut_rd), .rdata(rdata), .rempty(rempty)
|
||||
);
|
||||
|
||||
// independent LFSR backpressure on each clock
|
||||
logic [15:0] wl=16'hBEEF; always_ff @(posedge wclk) wl<={wl[14:0], wl[15]^wl[13]^wl[12]^wl[10]};
|
||||
logic [15:0] rl=16'h1234; always_ff @(posedge rclk) rl<={rl[14:0], rl[15]^rl[13]^rl[12]^rl[10]};
|
||||
|
||||
logic want_write, force_read_all, stop_write;
|
||||
assign want_write = wl[0] | wl[3]; // ~75% offered writes
|
||||
assign wr = want_write && !stop_write; // FIFO gates internally with !wfull; stop_write freezes the producer
|
||||
assign rd = force_read_all ? 1'b1 : (rl[1] | rl[4]); // continuous-read phase forces rd=1
|
||||
// gs_async_fifo's rd input is an accepted-read handshake. Keep the
|
||||
// randomized read request separate so the test explicitly enforces that
|
||||
// interface contract, exactly as every production wrapper does.
|
||||
assign dut_rd = rd && !rempty && (!TEST_REGISTERED || !registered_pending);
|
||||
always_ff @(posedge rclk or negedge rrst_n) begin
|
||||
if (!rrst_n) registered_pending <= 1'b0;
|
||||
else registered_pending <= TEST_REGISTERED && dut_rd;
|
||||
end
|
||||
|
||||
logic [WIDTH-1:0] wr_seq, rd_seq; // next value to write / next value expected to read
|
||||
assign wdata = wr_seq;
|
||||
|
||||
int errors; initial errors=0;
|
||||
int sb_err; // scoreboard-only error counter (reset + written solely by the reader always_ff)
|
||||
|
||||
// writer: count accepted writes, advance the sequence
|
||||
always_ff @(posedge wclk or negedge wrst_n) begin
|
||||
if (!wrst_n) wr_seq <= '0;
|
||||
else if (wr && !wfull) wr_seq <= wr_seq + 1;
|
||||
end
|
||||
|
||||
// reader scoreboard: every accepted read must equal the next expected sequence value (in order, no dup/drop)
|
||||
always_ff @(posedge rclk or negedge rrst_n) begin
|
||||
if (!rrst_n) begin rd_seq <= '0; sb_err <= 0; end
|
||||
else if (TEST_REGISTERED ? registered_pending : dut_rd) begin
|
||||
if (rdata !== rd_seq) begin
|
||||
if (sb_err < 20) $error("[afifo] out-of-order/dup/drop: got %0d expected %0d", rdata, rd_seq);
|
||||
sb_err <= sb_err + 1;
|
||||
end
|
||||
rd_seq <= rd_seq + 1;
|
||||
end
|
||||
end
|
||||
|
||||
task automatic run_cycles(input int n_r); repeat (n_r) @(posedge rclk); endtask
|
||||
|
||||
initial begin
|
||||
wrst_n=0; rrst_n=0; force_read_all=0; stop_write=0;
|
||||
repeat (6) @(posedge wclk); wrst_n=1;
|
||||
repeat (6) @(posedge rclk); rrst_n=1;
|
||||
|
||||
// reset check: FIFO must come up EMPTY
|
||||
@(posedge rclk);
|
||||
if (rempty !== 1'b1) begin $error("[afifo] rempty not asserted after reset"); errors++; end
|
||||
|
||||
// ---- Phase 1: randomized async read/write (wrap/full exercised many times) ----
|
||||
run_cycles(30000);
|
||||
|
||||
// ---- Phase 2: continuous reads -> drain fully; assert final-entry empty ----
|
||||
force_read_all = 1'b1;
|
||||
run_cycles(4000);
|
||||
force_read_all = 1'b0;
|
||||
|
||||
// ---- Phase 3: FREEZE the writer, drain fully, assert EMPTY + counts equal (final-entry empty assertion) ----
|
||||
stop_write = 1'b1;
|
||||
force_read_all = 1'b1;
|
||||
begin int g; g=0; while ((wr_seq !== rd_seq) && g<40000) begin @(posedge rclk); g++; end end
|
||||
run_cycles(20);
|
||||
|
||||
// ---- checks ----
|
||||
if (rempty !== 1'b1) begin $error("[afifo] FIFO not EMPTY after full drain (rempty=%0b)", rempty); errors++; end
|
||||
if (wr_seq !== rd_seq) begin $error("[afifo] count mismatch: wrote %0d read %0d (drop/dup)", wr_seq, rd_seq); errors++; end
|
||||
if (wr_seq < 32'd1000) begin $error("[afifo] too few transfers (%0d) — test not meaningful", wr_seq); errors++; end
|
||||
errors = errors + sb_err;
|
||||
|
||||
$display("[tb_gs_async_fifo] wrote=%0d read=%0d sb_err=%0d rempty=%0b errors=%0d",
|
||||
wr_seq, rd_seq, sb_err, rempty, errors);
|
||||
if (errors==0) $display("[tb_gs_async_fifo] PASS");
|
||||
else $display("[tb_gs_async_fifo] FAIL");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin #4000000; $error("[tb_gs_async_fifo] TIMEOUT"); $finish; end
|
||||
endmodule : tb_gs_async_fifo
|
||||
Reference in New Issue
Block a user