Unit delay simulation gives every gate, and usually every flip-flop clock-to-output path, the same small delay of one time unit instead of its real delay. It is used mainly in gate-level simulation of a synthesised netlist before accurate timing is available, because it removes the race conditions that zero-delay netlist simulation suffers from, shows the order in which signals settle and exposes glitches. It does not check timing; that remains the job of static timing analysis and SDF back-annotated simulation.
Unit delay simulation is a technique for modelling the behaviour of digital circuits in a discrete time domain. It is based on the assumption that each logic gate has a unit delay, which means that it takes one time step for the output to change after the input changes. It can be used to verify the functionality of a circuit design, and to detect and debug glitches or hazards that occur because signals propagate along paths of different length.
Key takeaways
- Zero delay: every gate switches instantly. Fast, but netlists with clock buffers can race, and glitches are invisible.
- Unit delay: every gate takes one time unit. Still fast, makes event order visible and fixes most clock-buffer races in netlist simulation.
- Full timing: real cell and wire delays from an SDF file. Slowest, used to check timing-sensitive behaviour after layout.
- Use unit delay for early gate-level simulation, scan and reset checks, and debugging X propagation, not for timing sign-off.
- Unit delay can itself fail when a clock passes through more unit-delay buffers than the data path has, so know how your library applies it.
How unit delay simulation works
To perform unit delay simulation, we represent the circuit as a network of nodes and edges, where each node corresponds to a logic gate or an input or output port, and each edge corresponds to a wire or connection. Each node has a current value and a next value, which are updated at each time step according to the logic function of the node and the values of its predecessors. Each edge carries the current value of its source node. The simulation proceeds as follows:
- Initialise the values of all nodes and edges according to the initial conditions of the circuit.
- For each node, evaluate its next value from its logic function and the values of its predecessors.
- For each node, assign its next value to its current value, and propagate the value to its successors.
- Increment the time step and repeat from step 2 until the desired number of time steps is reached or the circuit reaches a steady state.
Production simulators are event-driven rather than evaluating every node at every step: only gates whose inputs changed are re-evaluated, and their outputs are scheduled one time unit later. The result is the same, but much faster on large netlists where only a small fraction of nodes switch in any time step.
In Verilog, unit delay is expressed as a delay of one on each primitive, for example and #1 g1 (y, a, b);. Commercial simulators also offer a switch that overrides the delays in a netlist and cell library with unit (or zero) delays without editing the source. Many standard-cell Verilog models include a compile-time option that adds a small delay to the flip-flop output for the same purpose.
Zero delay, unit delay and full timing compared
| Mode | Gate delays | Speed | Shows glitches | Typical use |
|---|---|---|---|---|
| Zero delay | All zero; order set by delta cycles | Fastest | No | RTL simulation; quick functional netlist checks |
| Unit delay | One time unit per gate | Fast | Yes, in a simplified form | Early gate-level simulation, scan and reset checks, debug |
| Full timing (SDF) | Real cell and interconnect delays, min/typ/max | Slowest | Yes, realistic | Post-layout checks of asynchronous logic, resets, CDC paths and timing exceptions |
Why it is needed: the zero-delay race
A synthesised netlist contains clock buffers, clock-gating cells and other cells in the clock path. In zero-delay simulation, a buffer still takes a delta cycle to pass the clock on. A flip-flop clocked directly can therefore update its output before a downstream flip-flop, clocked through a buffer, samples its input. The downstream flop then captures the new value in the same cycle, a shoot-through that cannot happen in silicon.
The example below models a flip-flop as a user-defined primitive (UDP), as many cell libraries do, and builds a two-stage shift register in which the second flop is clocked through two buffers. The same netlist is instantiated with zero delay and with a unit clock-to-Q delay.
`timescale 1ns/1ns
// Rising-edge D flip-flop as a UDP, the way many cell libraries model it.
primitive udp_dff (q, clk, d);
output q; reg q;
input clk, d;
table
// clk d : q : q+
(01) 0 : ? : 0 ;
(01) 1 : ? : 1 ;
(0?) ? : ? : - ;
(?0) ? : ? : - ;
? (??) : ? : - ;
endtable
endprimitive
// Library-style cell: delay D on clock-to-Q (0 = zero-delay, 1 = unit-delay).
module DFF #(parameter D = 0) (input CK, input Dn, output Q);
udp_dff #(D) u0 (Q, CK, Dn);
endmodule
// Netlist: two-flop shift register; the second flop is clocked through two zero-delay buffers.
module shift2 #(parameter D = 0) (input clk, din, output q1, q2);
wire ck1, ck2;
buf b1 (ck1, clk);
buf b2 (ck2, ck1);
DFF #(D) f1 (.CK(clk), .Dn(din), .Q(q1));
DFF #(D) f2 (.CK(ck2), .Dn(q1), .Q(q2));
endmodule
module race_tb;
reg clk = 0, din = 0;
wire z1, z2, u1, u2;
shift2 #(0) zero_delay (.clk(clk), .din(din), .q1(z1), .q2(z2));
shift2 #(1) unit_delay (.clk(clk), .din(din), .q1(u1), .q2(u2));
always #5 clk = ~clk;
initial begin
@(posedge clk) #2; // edge 1 loads din = 0 into both flops
din = 1;
@(posedge clk) #2; // edge 2: q1 should become 1, q2 should take the old q1 (0)
$display("after edge 2: zero-delay q1=%b q2=%b | unit-delay q1=%b q2=%b", z1, z2, u1, u2);
$finish;
end
endmodule
After the second clock edge, q2 should hold the old value of q1, which is 0. Run with Icarus Verilog 12.0, the zero-delay copy prints q1=1 q2=1, the shoot-through error, while the unit-delay copy prints q1=1 q2=0, the correct result. The one time unit of clock-to-Q delay lets the buffered clock arrive before the data changes.
Seeing a glitch: the static-1 hazard
The function y = (a AND b) OR (NOT a AND c) should stay at 1 when b = c = 1, whatever a does. Built from gates, the inverted path is one gate longer than the direct path, so when a falls from 1 to 0, the AND that was holding y high turns off before the other AND turns on.
`timescale 1ns/1ns
// y = (a & b) | (~a & c), with b = c = 1. Logically y stays 1 when a changes.
module mux_gates #(parameter D = 1) (input a, b, c, output y);
wire an, t1, t2;
not #D g0 (an, a);
and #D g1 (t1, a, b);
and #D g2 (t2, an, c);
or #D g3 (y, t1, t2);
endmodule
module hazard_tb;
reg a = 1, b = 1, c = 1;
wire y0, y1;
mux_gates #(0) zero_delay (.a(a), .b(b), .c(c), .y(y0));
mux_gates #(1) unit_delay (.a(a), .b(b), .c(c), .y(y1));
initial begin
$monitor("t=%0d a=%b zero-delay y=%b unit-delay y=%b", $time, a, y0, y1);
#10 a = 0; // 1 -> 0 on a: the static-1 hazard path
#10 $finish;
end
endmodule
In Icarus Verilog 12.0, the zero-delay copy holds y at 1 throughout. The unit-delay copy shows y falling to 0 at t = 12 and returning to 1 at t = 13: a one-unit glitch, two gate delays after a changes. In real hardware the width of such a glitch depends on actual gate delays, but unit delay is enough to show that the hazard exists. That matters when the signal drives an asynchronous input, a clock or a clock-gating enable.
When to use unit delay simulation
- Early gate-level simulation: after synthesis and before an SDF file is available, to check that the netlist matches the RTL in function, including scan insertion and clock gating.
- Reset and initialisation checks: to find flip-flops that stay at X after reset, which RTL simulation can hide through X-optimism.
- Glitch and hazard debugging: to see the order of events on asynchronous control paths.
- Running more tests: unit-delay simulation is much quicker than full timing simulation, so a larger regression can run at gate level.
- Teaching and quick checks: it is a simple and intuitive way to model digital circuits, useful early in development or for small circuits.
Limitations
Unit delay simulation assumes that all logic gates have the same delay, which is not realistic. Different types of gates have different delays depending on their complexity, drive strength, load and technology, and the delay of a gate varies with operating conditions such as voltage and temperature. Unit delay simulation therefore cannot show whether a design meets its clock frequency, or whether a path violates setup or hold time.
It also ignores the physical effects along the wires, such as resistance, capacitance, inductance, noise and crosstalk. These effects change the delay and shape of signal waveforms, so unit delay simulation does not capture every source of timing error.
A specific trap: if the simulator applies a unit delay to every buffer in the clock tree as well as to the flops, a clock path of several buffers is slower than a data path through one flop. The race of the zero-delay case then returns in a different form. Libraries and simulator options usually handle this by giving clock-to-Q a delay larger than the clock tree depth, or by applying unit delay to sequential cells only. Check what your flow does before trusting the results.
More detailed techniques address these limits: full timing gate-level simulation with SDF back-annotation, switch-level simulation and transistor-level (SPICE) simulation. They use more accurate models of the cells and wires, but need far more computation and time, which may not be practical for large circuits. Timing sign-off itself is done with static timing analysis, which checks every path without needing test vectors.
How interviewers probe this topic
- Why does a netlist pass in unit delay but fail in zero delay? Expect the clock-buffer delta-cycle race.
- Why not rely on unit delay for timing? Because every gate has the same delay, so setup and hold are not checked.
- What does SDF simulation add over static timing analysis? It checks behaviour that STA cannot, such as asynchronous paths, reset sequencing and timing exceptions, with real delays.
- What causes X at the output of a gate-level simulation that was clean at RTL? Missing resets, X-pessimism in cell models or uninitialised memories.
FAQ
Is unit delay the same as a one-nanosecond delay?
No. One unit is one tick of the time unit in effect for the module, set by the Verilog timescale. With `timescale 1ns/1ps, #1 is 1 ns; simulator unit-delay switches may instead use the smallest time precision in the design.
Does unit delay simulation replace static timing analysis?
No. It checks function and event order. Static timing analysis checks timing on every path, and full timing simulation checks timing-sensitive behaviour with real delays.
Do I still need gate-level simulation if I run formal equivalence checking?
Equivalence checking proves that the netlist matches the RTL logically, which covers most of what functional gate-level simulation used to find. Teams still run a smaller set of gate-level tests for reset behaviour, X propagation, scan and timing-sensitive paths.
Unit delay simulation is still useful as a first-order approximation or a quick check of a circuit design, especially in the early stages of development or for simple circuits. It should not be relied upon as the only or final verification method, because it does not reflect all the factors that affect a circuit's performance and behaviour in silicon.

Your comments will be moderated before it appears here.