1
\$\begingroup\$

So I'm still learning test benches and this one is stumping me. I wrote a module to do 32bit multiplication and was able to get a testbench working. I then tried a simple conversion to make the module handle addition/subtraction and modified the test bench. For some reason the output from the module is coming back an 'x' but I can't see the bug. Help would be appreciated.

The module does sum & diff (2s complement subtraction) with no overflow, so I just pass the last 32 bits along.

I'm running this under VCS 2014.12 with the following options: -timescale=1ns/1ns +vcs+flush+all +warn=all -sverilog

module address_sum_diff(i_Aj, i_Ak, i_Instr, clk, o_Ai);
parameter size = 32; //Size is the width of adder
parameter level = 3; //Number of pipeline stages

input wire[size-1:0] i_Aj; //Aj wire
input wire[size-1:0] i_Ak; //Ak wire
input wire[6:0] i_Instr;   //Instr wire
input wire clk;            //Clock signal

output reg[size-1:0] o_Ai; //Ai register (No Overflow)

reg [size-1:0] Aj_int;            //Aj temp register
reg [size-1:0] Ak_int;            //Ak temp register
reg [6:0] Instr_int;              //Instr temp register
reg [size-1:0] Ai_int[level:1];   //Ai temp register
integer iCount;                   //Temp counter

assign o_Ai = Ai_int[level-1][31:0];//Move LSB only

always @(posedge clk)
 begin
  // Registering input of the adder
  Aj_int <= i_Aj;
  Ak_int <= i_Ak;
  Instr_int <= i_Instr;
  case(Instr_int[6:0])
   7'o020:Ai_int[0] <= Ak_int[size-1:0] + Aj_int[size-1:0];          //addition
   7'o021:Ai_int[0] <= Aj_int[size-1:0] + ~Ak_int[size-1:0] + 32'b1; //two's complement subtraction
  endcase
  // 'level' levels of registers to be inferred at the output of the multiplier
  for(iCount=1;iCount<level;iCount =iCount +1)
   Ai_int [iCount] <= Ai_int [iCount-1];
  end

   endmodule

The test bench is as follows

//Test Bench
module address_sum_diff_tb;
 parameter size = 32; //Width of adder
 parameter level = 3; //Stages in the pipelined adder

 reg [31:0] i_Aj;  //Aj register (input)
 reg [31:0] i_Ak;  //Ak register (input)
 reg [6:0] i_Instr;//Instr register (input) 

 reg clk;          //Clock signal (input)
 wire [31:0] o_Ai; //Ai register (output)

 //Temp registers & variables
 reg [31:0] Aj_temp [level:0];   //Aj temp register array
 reg [31:0] Ak_temp [level:0];   //Ak temp register array
 reg [31:0] Ai_temp [level:0];   //Ai temp register array
 reg [6:0] Instr_temp [level:0]; //Instr temp register array
 real i; //Temp counter
 real j; //Temp counter
 int k; //Temp counter

 //Initialize values
 initial begin
  clk <= 1'b0;
  i_Aj <= 32'b0;
  i_Ak <= 32'b0;
  i_Instr <= 7'b0;
 end

 //Cycle through all test cases
 always @(posedge clk)
  begin   
   i_Instr <=7'o020;
   for (i=1;i<15;i=i+1)
    begin
     for (j=1;j<15;j=j+1)
      begin
       i_Aj <= i;
       i_Ak <= j;
       Aj_temp[0] <= i_Aj;
       Ak_temp[0] <= i_Ak;          
       Instr_temp[0] <= i_Instr;
       @(posedge clk);
       for(k=1;k<level+1;k=k+1) 
        begin
         Instr_temp[k] <= Instr_temp[k-1];
         Aj_temp[k] <= Aj_temp [k-1];
         Ak_temp[k] <= Ak_temp [k-1];
         Ai_temp[k] <= Aj_temp [k-1] + Ak_temp [k-1];
        end
      end
    end
    $finish;
  end

 //Generate clock 
 always #1 clk <= ~clk;

 //Alert on self-check error
 always @(Ai_temp[level])
  begin
    if (o_Ai!==Ai_temp[level])
    begin
      $monitor("ERROR: %0d,\t%0o,\t%0d,\t%0d,\t%0d,\t%0d",$time, Instr_temp[level],Aj_temp[level], Ak_temp[level], o_Ai, Ai_temp[level]);
    end
  end

 //Log output 
 initial begin
  $dumpfile ("dump.vcd"); 
  $dumpvars; 
 end 

 //Output data to terminal     
  initial begin
    $display("\t\ttime,\tInstr,\tAj,\tAk,\tAi\tAiTmp"); 
    $monitor("%d,\t%0o,\t%0d,\t%0d,\t%0d,\t%0d",$time, Instr_temp[level], Aj_temp[level], Ak_temp[level], o_Ai, Ai_temp[level]); 
  end 

 //Initialize DUT
 address_sum_diff test_address_sum_diff (i_Aj, i_Ak, i_Instr, clk, o_Ai);
endmodule
\$\endgroup\$
6
  • \$\begingroup\$ Any particular reason you are using real for i and j in the testbench? \$\endgroup\$ Oct 29, 2015 at 20:25
  • 1
    \$\begingroup\$ Not an answer to your problem, but a comment: I think you misunderstand the $monitor statement. You shouldn't need to put it in an always block with an if check around it. Use $display or $strobe there instead. \$\endgroup\$
    – Bill Nace
    Oct 29, 2015 at 20:51
  • \$\begingroup\$ @bill I usually use $display and do be honest I don't recall why I have $monitor there. I think I was properly using it, but then wanted to do some auto checking and wrapped it in the if statement without changing it. \$\endgroup\$
    – J Kula
    Oct 29, 2015 at 20:55
  • \$\begingroup\$ @Tom, yes originally I had an integer but I needed to put 2^32 -1 in the value and int is signed. I tried using Int unsigned, but for some reason VCS didn't seem to care and still treated it as signed so switching to real let me get 2^32-1 in the loop without any issue. Seems like a quirk in VCS with the signed/unsigned int. I'm pretty sure I was using the notation correctly... just wasn't working. \$\endgroup\$
    – J Kula
    Oct 29, 2015 at 21:03
  • \$\begingroup\$ just stick reg [31:0], that will get you the required range. \$\endgroup\$ Oct 29, 2015 at 21:14

2 Answers 2

1
\$\begingroup\$

Found it, bug was in the verilog.

reg [size-1:0] Ai_int[level:1];   //Ai temp register

I was assigning to Ai_int[0]. The line should be:

reg [size-1:0] Ai_int[level:0];   //Ai temp register
\$\endgroup\$
0
\$\begingroup\$

I think you are updating Ai_int multiple times in the same always block , so it is taking the updated value, i.e don't use for loop and also there is no such memory like Ai_int[0] as you have declared it as [3:1].

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.