0
\$\begingroup\$

I'm seeing some where differences in circuit simulation when changing what should be an unrelated module. I'm trying to understand what optimizations are going on here to cause this:

// Multiplicand Load Register                                                                     
module mc (input  clkIn,                                                                                     
           input  rstIn,                                                                                     
           input  [7:0]multicIn,                                                                             
           input  ldMIn,                                                                                     
           output reg [7:0]multicOut);                                                                                                                                                             

  always @ (posedge clkIn)                                                                          
  begin                                                                                               
    if (rstIn)                                                                                          
      multicOut <= 8'b00000000;                                                                       
    else if (ldMIn)                                                                                     
      multicOut <= multicIn;                                                                        
  end                                                                                               
endmodule //mc                                                                                                                                                                                      

// Multiplier Shift Register                                                                      
module mp (input  clkIn,                                                                                     
           input  rstIn,                                                                                     
           input  [7:0]multipIn,                                                                             
           input  ldMIn,                                                                                     
           input  srPIn,                                                                                     
           input  irIn,                                                                                      
           output reg [7:0]prodLowOut);                                                                                                                                                             

  always @ (posedge clkIn)                                                                          
  begin                                                                                               
    if (rstIn)                                                                                          
      prodLowOut <= 8'b00000000;                                                                      
    else if (ldMIn)                                                                                      
      prodLowOut <= multipIn;                                                                         
    else if (srPIn)                                                                                     
      prodLowOut <= {irIn, prodLowOut[7:1]};                                                        
  end                                                                                               
endmodule //mp

If I simulate this as it is, the mc module loads a clock cycle early (seeming to infer a latch):

enter image description here

But if I comment out the shift register, else if srPIn, line in mp (effectively making them the same), then mc loads at the correct time:

enter image description here

My question is, why are changes in one module seeming to affect changes in another? Am I hitting some weird optimization area? Why am I inferring a latch where I shouldn't be? This seems to follow the correct rules for writing a register.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

I'm guessing your test bench stimulus is using blocking assignments and/or # delays before assigning stimulus values. Something like below.

initial begin
  clkIn = 1;
  forever #5 clkIn = !clkIn;
end
initial begin
  ldMIn = 1'b0;
  #20;
  ldMIn = 1'b1;
  #10;
  ldMIn = 1'b0;
end

The above example allows for a race condition in the Verilog scheduler. ldMIn and clkIn become one in the same time step, but the assignment and evaluation order is not deterministic. In your first waveform, ldMIn is being assigned before mc is triggred by the @(posedge clkIn) which is why multicOut is updated immediately. In the, in the second waveform the scheduler happened to reverse the order.

The Verilog language specifically allows non-determinism (up the to the vender how to implement). Making it your responsibility to enforce determinism when needed. The easiest way to do this in the test-bench is to use non-blocking assignment for synchronous data, just like RTL does. (See Blocking vs Non Blocking Assignments )

Assigning ldMIn and other non-clock synchronous signals with non-blocking should fix your issue. I would highly suggest one additional change; delay the assignments relative to @(posedge clkIn) instead of # delays. Doing so forces any assignment to be after the clock update and allows for easy scaling with the clock frequency.

initial begin
  clkIn = 1;
  forever #5 clkIn = !clkIn;
end
initial begin
  ldMIn = 1'b0; // blocking assignment okay for time 0 initialization
  #1; // tiny delay to mask possible posedge (x->1 transition) at time 0
  repeat(2) @(posedge clkIn); // delay relative to clock edge; not time
  ldMIn <= 1'b1; // non-blocking assignment 
  @(posedge clkIn); // delay realitve to clock
  ldMIn <= 1'b0; // non-blocking assignment
end
\$\endgroup\$
1
  • \$\begingroup\$ Thanks! This helped a bunch in clarifying blocking vs nonblocking and I never thought it would actually matter in the testbench. I come from a mostly VHDL background and I've never encountered anything like this. \$\endgroup\$
    – nbstrong
    Oct 10, 2019 at 2:00
0
\$\begingroup\$

It looks like you are changing your input values and the clock at exactly the same time, although we would need to see your testbench to be sure. That's a dangerous thing to do in real life or in a simulation. Try moving the changes in the input values by about a quarter of the clock period, after the rising clock edge.

\$\endgroup\$

Your Answer

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

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