Hardware Engineering · HDL and Synthesis
Setup and Hold Slack: Reading a Static Timing Report
How arrival and required times are propagated through a timing graph, why setup and hold checks run in opposite directions, and how skew, derating, and path exceptions change the verdict.
A static timing report says a path has negative slack of some number of picoseconds and names the two registers it runs between. Getting from that line to a decision requires knowing what was computed: which delay values were used, which clock edges were compared, what was assumed about the clock, and what exceptions were applied. The arithmetic is simple; the modelling is where the mistakes live.
Static timing analysis replaces simulation with graph traversal. Every pin in the netlist is a vertex; every cell arc and every net connection is a directed edge with a delay. The tool walks the graph from the clock and data sources to the endpoints, computing an arrival time at each vertex, and walks backward from the endpoints computing a required time. Slack is the difference. No vector is applied and no state is exercised, which is why the analysis covers all input combinations implicitly and why it cannot see a functional false path without being told.
The setup check compares two different clock edges
For a path from launching register A to capturing register B on the same clock, setup asks whether data that leaves A on one edge arrives at B early enough to be captured by the next edge. Writing $T$ for the clock period:
$$t_{cq} + t_{pd,max} + t_{setup} \le T + t_{skew}$$
The left side is the arrival time: clock-to-Q of the launching register plus the longest propagation delay through the combinational logic plus the capturing register’s setup requirement. The right side is the required time: one full clock period, adjusted by the skew between the two registers’ clock arrival times. Rearranged, the useful quantity is the logic budget: with a 1 ns period, a clock-to-Q of roughly 100 ps, a setup time of roughly 50 ps, and an uncertainty allowance of a few tens of picoseconds, the combinational path has on the order of 800 ps to work with in a modern node.
The propagation delay is the maximum over the paths through the logic, which is what makes the analysis worst-case. Different paths through the same cone of logic have different delays, and the report names the worst one, called the critical path. Delay values come from the library’s characterization at the load and slew inferred from the netlist, so the same logical path can produce different numbers after placement changes the wire parasitics.
The hold check uses the same edge
Hold asks the opposite question: data launched by A on an edge must not arrive at B so soon that it arrives before B’s hold window closes on the same edge. The comparison is between two paths that start at the same edge:
$$t_{cq} + t_{pd,min} \ge t_{hold} + t_{skew}$$
Now the propagation delay is the minimum over all paths, which is why hold analysis is often called minimum-delay analysis. The failing case is a short path: a register whose output feeds another register with almost no logic between them, or with logic that happens to be fast at the corner being analysed.
This asymmetry has a consequence that surprises people the first time it matters. A setup violation can be relieved by lowering the clock frequency, because the period appears on the required side. A hold violation cannot: the period does not appear in the hold inequality at all, so changing the frequency leaves it exactly where it is, and the only remedies are in the data or clock paths. Hold fixes are structural: delay is added in the data path, typically by inserting buffers or by using a slower cell, and it costs area and power on paths that have no timing slack problem of their own.
# Setup and hold slack for one register-to-register path.
def setup_slack(period, t_cq, t_pd_max, t_setup, skew, uncertainty):
return (period + skew) - (t_cq + t_pd_max + t_setup + uncertainty)
def hold_slack(t_cq, t_pd_min, t_hold, skew, uncertainty):
return (t_cq + t_pd_min) - (t_hold + skew + uncertainty)
p = 1.0e-9 # 1 GHz clock
print("setup", setup_slack(p, 100e-12, 700e-12, 50e-12, 30e-12, 40e-12))
print("hold ", hold_slack(100e-12, 20e-12, 40e-12, 30e-12, 0.0))
The two calls use the same register’s data but different delay values: maximum for the setup check, minimum for the hold check. Every delay in the library exists in both forms, and the analysis runs twice over the netlist for that reason.
Skew moves margin from one check to the other
The skew term in both equations is the difference between the clock arrival times at the capturing and launching registers. The sign convention depends on the tool, so the useful statement is qualitative: making the capturing register’s clock arrive later than the launching register’s adds to the setup margin and subtracts from the hold margin on the same path. Skew therefore does not create margin; it moves it along the path from one check to the other.
Deliberate use of this is called clock skew scheduling or useful skew: the clock tree is built so that registers near the end of a critical path are clocked slightly later, borrowing margin from the hold side, which is usually abundant. The technique is bounded by hold violations and by the difficulty of controlling skew precisely through the clock tree and across process corners.
Skew is not the only source of uncertainty. A real clock has jitter from the source, and the tool cannot know the exact delay of every clock buffer, so a setup uncertainty allowance is subtracted from the required time, covering jitter, the clock tree’s unmodelled variation, and the difference between the tool’s clock model and the built tree. The allowance is a constraint the designer supplies; if it is too small, the design fails in silicon while the report shows passing.
Variation within a single chip compounds this. Two identical cells in different places do not have identical delays, because doping, oxide thickness, and temperature differ across the die. The classical treatment applies a single derating factor to all delays in the late direction for setup and in the early direction for hold, which is pessimistic; more granular models divide the derating by cell type and by the number of stages in the path, and statistical methods propagate distributions instead of bounds. All of them make hold analysis harder, because hold uses minimum delays and every derating scheme makes those minima smaller.
Exceptions are assumptions the tool cannot check
Static analysis sees a graph, not a protocol. Two cases are routine and both require an explicit exception.
A false path is a timing path that exists structurally but can never be sensitized functionally: two multiplexer inputs never selected together, a mode that is mutually exclusive with another, or a path through a register that is held in reset during the operation in question. Not declaring it costs nothing functionally and a great deal in implementation, because the tool will try to close a path that does not matter and spend area, power, and buffering on it. Declaring a real path false is the opposite error and produces a design that fails in silicon with a report that says it passes. The exception is a claim about behaviour, and it has to be justified the way any other claim about behaviour is.
A multicycle path is one that legitimately takes more than one clock period. Declaring it for setup moves the required time out by $N$ periods for integer $N$; the corresponding hold declaration must move by $N-1$ periods, not by $N$ and not by zero. A setup multicycle without its hold counterpart is a common source of hold violations found late.
A third family is the maximum delay constraint, applied to paths that end at a pin rather than at a register: a signal that must reach an output port within a window, or a combinational path through a block that will be constrained by the environment around it.
Inputs and outputs are constrained by the environment
Registers inside the chip are easy to check, because both endpoints are in the netlist and the clock is known. Ports are not. A path starting at an input port needs to know when the signal arrives relative to the clock, and a path ending at an output port needs to know when the receiver samples it. These are supplied as input and output delay constraints, and they are part of the interface contract rather than a property of the logic.
A port with no such constraint is not timed at all. The report lists it as unconstrained, and unconstrained is not the same as passing: the tool has no opinion. A design with an unconstrained input path can pass the timing report and fail immediately in the system, and the failure will look like a protocol bug rather than a timing one. The generated-clock and clock-group constraints serve the same purpose for internal clocks: without them, two asynchronous clock domains get compared edge-to-edge, which is meaningless and produces either impossible requirements or spurious passes. The crossing between such domains is a different problem, covered in metastability and clock domain crossing.
Block-based analysis and its pessimism
The traversal described above is called block-based analysis: it keeps one maximum and one minimum arrival time per pin and propagates them forward. That is linear in the size of the netlist, and it is what allows a full-chip analysis to run in minutes.
It is also conservative. If a pin’s maximum arrival comes from one path and its minimum from another, a later check that uses both figures may combine values from paths that never coexist. Path-based analysis enumerates paths and is exact for the modelled delays, but the number of paths in a real design grows exponentially with logic depth, so enumeration is confined to reporting the critical paths rather than to computing the verdict. The gap between the two is real but usually small, and it is one of the reasons a design that fails by a few picoseconds in the report often closes after placement and optimization rather than needing a logic change.
The estimates from just after mapping are weaker still. At that stage clocks are ideal, wire delays are statistical, and no cell has a placement or an extracted parasitic, as described in technology mapping. Setup slack from that stage is optimistic because the clock tree has not been built and because the wire delays have not been extracted; hold slack is unreliable in the other direction, since the short paths that create hold problems exist in the netlist but their final delays do not. A post-mapping report is useful for finding structurally slow paths, which is what the mapping and optimization steps consume, and not for sign-off.
References
- Static Timing Analysis for Nanometer Designs: A Practical Approach — J. Bhasker and Rakesh Chadha, Springer
- CMOS VLSI Design: A Circuits and Systems Perspective — Neil H. E. Weste and David Money Harris, Addison-Wesley
- Digital Integrated Circuits: A Design Perspective — Jan M. Rabaey, Anantha Chandrakasan, and Borivoje Nikolic, Prentice Hall