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): in1
→ tmp1
→ out1
and in2
→ tmp2
→ out2
. 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
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