`include "wally-config.vh"

/////////////
// counter //
/////////////
// module counter(input  logic clk, 
//                input  logic req, 
//                output logic done);
 
//    logic    [7:0]  count;

//   // This block of control logic sequences the divider
//   // through its iterations.  You may modify it if you
//   // build a divider which completes in fewer iterations.
//   // You are not responsible for the (trivial) circuit
//   // design of the block.

//   always @(posedge clk)
//     begin
//       if      (count == `DIVLEN + 2) done <= #1 1;
//       else if (done | req) done <= #1 0;	
//       if (req) count <= #1 0;
//       else     count <= #1 count+1;
//     end
// endmodule

///////////
// clock //
///////////
module clock(clk);
  output clk;
 
  // Internal clk signal
  logic clk;
 
endmodule

//////////
// testbench //
//////////
module testbench;
  logic               clk;
  logic               req;
  logic               done;
  logic               Int, Sqrt, Mod;
  logic [`XLEN-1:0]   a, b;
  logic [`NF-1:0]     afrac, bfrac;
  logic [`NE-1:0]     aExp, bExp;
  logic               asign, bsign;
  logic [`NF-1:0]     r;
  logic [`XLEN-1:0]   rInt;
  logic [`DIVLEN-1:0] Quot;
 
  // Test parameters
  parameter MEM_SIZE = 40000;
  parameter MEM_WIDTH = 64+64+64;
 
  // Test sizes
  `define memr  63:0 
  `define memb  127:64
  `define mema  191:128

  // Test logicisters
  logic [MEM_WIDTH-1:0] Tests [0:MEM_SIZE];  // Space for input file
  logic [MEM_WIDTH-1:0] Vec;  // Verilog doesn't allow direct access to a
                            // bit field of an array 
  logic [63:0] correctr, nextr, diffn, diffp;
  logic [10:0] rExp;
  logic        rsign;
  integer testnum, errors;

  // Equip Int, Sqrt, or IntMod test
  assign Int =  1'b0;
  assign Mod =  1'b0;
  assign Sqrt = 1'b1;

  // Divider
  srt srt(.clk, .Start(req), 
                .Stall(1'b0), .Flush(1'b0), 
                .XExp(aExp), .YExp(bExp), .rExp,
                .XSign(asign), .YSign(bsign), .rsign,
                .SrcXFrac(afrac), .SrcYFrac(bfrac), 
                .SrcA(a), .SrcB(b), .Fmt(2'b00), 
                .W64(1'b1), .Signed(1'b0), .Int, .Mod, .Sqrt, 
                .Result(Quot), .Flags(), .done);

  // Counter
  // counter counter(clk, req, done);


    initial
    forever
      begin
        clk = 1; #17;
        clk = 0; #16;
      end


  // Read test vectors from disk
  initial
    begin
      testnum = 0; 
      errors = 0;
      $readmemh ("sqrttestvectors", Tests);
      Vec = Tests[testnum];
      a = Vec[`mema];
      {asign, aExp, afrac} = a;
      b = Vec[`memb];
      {bsign, bExp, bfrac} = b;
      nextr = Vec[`memr];
      r = Quot[(`DIVLEN - 2):(`DIVLEN - `NF - 1)];
      rInt = Quot;
      req <= #5 1;
    end
  
  // Apply directed test vectors read from file.

  always @(posedge clk) begin
    r = Quot[(`DIVLEN - 2):(`DIVLEN - `NF - 1)];
    rInt = Quot;
    if (done) begin
      if (~Int & ~Sqrt) begin // This test case checks floating point division
        req <= #5 1;
        diffp = correctr[51:0] - r;
        diffn = r - correctr[51:0];
        if ((rsign !== correctr[63]) | (rExp !== correctr[62:52]) | ($signed(diffn) > 1) | ($signed(diffp) > 1) | (diffn === 64'bx) | (diffp === 64'bx)) // check if accurate to 1 ulp
          begin
            errors = errors+1;
            $display("result was %h_%h, should be %h %h %h\n", rExp, r, correctr, diffn, diffp);
            $display("failed\n");
            $stop;
          end
        if (afrac === 52'hxxxxxxxxxxxxx)
          begin
            $display("%d Tests completed successfully", testnum);
            $stop;
          end
      end else if (~Sqrt) begin // This test case works for both integer divide and integer modulo
        req <= #5 1;
        diffp = correctr[63:0] - rInt;
        if (($signed(diffp) != 0) | (diffp === 64'bx)) // check if accurate to 1 ulp
          begin
            errors = errors+1;
            $display("result was %h, should be %h %h\n", rInt, correctr, diffp);
            $display("failed\n");
          end
        if (afrac === 52'hxxxxxxxxxxxxx)
        begin
          $display("%d Tests completed successfully", testnum - errors);
          $stop;
        end
      end else begin // This test case verifies square root
        req <= #5 1;
        diffp = correctr[51:0] - r;
        diffn = r - correctr[51:0];
        if ((rExp !== correctr[62:52]) | ($signed(diffn) > 1) | ($signed(diffp) > 1) | (diffn === 64'bx) | (diffp === 64'bx)) // check if accurate to 1 ulp
          begin
            errors = errors + 1;
            $display("result was %h, should be %h %h %h\n", r, correctr, diffn, diffp);
            $display("failed\n");
          end
        if (afrac === 52'hxxxxxxxxxxxxx) begin 
          $display("%d Tests completed successfully", testnum-errors);
          $stop; end 
      end
    end
    if (req) begin
      req <= #5 0;
      correctr = nextr;
      testnum = testnum+1;
      Vec = Tests[testnum];
      $display("a = %h  b = %h",a,b);
      a = Vec[`mema];
      {asign, aExp, afrac} = a;
      b = Vec[`memb];
      {bsign, bExp, bfrac} = b;
      nextr = Vec[`memr];
    end
  end
endmodule