// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// SPDX-FileCopyrightText: 2020 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0

// verilog_format: off
`define stop $stop
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d:  got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
// verilog_format: on

module t(/*AUTOARG*/
  // Inputs
  clk
  );
  input clk;

  integer cyc = 0;
  reg [63:0] crc;
  reg [63:0] sum;

  reg [127:0] in;

  check #(48) check48 (.*);
  check #(31) check31 (.*);
  check #(32) check32 (.*);
  check #(63) check63 (.*);
  check #(64) check64 (.*);
  check #(96) check96 (.*);
  check #(128) check128 (.*);

  always_comb begin
    if (crc[2:0] == 0) in = '0;
    else if (crc[2:0] == 1) in = ~'0;
    else if (crc[2:0] == 2) in = 128'b1;
    else if (crc[2:0] == 3) in = ~ 128'b1;
    else begin
      in = {crc, crc};
      if (crc[3]) in[31:0] = '0;
      if (crc[4]) in[63:32] = '0;
      if (crc[5]) in[95:64] = '0;
      if (crc[6]) in[127:96] = '0;
      if (crc[7]) in[31:0] = ~'0;
      if (crc[8]) in[63:32] = ~'0;
      if (crc[9]) in[95:64] = ~'0;
      if (crc[10]) in[127:96] = ~'0;
    end
  end

  // Test loop
  always @ (posedge clk) begin
`ifdef TEST_VERBOSE
    $write("[%0t] cyc==%0d in=%x\n", $time, cyc, in);
`endif
    cyc <= cyc + 1;
    crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]};
    if (cyc == 0) begin
      // Setup
      crc <= 64'h5aef0c8d_d70a4497;
      sum <= '0;
    end
    else if (cyc == 99) begin
      `checkr(check48.sum, 14574057015683440.000000);
      `checkr(check31.sum, 114141374814.000000);
      `checkr(check32.sum, 236547942750.000000);
      `checkr(check63.sum, 513694866079917670400.000000);
      `checkr(check64.sum, 1002533584033221181440.000000);
      `checkr(check96.sum, 4377373669974269260279175970816.000000);
      `checkr(check128.sum, 18358899571808044815012294240949812330496.000000);
      $write("*-* All Finished *-*\n");
      $finish;
    end
  end

endmodule

module check(/*AUTOARG*/
  // Inputs
  in, clk, cyc
  );
  parameter WIDTH = 128;
  input [127:0] in;

  wire [WIDTH-1:0] ci = in[WIDTH-1:0];
  wire signed [WIDTH-1:0] cis = in[WIDTH-1:0];

  real r;
  real rs;
  always_comb r = ci;
  always_comb rs = cis;

  input clk;
  input integer cyc;
  real          sum;

  always_ff @ (negedge clk) begin
`ifdef TEST_VERBOSE
    $write("[%0t] w%0d in=%h r=%f rs=%f sum=%f\n", $time, WIDTH, ci, r, rs, sum);
`endif
    if (cyc < 10) sum <= 0;
    else sum <= sum + r + rs;
  end
endmodule
