// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2004 by Wilson Snyder.

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

   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 'sh 8b1b; 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
