Initial commit: retroDE_ps2 — first-of-its-kind PS2 GS FPGA core (DE25-Nano / Agilex 5)
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression (272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps, and all dump-derived textures/traces) is excluded via .gitignore and stays local. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
// tb_gs_grad_divider — proves gs_grad_divider is BIT-EXACT to SystemVerilog signed `/` (Ch352).
|
||||
// Golden = (den==0) ? 0 : $signed(num)/$signed(den). Covers all 4 sign combinations, zero divisor,
|
||||
// truncation-toward-zero, most-negative edges, divide-by-1 / by-self, and random operands.
|
||||
`timescale 1ns/1ps
|
||||
module tb_gs_grad_divider;
|
||||
localparam int W = 56;
|
||||
logic clk=0; always #5 clk=~clk;
|
||||
logic rst_n, start, busy, done;
|
||||
logic signed [W-1:0] num, den, quo;
|
||||
|
||||
gs_grad_divider #(.W(W)) dut (
|
||||
.clk(clk), .rst_n(rst_n), .start(start), .num(num), .den(den),
|
||||
.quo(quo), .busy(busy), .done(done)
|
||||
);
|
||||
|
||||
int errors = 0;
|
||||
function automatic logic signed [W-1:0] golden(input logic signed [W-1:0] n, d);
|
||||
// NOTE: use if/else with a signed intermediate — a ternary `? '0 : n/d` poisons n/d into an UNSIGNED
|
||||
// context (the '0 branch), giving the wrong reference. This is the true signed truncate-toward-zero.
|
||||
logic signed [W-1:0] q;
|
||||
if (d == '0) q = '0;
|
||||
else q = n / d;
|
||||
golden = q;
|
||||
endfunction
|
||||
|
||||
task automatic do_div(input logic signed [W-1:0] n, d, input string tag);
|
||||
logic signed [W-1:0] exp;
|
||||
exp = golden(n,d);
|
||||
@(negedge clk); num=n; den=d; start=1'b1;
|
||||
@(negedge clk); start=1'b0;
|
||||
begin int to=0; while(!done && to<200) begin @(posedge clk); to++; end
|
||||
if(!done) begin $error("[divtb] TIMEOUT %s", tag); errors++; end end
|
||||
if (quo !== exp) begin
|
||||
errors++;
|
||||
if (errors<20) $error("[divtb] %s: num=%0d den=%0d quo=%0d exp=%0d", tag, n, d, quo, exp);
|
||||
end
|
||||
@(negedge clk);
|
||||
endtask
|
||||
|
||||
logic signed [W-1:0] rn, rd;
|
||||
initial begin
|
||||
rst_n=0; start=0; num=0; den=0;
|
||||
repeat(4) @(negedge clk); rst_n=1; repeat(2) @(negedge clk);
|
||||
|
||||
// ---- targeted: all sign combinations + truncation toward zero ----
|
||||
do_div( 56'sd7, 56'sd2, "7/2=3");
|
||||
do_div(-56'sd7, 56'sd2, "-7/2=-3 (trunc, not -4)");
|
||||
do_div( 56'sd7, -56'sd2, "7/-2=-3");
|
||||
do_div(-56'sd7, -56'sd2, "-7/-2=3");
|
||||
do_div( 56'sd1000000, 56'sd7, "1e6/7 trunc");
|
||||
do_div(-56'sd1000000, 56'sd7, "-1e6/7 trunc");
|
||||
// ---- zero divisor -> 0 ----
|
||||
do_div( 56'sd12345, 56'sd0, "x/0=0");
|
||||
do_div(-56'sd99999, 56'sd0, "neg/0=0");
|
||||
// ---- divide by 1 / by self / smaller-than-divisor ----
|
||||
do_div( 56'sd123456789, 56'sd1, "x/1");
|
||||
do_div(-56'sd123456789, 56'sd1, "-x/1");
|
||||
do_div( 56'sd42, 56'sd42, "x/x=1");
|
||||
do_div( 56'sd3, 56'sd100, "3/100=0");
|
||||
do_div(-56'sd3, 56'sd100, "-3/100=0");
|
||||
// ---- edges: most-negative, large magnitudes (the <<16-folded gradient numerators) ----
|
||||
do_div( {1'b1,{(W-1){1'b0}}}, 56'sd1, "MIN/1");
|
||||
do_div( {1'b1,{(W-1){1'b0}}}, -56'sd1, "MIN/-1");
|
||||
do_div( 56'sh0FFFF_FFFF_FFFF, 56'sd131072, "bigpos/2^17");
|
||||
do_div(-56'sh0FFFF_FFFF_FFFF, 56'sd131072, "bigneg/2^17");
|
||||
|
||||
// ---- random sweep (both signs, dividers up to 32-bit like the determinant) ----
|
||||
for (int i=0;i<4000;i++) begin
|
||||
rn = {$random,$random}; rn = rn & {W{1'b1}};
|
||||
rd = $random; // ~32-bit determinant range, both signs
|
||||
if ((i%37)==0) rd = 0; // sprinkle zero divisors
|
||||
do_div(rn, rd, $sformatf("rand%0d", i));
|
||||
end
|
||||
|
||||
$display("[tb_gs_grad_divider] errors=%0d", errors);
|
||||
if (errors==0) $display("[tb_gs_grad_divider] PASS");
|
||||
else $display("[tb_gs_grad_divider] FAIL");
|
||||
$finish;
|
||||
end
|
||||
initial begin #5000000; $display("[tb_gs_grad_divider] GLOBAL TIMEOUT"); $finish; end
|
||||
endmodule
|
||||
Reference in New Issue
Block a user