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