Digital signals are treated as 0s and 1s, but in real hardware a gate output does not change at the same instant its inputs do. Transistors need time to charge and discharge the output, so every gate has a propagation delay. Verilog lets you attach these delays to gate primitives, so that a simulation shows not only what a circuit computes, but also when each output changes.
10 min read | Beginner Level
What You'll Learn
- The difference between rise, fall and turn-off delays
- How to specify one, two or three delays on a primitive, and which delay applies to each transition
- How min:typ:max delays model the spread between fast and slow chips
- Why short pulses can disappear, and why synthesis ignores all of these delays
Rise, Fall and Turn-Off Delays
An output can change in different directions, and real gates are usually faster in one direction than the other. Verilog therefore lets you give each kind of transition its own delay:
| Delay | Transition | Meaning |
|---|---|---|
| Rise delay | 0, x or z to 1 | Time for the output to rise to 1 |
| Fall delay | 1, x or z to 0 | Time for the output to fall to 0 |
| Turn-off delay | 0, 1 or x to z | Time for a tri-state output to stop driving and go to high impedance |

A transition to x uses the smallest of the delays given, because the simulator reports an unknown value as early as it could possibly appear. Delays can be applied to nets as well as gate outputs, but this article focuses on primitives.
Synthesis result: None. Synthesis tools ignore every # delay in the design, usually with a warning. The real delays of the synthesized circuit come from the target library and from the placed and routed layout, not from numbers in the Verilog code. Gate delays are a simulation feature: they are used in testbench models, in gate-level netlists that carry timing, and to make waveforms easier to read.
Gate-Level Simulation with Real Timing
After layout, timing tools calculate the actual delay of every cell and wire in the chip and write them to a delay file. Verification engineers load that file into a gate-level simulation of the netlist, which replaces the delays of each cell instance with these real values. This catches problems that zero-delay RTL simulation cannot show, such as a reset that arrives too late or a glitch on an asynchronous signal.
Delay Specification Format
A delay is written after the gate type and before the instance name. One, two or three values can be given:
// Single delay specified - used for all three types of transition delays
or #(<delay>) o1 (out, a, b);
// Two delays specified - used for Rise and Fall transitions
or #(<rise>, <fall>) o1 (out, a, b);
// Three delays specified - used for Rise, Fall and Turn-off transitions
or #(<rise>, <fall>, <turn_off>) o1 (out, a, b);
When fewer than three values are given, the missing ones are derived from the others:
| Format | Rise | Fall | Turn-off | To x |
|---|---|---|---|---|
#(d) | d | d | d | d |
#(r, f) | r | f | smaller of r and f | smaller of r and f |
#(r, f, t) | r | f | t | smallest of r, f and t |
Gates whose output can never be z, such as and, or, xor, buf and not, accept at most two delays, since a turn-off delay means nothing for them. The three-delay format is for tri-state primitives such as bufif0, bufif1, notif0 and notif1.
One Delay Format
The design below has an AND gate with a delay of 2 time units and a bufif0 with a delay of 3. The bufif0 drives a onto out2 when its control input b is 0, and drives z when b is 1.
module des ( input a, b,
output out1, out2);
// AND gate has 2 time unit gate delay
and #(2) o1 (out1, a, b);
// BUFIF0 gate has 3 time unit gate delay
bufif0 #(3) b1 (out2, a, b);
endmodule
The testbench changes one input every 10 time units, which is longer than any of the delays, so each output change can be traced back to one input change.
module tb;
reg a, b;
wire out1, out2;
des d0 (.out1(out1), .out2(out2), .a(a), .b(b));
initial begin
{a, b} <= 0;
$monitor ("T=%0t a=%0b b=%0b and=%0b bufif0=%0b", $time, a, b, out1, out2);
#10 a <= 1;
#10 b <= 1;
#10 a <= 0;
#10 b <= 0;
end
endmodule
ncsim> run T=0 a=0 b=0 and=x bufif0=x T=2 a=0 b=0 and=0 bufif0=x T=3 a=0 b=0 and=0 bufif0=0 T=10 a=1 b=0 and=0 bufif0=0 T=13 a=1 b=0 and=0 bufif0=1 T=20 a=1 b=1 and=0 bufif0=1 T=22 a=1 b=1 and=1 bufif0=1 T=23 a=1 b=1 and=1 bufif0=z T=30 a=0 b=1 and=1 bufif0=z T=32 a=0 b=1 and=0 bufif0=z T=40 a=0 b=0 and=0 bufif0=z T=43 a=0 b=0 and=0 bufif0=0 ncsim: *W,RNQUIE: Simulation is complete.
Both outputs start at x, because a gate output has no value until its first delay has passed. After that, every change of and appears 2 units after the input change that caused it (T=2, 22 and 32), and every change of bufif0 appears 3 units after (T=3, 13, 23 and 43). With a single delay, the direction of the change makes no difference.
Quick Check
At T=30, a falls to 0. Why does bufif0 not change 3 units later?
Show Answer
At T=30, b is still 1, so the bufif0 is disabled and its output stays at z no matter what a does. A delay only applies when the output value actually changes. The output changes again at T=43, 3 units after b returns to 0 at T=40.
Two Delay Format
The same testbench is now applied to a design with separate rise and fall delays. The AND gate rises in 2 units and falls in 3, and the bufif0 rises in 4 and falls in 5.
module des ( input a, b,
output out1, out2);
and #(2, 3) o1 (out1, a, b); // rise = 2, fall = 3
bufif0 #(4, 5) b1 (out2, a, b); // rise = 4, fall = 5, turn-off = 4
endmodule
ncsim> run T=0 a=0 b=0 and=x bufif0=x T=3 a=0 b=0 and=0 bufif0=x T=5 a=0 b=0 and=0 bufif0=0 T=10 a=1 b=0 and=0 bufif0=0 T=14 a=1 b=0 and=0 bufif0=1 T=20 a=1 b=1 and=0 bufif0=1 T=22 a=1 b=1 and=1 bufif0=1 T=24 a=1 b=1 and=1 bufif0=z T=30 a=0 b=1 and=1 bufif0=z T=33 a=0 b=1 and=0 bufif0=z T=40 a=0 b=0 and=0 bufif0=z T=45 a=0 b=0 and=0 bufif0=0 ncsim: *W,RNQUIE: Simulation is complete.
Each change now uses the delay for its direction:
andgoes from x to 0 at T=3 and from 1 to 0 at T=33, using the fall delay of 3. It rises at T=22, using the rise delay of 2.bufif0falls to 0 at T=5 and T=45 (fall delay 5), and rises to 1 at T=14 (rise delay 4).bufif0turns off at T=24. No turn-off delay was given, so the simulator uses the smaller of rise and fall, which is 4.
Three Delay Format
The bufif0 can take a third delay for its turn-off transition. The AND gate keeps its two delays, because it cannot drive z.
module des ( input a, b,
output out1, out2);
and #(2, 3) o1 (out1, a, b); // rise = 2, fall = 3
bufif0 #(5, 6, 7) b1 (out2, a, b); // rise = 5, fall = 6, turn-off = 7
endmodule
ncsim> run T=0 a=0 b=0 and=x bufif0=x T=3 a=0 b=0 and=0 bufif0=x T=6 a=0 b=0 and=0 bufif0=0 T=10 a=1 b=0 and=0 bufif0=0 T=15 a=1 b=0 and=0 bufif0=1 T=20 a=1 b=1 and=0 bufif0=1 T=22 a=1 b=1 and=1 bufif0=1 T=27 a=1 b=1 and=1 bufif0=z T=30 a=0 b=1 and=1 bufif0=z T=33 a=0 b=1 and=0 bufif0=z T=40 a=0 b=0 and=0 bufif0=z T=46 a=0 b=0 and=0 bufif0=0 ncsim: *W,RNQUIE: Simulation is complete.
The waveform below shows the same run. The bufif0 rises 5 units after T=10, turns off 7 units after T=20, and falls 6 units after T=40, so all three of its delays are visible.
Quick Check
If the bufif0 in the three-delay design were changed to bufif0 #(5, 6) b1 (out2, a, b);, at what time would out2 go to z?
Show Answer
At T=25. Without a third value, the turn-off delay is the smaller of rise and fall, which is 5, and b rises at T=20.
Shared Tri-State Buses
When several devices share one bus line through tri-state drivers, one driver must turn off before the next one turns on, or both will drive the line at the same time. Designers of such buses compare the turn-off delay of one driver with the turn-on delay of the next to check that there is no overlap. A model with separate turn-off delays shows this overlap in simulation as an x on the bus.
Min/Typ/Max Delays
Delays are not the same on every chip. They change with the manufacturing process, the supply voltage and the temperature, so a gate that takes 3 ns on one chip may take 2 ns on a fast chip and 4 ns on a slow one. Verilog lets each delay value be written as a min:typ:max triple to cover this range. These values usually come from the cell library provided with the manufacturing process.
#(<rise_min>:<rise_typ>:<rise_max>, <fall_min>:<fall_typ>:<fall_max>, <off_min>:<off_typ>:<off_max>)
Each of the rise, fall and turn-off delays gets its own triple:
module des ( input a, b,
output out1, out2);
and #(1:2:3, 3:4:5) o1 (out1, a, b);
bufif0 #(5:6:7, 6:7:8, 7:8:9) b1 (out2, a, b);
endmodule
ncsim> run T=0 a=0 b=0 and=x bufif0=x T=4 a=0 b=0 and=0 bufif0=x T=7 a=0 b=0 and=0 bufif0=0 T=10 a=1 b=0 and=0 bufif0=0 T=16 a=1 b=0 and=0 bufif0=1 T=20 a=1 b=1 and=0 bufif0=1 T=22 a=1 b=1 and=1 bufif0=1 T=28 a=1 b=1 and=1 bufif0=z T=30 a=0 b=1 and=1 bufif0=z T=34 a=0 b=1 and=0 bufif0=z T=40 a=0 b=0 and=0 bufif0=z T=47 a=0 b=0 and=0 bufif0=0 ncsim: *W,RNQUIE: Simulation is complete.
The simulator picks one value from each triple, and by default it uses the typical (middle) value. The log matches the typical delays exactly:
| Output | Transition | Typical delay | Input change | Output change |
|---|---|---|---|---|
| and | fall (x to 0) | 4 | T=0 | T=4 |
| and | rise | 2 | T=20 | T=22 |
| and | fall | 4 | T=30 | T=34 |
| bufif0 | fall (x to 0) | 7 | T=0 | T=7 |
| bufif0 | rise | 6 | T=10 | T=16 |
| bufif0 | turn-off | 8 | T=20 | T=28 |
| bufif0 | fall | 7 | T=40 | T=47 |
To run with the minimum or maximum values instead, select them when you start the simulator. Most simulators accept a command-line option such as +mindelays, +typdelays or +maxdelays, so the same code can be checked at both ends of the range without editing it.
Process Corners
Chips are checked at several "corners", each a combination of process, voltage and temperature. The slow corner, with maximum delays, shows whether signals still arrive before the next clock edge. The fast corner, with minimum delays, shows whether a signal arrives so early that it disturbs data being captured at the same edge. Running a simulation with min and max delays is the simplest form of the same idea.
Inertial Delay: Short Pulses Are Filtered
Gate delays in Verilog are inertial: an input pulse that is shorter than the gate's delay does not appear at the output. This models a real gate, which needs a minimum amount of time to switch its output fully.
module pulse_demo;
reg a, b;
wire out;
and #3 o1 (out, a, b);
initial begin
a = 0; b = 1;
#10 a = 1; // 2 unit pulse on a, shorter than the delay of 3
#2 a = 0;
#10 a = 1; // 5 unit pulse on a, longer than the delay
#5 a = 0;
end
endmodule
At T=10, the AND gate schedules out to become 1 at T=13. At T=12, a returns to 0 before that happens, so the simulator cancels the pending change and out stays 0. The second pulse starts at T=22 and lasts 5 units, so out rises at T=25 and falls at T=30: the pulse passes through, delayed by 3.
Common Beginner Mistakes
Mistake #1: Expecting synthesis to build the delays
Wrong: and #5 o1 (out, a, b); to create a delay of 5 time units in hardware
Right: Use delays only for simulation. If the hardware needs to wait, count clock cycles with a counter or shift register
Why? Synthesis ignores # delays. The netlist has the same function with or without them, and its timing comes from the library cells. A design that only works in simulation because of a # delay will fail on the chip.
Mistake #2: Giving three delays to a gate that cannot drive z
Wrong: and #(2, 3, 4) o1 (out, a, b);
Right: and #(2, 3) o1 (out, a, b);
Why? An AND gate never turns off, so a turn-off delay has no meaning and the compiler reports an error. Three values are only allowed on tri-state primitives such as bufif0 and notif1.
Mistake #3: Swapping the rise and fall values
Wrong: Writing #(fall, rise) because the library data sheet lists the fall delay first
Right: The order is always rise, fall, turn-off: #(rise, fall)
Why? The code compiles either way, and the outputs change at the wrong times. In the two-delay example, and #(3, 2) would make and rise at T=23 instead of T=22 and fall at T=32 instead of T=33.
Mistake #4: Expecting a short pulse to pass through a gate
Wrong: Driving a 1 unit pulse into a gate with a delay of 3, and expecting a 1 unit pulse at the output
Right: Make the pulse at least as long as the gate delay, or reduce the delay
Why? Gate delays are inertial, so pulses shorter than the delay are filtered out, as shown in the pulse_demo example. When a pulse disappears in a gate-level simulation, compare its width with the delays on its path.
Mistake #5: Expecting min:typ:max to use all three values
Wrong: Writing #(2:3:4) and expecting the simulation to check all three delays
Right: Run the simulation once per corner, selecting min, typ or max with a simulator option
Why? A simulation uses one value from each triple, which is the typical value by default. The min and max values are never used unless they are selected when the simulator starts.
Practice Exercise
Challenge: Predict a notif1 Waveform
A notif1 drives the inverse of its input when its control is 1, and drives z when its control is 0. Predict when out changes, and to what value, for the code below.
module tb;
reg in, ctrl;
wire out;
notif1 #(3, 4, 5) n1 (out, in, ctrl); // rise = 3, fall = 4, turn-off = 5
initial begin
in = 0; ctrl = 0;
#10 ctrl = 1;
#10 in = 1;
#10 ctrl = 0;
end
endmodule
Hint
Work out the new output value at each input change (T=0, 10, 20 and 30), decide whether it is a rise, a fall or a turn-off, and add the matching delay.
Solution
| Input change | New output value | Transition | Output changes at |
|---|---|---|---|
| T=0: ctrl = 0 | z | x to z, turn-off 5 | T=5 |
| T=10: ctrl = 1, in = 0 | ~0 = 1 | z to 1, rise 3 | T=13 |
| T=20: in = 1 | ~1 = 0 | 1 to 0, fall 4 | T=24 |
| T=30: ctrl = 0 | z | 0 to z, turn-off 5 | T=35 |
out is x from T=0 to T=5, z until T=13, 1 until T=24, 0 until T=35, and z after that. Every input change is at least 10 units apart, so no change is filtered by inertial delay.
Summary
In this tutorial, you learned:
- Rise, fall and turn-off delays apply to transitions to 1, to 0 and to z, and a transition to x uses the smallest delay
- A primitive can take one delay for all transitions, two for rise and fall, or three for rise, fall and turn-off
- With two delays, the turn-off delay is the smaller of rise and fall; three delays are only allowed on tri-state primitives
- Each delay can be a min:typ:max triple, and the simulator uses the typical value unless told otherwise
- Gate delays are inertial, so input pulses shorter than the delay are filtered out
- Synthesis ignores all
#delays; real timing comes from the library and the layout