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

module t (
    input clk
);

  by_width #(1) w1 (.clk(clk));
  by_width #(31) w31 (.clk(clk));
  by_width #(32) w32 (.clk(clk));
  by_width #(33) w33 (.clk(clk));
  by_width #(63) w63 (.clk(clk));
  by_width #(64) w64 (.clk(clk));
  by_width #(65) w65 (.clk(clk));
  by_width #(95) w95 (.clk(clk));
  by_width #(96) w96 (.clk(clk));
  by_width #(97) w97 (.clk(clk));

  reg signed [15:0] a;
  reg signed [4:0] b;

  reg signed [15:0] sr, srs, sl, sls;

  reg [15:0] b_s;
  reg [15:0] b_us;

  task check_s(input signed [7:0] i, input [7:0] expval);
    //$display("check_s %x\n", i);
    if (i !== expval) $stop;
  endtask
  task check_us(input signed [7:0] i, input [7:0] expval);
    //$display("check_us %x\n", i);
    if (i !== expval) $stop;
  endtask

  always @* begin
    sr = a >> b;
    srs = copy_signed(a) >>> b;
    sl = a << b;
    sls = a <<< b;
    // verilator lint_off WIDTH
    b_s = b >>> 4;  // Signed
    b_us = b[4:0] >>> 4;  // Unsigned, due to extract
    check_s(3'b111, 8'h07);
    check_s(3'sb111, 8'hff);
    check_us(3'b111, 8'h07);
    check_us(3'sb111, 8'hff);  // Note we sign extend ignoring function's input requirements
    // verilator lint_on WIDTH
  end

  reg signed [32:0] bug349;

  initial begin
  end
  integer i;
  initial begin
    if ((-1 >>> 3) != -1) $stop;  // Decimals are signed
    // verilator lint_off WIDTH
    if ((3'b111 >>> 3) != 0) $stop;  // Based numbers are unsigned
    if ((3'sb111 >>> 3) != -1) $stop;  // Signed based numbers
    // verilator lint_on WIDTH
    if ((3'sb000 > 3'sb000)) $stop;
    if (!(3'sb000 > 3'sb111)) $stop;
    if ((3'sb111 > 3'sb000)) $stop;
    if ((3'sb000 < 3'sb000)) $stop;
    if ((3'sb000 < 3'sb111)) $stop;
    if (!(3'sb111 < 3'sb000)) $stop;
    if (!(3'sb000 >= 3'sb000)) $stop;
    if (!(3'sb000 >= 3'sb111)) $stop;
    if ((3'sb111 >= 3'sb000)) $stop;
    if (!(3'sb000 <= 3'sb000)) $stop;
    if ((3'sb000 <= 3'sb111)) $stop;
    if (!(3'sb111 <= 3'sb000)) $stop;
    // When we multiply overflow, the sign bit stays correct.
    if ((4'sd2 * 4'sd8) != 4'd0) $stop;
    // From the spec:
    // verilator lint_off WIDTH
    i = -12 / 3;
    if (i !== 32'hfffffffc) $stop;
    i = -'d12 / 3;
    if (i !== 32'h55555551) $stop;
    i = -'sd12 / 3;
    if (i !== 32'hfffffffc) $stop;
    i = -4'sd12 / 3;
    if (i !== 32'h00000001) $stop;
    // verilator lint_on WIDTH

    // verilator lint_off WIDTH
    bug349 = 4'sb1111 - 1'b1;
    if (bug349 != 32'he) $stop;
  end

  function signed [15:0] copy_signed;
    input [15:0] ai;
    copy_signed = ai;
  endfunction

  integer cyc;
  initial cyc = 0;
  wire [31:0] ucyc = cyc;
  always @(posedge clk) begin
    cyc <= cyc + 1;
`ifdef TEST_VERBOSE
    $write("%x  %x %x %x %x  %x %x\n", cyc, sr, srs, sl, sls, b_s, b_us);
`endif
    case (cyc)
      0: begin
        a <= 16'sh8b1b;
        b <= 5'sh1f;  // -1
      end
      1: begin
        // Check spaces in constants
        a <= 16'sh8b1b;
        b <= 5'sh01;  // -1
      end
      2: begin
        a <= 16'sh8b1b;
        b <= 5'sh1e;  // shift AMOUNT is really unsigned
        if (ucyc / 1 != 32'd2) $stop;
        if (ucyc / 2 != 32'd1) $stop;
        if (ucyc * 1 != 32'd2) $stop;
        if (ucyc * 2 != 32'd4) $stop;
        if (ucyc * 3 != 32'd6) $stop;
        if (cyc * 32'sd1 != 32'sd2) $stop;
        if (cyc * 32'sd2 != 32'sd4) $stop;
        if (cyc * 32'sd3 != 32'sd6) $stop;
      end
      3: begin
        a <= 16'sh0048;
        b <= 5'sh1f;
        if (ucyc * 1 != 32'd3) $stop;
        if (ucyc * 2 != 32'd6) $stop;
        if (ucyc * 3 != 32'd9) $stop;
        if (ucyc * 4 != 32'd12) $stop;
        if (cyc * 32'sd1 != 32'sd3) $stop;
        if (cyc * 32'sd2 != 32'sd6) $stop;
        if (cyc * 32'sd3 != 32'sd9) $stop;
      end
      4: begin
        a <= 16'sh4154;
        b <= 5'sh02;
      end
      5: begin
        a <= 16'shc3e8;
        b <= 5'sh12;
      end
      6: begin
        a <= 16'sh488b;
        b <= 5'sh02;
      end
      9: begin
        $write("*-* All Finished *-*\n");
        $finish;
      end
      default: ;
    endcase
    case (cyc)
      0: ;
      1: if ({sr, srs, sl, sls, b_s, b_us} !== 96'sh0000_ffff_0000_0000_ffff_0001) $stop;
      2: if ({sr, srs, sl, sls, b_s, b_us} !== 96'sh458d_c58d_1636_1636_0000_0000) $stop;
      3: if ({sr, srs, sl, sls, b_s, b_us} !== 96'sh0000_ffff_0000_0000_ffff_0001) $stop;
      4: if ({sr, srs, sl, sls, b_s, b_us} !== 96'sh0000_0000_0000_0000_ffff_0001) $stop;
      5: if ({sr, srs, sl, sls, b_s, b_us} !== 96'sh1055_1055_0550_0550_0000_0000) $stop;
      6: if ({sr, srs, sl, sls, b_s, b_us} !== 96'sh0000_ffff_0000_0000_ffff_0001) $stop;
      7: if ({sr, srs, sl, sls, b_s, b_us} !== 96'sh1222_1222_222c_222c_0000_0000) $stop;
      8: ;
      9: ;
    endcase
  end
endmodule


module by_width (
    input clk
);
  parameter WIDTH = 1;

  reg signed i1;
  reg signed [62:0] i63;
  reg signed [64:0] i65;

  // verilator lint_off WIDTH
  wire signed [WIDTH-1:0] i1extp  /*verilator public*/ = i1;
  wire signed [WIDTH-1:0] i1ext = i1;
  wire signed [WIDTH-1:0] i63ext = i63;
  wire signed [WIDTH-1:0] i65ext = i65;
  // verilator lint_on WIDTH

  integer cyc;
  initial cyc = 0;
  always @(posedge clk) begin
    cyc <= cyc + 1;
    i1 <= cyc[0];
    i63 <= {63{cyc[0]}};
    i65 <= {65{cyc[0]}};
    case (cyc)
      1: begin
        if (i1extp != {WIDTH{1'b0}}) $stop;
        if (i1ext != {WIDTH{1'b0}}) $stop;
        if (i63ext != {WIDTH{1'b0}}) $stop;
        if (i65ext != {WIDTH{1'b0}}) $stop;
      end
      2: begin
        if (i1extp != {WIDTH{1'b1}}) $stop;
        if (i1ext != {WIDTH{1'b1}}) $stop;
        if (i63ext != {WIDTH{1'b1}}) $stop;
        if (i65ext != {WIDTH{1'b1}}) $stop;
      end
      default: ;
    endcase
  end
endmodule
