1
\$\begingroup\$

I am having trouble with simulation of the nonblocking assignment delay in the always block.

A simple example: assignment of the input in to an intermediate wire tmp, which in turn is used to set the output register out on a rising clock edge.

As far as I know, in a hardware implementation of such a module, the tmp signal will switch almost immediately, i.e., in the same clock cycle as in changes. On the other hand, the out signal will switch one clock cycle after tmp (and this is what I usually observe on the ILA core). However, I am not always able to properly simulate this delay.

For example, I simulated two such systems in Xilinx Vivado (see the code below): in1tmp1out1 and in2tmp2out2. The only difference is in the testbench: in2 is generated using an additional @ (posedge clk) expression. The waveforms of in1 and in2 appear to be identical, but somehow they cause a different effect: out2 does appear with the expected delay, while out1 does not.

Additionally, if the intermediate signal tmp2 is removed (and the assignment on a rising clock edge is out2 <= in2), the delay of out2 also disappears. This makes me a bit confused, as I do not understand why such a simple continuous assignment would affect the timing to a degree that the delay vanishes.

I wonder how can this effect be reliably controlled. Specifically, I would like the simulated waveforms to work in line with the signals that occur in the hardware. This would speed up the debugging process as with minor changes I could rely on the simulation results, and it would no longer require re-synthesizing the entire project.

Simulation result

Simulation result.

Source code

test_module.v:

`timescale 1ns / 1ps

module test_module (
  input clk, in1, in2,
  output tmp1, tmp2,
  output reg out1 = 1'b0,
  output reg out2 = 1'b0
);
  
  assign tmp1 = in1, tmp2 = in2;
  
  always @ (posedge clk) begin
    out1 <= tmp1;
    out2 <= tmp2;
  end
  
endmodule

test_module_tb.v:

`timescale 1ns / 1ps

module test_module_tb;
  
  localparam integer period = 10;
  localparam integer cycle = 2 * period;
  
  reg clk = 1'b1,
      in1 = 1'b0,
      in2 = 1'b0;
  
  wire tmp1, tmp2, out1, out2;
  
  always #(period/2) clk = ~clk;
  always #(cycle) in1 = ~in1;
  always #(cycle) @(posedge clk) in2 = ~in2;
  
  test_module UUT (.clk(clk), .in1(in1), .in2(in2), .tmp1(tmp1), .tmp2(tmp2), .out1(out1), .out2(out2));
  
endmodule

Schematic

Schematic.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

You get unreliable simulation results because you have a race condition in the testbench code. I was unable to reproduce your waves on 2 different simulators (I saw no delay on either output).

Although the inputs are changing at the same time as the clock rising edge, from a Verilog simulator perspective, they have a race condition.

One approach is to assume the inputs are synchronous to the clock. In that case, drive the inputs in the testbench on the posedge of the clock and use nonblocking assignments, just like you drive the outputs of your design module.

module test_module_tb;
  
  localparam integer period = 10;
  localparam integer cycle = 2 * period;
  
  reg clk = 1'b1,
      in1 = 1'b0,
      in2 = 1'b0;
  
  wire tmp1, tmp2, out1, out2;
  
  always #(period/2) clk = ~clk;

  reg [1:0] cnt = 0;
  always @(posedge clk) begin
    if (cnt == 1) begin
        cnt <= 0;
    end else begin
        cnt <= cnt + 1;
    end
  end

  always @(posedge clk) begin
    if (cnt == 0) begin
        in1 <= ~in1;
        in2 <= ~in2;
    end
  end
  
  test_module UUT (.clk(clk), .in1(in1), .in2(in2), .tmp1(tmp1), .tmp2(tmp2), .out1(out1), .out2(out2));
  
endmodule

Now both inputs are synchronous to the clock.

enter image description here

I created a counter in the testbench (cnt); you can adjust it to correspond to your cycle parameter.

\$\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.