Delay modelling is how an HDL simulation represents the time a gate or wire takes to respond. The two models that matter in practice are inertial delay, where pulses shorter than the delay are swallowed, and transport delay, where every input change appears at the output after the delay, however short. In Verilog, a delayed continuous assignment gives inertial behaviour, and a delay on the right-hand side of a nonblocking assignment gives transport behaviour. Delays placed anywhere else inside an always block usually give wrong timing and should be avoided.
This post explains each delay model, then sets out coding guidelines for design models and testbenches, with a small example that you can simulate.
Key takeaways
- Inertial delay filters glitches shorter than the delay. Transport delay passes every pulse through, shifted in time.
- Delta delay is the zero-time step a simulator uses to order events within one time point.
- For combinational logic, use
assign #dor a zero-delay always block feeding a delayedassign. - Use
q <= #d valueonly when you want transport behaviour or a clock-to-output delay on a flop. - Never put
#don the left of an assignment inside an always block that models logic. The block stops listening during the delay and misses input changes. - Synthesis tools ignore all
#delays. They exist for simulation only.
Types of delay model
In digital logic design there are several delay models. The commonly used ones are below.
Inertial delay model
Inertial delay takes into account how long the input has been stable before it changes the output. The output does not change unless the input stays at its new value for at least the delay period. A pulse narrower than the delay is rejected. This matches a real gate, which needs a minimum amount of energy at its input to switch, so it is sometimes described as the realistic delay model (the original version of this post also called it event delay, a name used in some texts). It is the default in VHDL (y <= a after 5 ns;) and the behaviour of Verilog continuous assignments and gate primitives.
Transport delay model
Transport delay represents the time a signal takes to propagate through a wire or gate with no filtering. The output follows the input exactly, after a time equal to the propagation delay, so even very short pulses get through. It is the right model for wires, delay lines and long interconnect. In VHDL it is written y <= transport a after 5 ns;.
Delta delay model
Delta delay is a zero-time delay used for events that occur in the current simulation time. When a signal is assigned with no delay, the simulator still processes the update one delta cycle later, which keeps the order of events consistent within a single time point. The term is used mainly in VHDL; Verilog has a similar idea in its event regions (active, inactive, nonblocking update).
Pure delay model
Pure delay is a fixed delay between two points in a circuit that does not depend on the input signals. It shifts the waveform by a constant amount and, like transport delay, does not filter pulses. Many texts treat pure delay and transport delay as the same thing.
| Model | Filters short pulses? | Typical use | Verilog style | VHDL style |
|---|---|---|---|---|
| Inertial | Yes, pulses shorter than the delay | Gates, combinational logic | assign #5 y = a & b; | y <= a and b after 5 ns; |
| Transport / pure | No | Wires, delay lines | y <= #5 a & b; in an always block | y <= transport a after 5 ns; |
| Delta | Not applicable (zero time) | Event ordering in zero-delay models | Event regions | Delta cycles |
General coding practices for delays
Here are some coding practices to follow when modelling delays in digital logic.
- Use the delay model that reflects the behaviour of the circuit being modelled. The choice depends on the type of circuit and the level of accuracy required.
- Specify delays using explicit delay syntax, such as
#in Verilog or theafterkeyword in VHDL, rather than relying on implicit delays. - Use comments to describe the purpose of each delay and any assumptions behind it.
- Use named constants or parameters for delay values rather than hard-coding them.
- Make sure the delay values are consistent with the data sheets of the components being modelled.
- Simulate the circuit with different input patterns, including narrow pulses, to verify the delay modelling.
- Use simulation tools that support the delay models you need and can simulate the circuit behaviour accurately.
- Remember that RTL delays are not timing analysis. Real path delays come from the library and are checked by static timing analysis and gate-level simulation with SDF back-annotation.
Verilog modelling guidelines
The Verilog guidelines below follow the widely cited paper by Clifford E. Cummings, "Correct Methods for Adding Delays to Verilog Behavioral Models" (HDLCON 1999).
- Do not place delays on the LHS or RHS of blocking assignments to model combinational logic.
- Do not place delays on the LHS of nonblocking assignments to model combinational logic.
- Place delays on the RHS of nonblocking assignments only when you want to model transport output-propagation behaviour. This style accurately models delay lines and combinational logic with pure transport delays, but it generally makes simulation slower.
- In general, do not place delays on the RHS of nonblocking assignments to model combinational logic. The style can be confusing and is not very simulation efficient. It is, however, a common and useful practice to place delays on the RHS of nonblocking assignments to model clock-to-output behaviour on sequential logic.
- Use continuous assignments with delays to model simple combinational logic. This style accurately models combinational logic with inertial delays.
- Use always blocks with no delays to model complex combinational logic that is easier to express with behavioural constructs such as
case,casez,casexandif-else. Drive the outputs of these zero-delay always blocks into continuous assignments to apply the delays. This style also models complex combinational logic with inertial delays.
Example: three delay styles side by side
The model below implements the same AND gate three ways with a 5 ns delay. The testbench applies a 10 ns pulse, a 2 ns pulse, and a short burst of changes.
`timescale 1ns/1ns
module delay_styles (input wire a, b, output wire y_inertial, output reg y_transport, output reg y_lhs);
localparam TPD = 5;
// Recommended: continuous assignment with delay (inertial)
assign #TPD y_inertial = a & b;
// Transport delay: RHS delay on a nonblocking assignment
always @(a or b) y_transport <= #TPD a & b;
// Not recommended: LHS delay in an always block
always @(a or b) #TPD y_lhs = a & b;
endmodule
module tb;
reg a = 0, b = 1;
wire yi, yt, yl;
delay_styles dut (.a(a), .b(b), .y_inertial(yi), .y_transport(yt), .y_lhs(yl));
initial begin
$monitor("%4t a=%b inertial=%b transport=%b lhs=%b", $time, a, yi, yt, yl);
#10 a = 1; // wide pulse, 10 ns
#10 a = 0;
#10 a = 1; // narrow pulse, 2 ns (shorter than TPD)
#2 a = 0;
#8 a = 1; // t=40
#2 a = 0; // t=42
#2 a = 1; // t=44, then stays high
#16 $finish;
end
endmodule
Output from Icarus Verilog (times in ns):
0 a=0 inertial=x transport=x lhs=x
5 a=0 inertial=0 transport=0 lhs=0
10 a=1 inertial=0 transport=0 lhs=0
15 a=1 inertial=1 transport=1 lhs=1
20 a=0 inertial=1 transport=1 lhs=1
25 a=0 inertial=0 transport=0 lhs=0
30 a=1 inertial=0 transport=0 lhs=0
32 a=0 inertial=0 transport=0 lhs=0
35 a=0 inertial=0 transport=1 lhs=0
37 a=0 inertial=0 transport=0 lhs=0
40 a=1 inertial=0 transport=0 lhs=0
42 a=0 inertial=0 transport=0 lhs=0
44 a=1 inertial=0 transport=0 lhs=0
45 a=1 inertial=1 transport=1 lhs=1
47 a=1 inertial=0 transport=0 lhs=1
49 a=1 inertial=1 transport=1 lhs=1
Reading the result:
- 10 ns pulse (10 to 20 ns): all three styles show it from 15 to 25 ns, as expected.
- 2 ns pulse (30 to 32 ns): the inertial output ignores it. The transport output reproduces it from 35 to 37 ns.
- Burst at 40, 42 and 44 ns: the input finally settles high at 44 ns, so a correct 5 ns gate should go high at 49 ns. The inertial output does. The LHS-delay version goes high at 45 ns, 4 ns early, because the always block was stuck in its
#5wait during the changes at 42 and 44 ns and then simply sampled whatever value was present at 45 ns.
The transport output rises at 45 ns, falls at 47 ns and rises again at 49 ns, copying each input edge 5 ns later.
Testbench guidelines
- Placing delays on the LHS of blocking assignments in a testbench is reasonable, because the delay is only used to space out sequential stimulus events. Placing a delay on the RHS of a blocking assignment is confusing and poor style.
- Nonblocking assignments are less efficient to simulate than blocking assignments, so placing delays on the LHS of nonblocking assignments, for either modelling or stimulus, is generally discouraged.
- RHS delays on nonblocking assignments are sometimes used in testbenches when stimulus must be scheduled on future clock edges or after a set delay, without blocking later stimulus in the same procedural block. Some multi-clock verification suites benefit from several nonblocking assignments with RHS delays. Because the style is easy to misread, it is still not generally recommended.
- Continuous assignments can be used anywhere in a testbench to drive stimulus onto input ports and bidirectional ports of instantiated models.
Common mistakes
- Writing
always @(a or b) #5 y = a & b;and expecting a 5 ns gate. As the example shows, events are missed and the timing is wrong. - Adding
#1to every flop assignment to "fix" a race. Races between blocking and nonblocking assignments should be fixed by using nonblocking assignments for sequential logic, not by delays. - Expecting synthesis to honour
#delays. It ignores them, sometimes with a warning, so the netlist will not match an RTL simulation that relied on them. - Mixing inertial and transport styles in one model without saying so. Comment the intent.
How interviewers probe this topic
- "What is the difference between inertial and transport delay?" Expect to explain pulse rejection and give one example of each.
- "What happens if a 2 ns pulse goes into
assign #5?" It is filtered out. - "Why should you avoid
#5on the LHS in an always block?" The block cannot see input changes during the wait. - "Where is
q <= #1 d;acceptable?" As a clock-to-output delay in a flop model, to make waveforms easier to read.
FAQ
Does Verilog have a transport keyword like VHDL?
No. Transport behaviour is obtained with an RHS delay on a nonblocking assignment. Some simulators also offer options for path pulse rejection in specify blocks.
Are gate primitive delays inertial?
Yes. Built-in primitives such as and #5 (y, a, b); behave inertially, like delayed continuous assignments.
Do these delays matter for synthesis?
No. They only affect simulation. Timing in silicon is set by the cell library and checked with static timing analysis.
Conclusions
Any delay added to statements inside an always block does not accurately model hardware behaviour and should be avoided. The one exception is a carefully placed delay on the right-hand side of a nonblocking assignment, which accurately models transport delay, generally at some cost in simulator performance.
Adding delays to continuous assignments, or modelling complex logic with no delays inside an always block and driving the outputs through delayed continuous assignments, accurately models inertial delay. These are the recommended styles for modelling combinational logic.
Please leave a comment if you have any further questions.


Your comments will be moderated before it appears here.