// 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