Static Timing Analysis Fundamentals: Setup, Hold, and Reading the Reports That Decide Whether Your Chip Works
A chip that is one picosecond slow will not boot. The whole point of static timing analysis (STA) is to prove, without running a single vector through simulation, that every path in your design meets its timing — setup, hold, recovery, removal, and a handful of quieter checks — across every corner the chip must operate in. If STA passes, your chip meets timing. If STA fails and you tape out anyway, you have built a very expensive paperweight.
STA is often taught as a checkbox at the end of the flow: run it, read “all paths met,” move on. The reality is different. Real designs fight with timing through every stage — synthesis, floorplan, placement, clock tree synthesis, routing, extraction, signoff — and every iteration is someone reading an STA report and figuring out what to do next. Learning to read those reports fluently is one of the biggest step-function improvements available to a digital designer or implementation engineer.
This post is the first-principles version: what STA actually computes, what setup and hold really mean, what the rest of the checks are for, how clock domain crossings get analyzed, what SDC constraints tell the tool, and how to read a real STA report end-to-end.
The premise: flops, paths, and the two timing checks
Every synchronous digital circuit is a directed graph of combinational logic between flip-flops (or latches). The flip-flops sample their data inputs at clock edges. For that sampling to produce the right value, two things must be true:
- The data at the D input must be stable long enough before the clock edge — the setup time.
- The data at the D input must be stable long enough after the clock edge — the hold time.
Violate setup, and the flop samples either the old value or the new one unpredictably (metastability). Violate hold, and the flop samples the next clock cycle’s value instead of this one. Both mean functional failure.
STA is a static algorithm that, given a netlist and a library of cell timing models, computes the worst-case arrival time for every signal at every flop’s D input — and compares it against the required time based on the clock edge and the flop’s setup/hold characteristics. It does this for every path in the design. No simulation, no input vectors: pure graph analysis.
This is why it is called static: the answers do not depend on what the circuit is doing. They depend only on the netlist, the library, the parasitics, and the constraints.
Setup and hold in a single diagram’s worth of prose
For a path from flop A to flop B with a common clock:
- Launch clock arrives at A at time
Tclk_a. - Data launches from A after the flop’s clock-to-Q delay: departs at
Tclk_a + Tcq. - Data propagates through combinational logic with delay
Tcomb. - Data arrives at B’s D input at
Tclk_a + Tcq + Tcomb. - Capture clock arrives at B at time
Tclk_b(which isTclk_a + T_periodplus any skew between A and B’s clock delivery).
Setup check: data must arrive before the capture edge minus the setup window:
Tclk_a + Tcq + Tcomb ≤ Tclk_b + T_period − Tsetup
Rearranged:
Slack_setup = (T_period + skew) − (Tcq + Tcomb + Tsetup) ≥ 0
Hold check: data must not arrive so quickly that the capture edge sees the new data on the current edge (one period before the edge that is supposed to capture it):
Tclk_a + Tcq_min + Tcomb_min ≥ Tclk_b + Thold
Rearranged:
Slack_hold = (Tcq_min + Tcomb_min) − (skew + Thold) ≥ 0
Setup failures are fixed with more time — a longer clock period, less skew on the capture side, faster cells, pipelining. Hold failures are fixed with more delay in the combinational path (buffers inserted between the launching flop and the capturing flop).
A beginner intuition that keeps paying dividends: setup is about the maximum path, hold is about the minimum path. Every synthesis and implementation tool tries to make the maximum fast enough for setup while making sure the minimum stays long enough for hold. Those are competing goals — every buffer you add to fix hold slows down the path for setup, and vice versa.
The other checks
Setup and hold are the big two, but STA also verifies:
- Recovery: the asynchronous reset/set signal must be deasserted long enough before the clock edge. Think of it as setup-for-reset.
- Removal: the asynchronous reset/set signal must stay asserted long enough after the clock edge. Think of it as hold-for-reset.
- Minimum pulse width: clock high and low times must be at least the flop’s spec. A glitchy clock fails here.
- Minimum period: the clock’s period must be at least the sum of its minimum high and low pulse widths.
- Data-to-data checks: for some cells (latches, certain IP), there are checks between two data inputs rather than data-to-clock.
Signoff STA runs all of these. If your tool produces a report called “non-setup-hold checks” or similar, read it carefully — violations there usually mean something is genuinely wrong in the reset network or clock generator.
Timing arcs and delay calculation
STA looks up every cell’s delay from a timing library (.lib, in Liberty format). Each library arc says: “for input X going from 0 to 1, with this input slew and this output load, the propagation delay to output Y is D, and the output slew is S.” The lookup is typically a 2-D table indexed by input slew and output load, called a NLDM (Non-Linear Delay Model).
Modern libraries use CCS (Composite Current Source) or ECSM (Effective Current Source Model) instead — full current waveforms that interact correctly with the parasitics. These are more accurate (and 10× larger files) and required for advanced nodes where voltage effects get messy.
Interconnect delay comes from the parasitics (resistance and capacitance of wires). Before layout, STA uses wire load models — a statistical estimate based on fanout. Post-layout, it uses extracted parasitics from the layout tool (SPEF files). The difference between wire-load-estimated STA and post-extraction STA is why designs that pass synthesis timing can fail after placement and routing.
Corners: PVT, OCV, and AOCV
Silicon is not deterministic. Voltage varies, temperature varies, process varies chip-to-chip. STA runs at multiple “corners”:
- Slow corner (slow transistors, low voltage, high temperature for CMOS — or low temp for leaky processes): worst setup.
- Fast corner (fast transistors, high voltage, lower temperature): worst hold.
- Typical corner: reference.
Each PVT combination plus process variation direction gives a “corner.” A production signoff runs dozens — sometimes hundreds — of corners across different clock domains, different modes (functional, scan, BIST), and different functional contexts (low-power modes, high-performance modes).
On-Chip Variation (OCV) derates launch and capture paths differently to model the fact that two flops on the same die experience slightly different process variation. Classic OCV multiplies launch-path delays by, say, 1.05 and capture paths by 0.95 (worst-case) for setup analysis. It is crude but conservative.
AOCV (Advanced OCV) and POCV (Parametric OCV) / SOCV (Statistical OCV) use path-length-dependent and statistical models instead. Longer paths get less derate because variation averages out across many cells. Critical for advanced nodes (7 nm and below) where being conservative on every cell costs enormous amounts of area and power.
Reading a timing report: look for a column like “Derating” or a row like derate_cell_check to know what derating model was applied.
Clock domain crossings (CDC)
STA is fundamentally a single-clock-domain analysis. Two asynchronous clocks have no fixed phase relationship; you cannot compute a meaningful skew. STA handles this by declaring the domains asynchronous to each other:
|
|
This tells the tool “do not compute setup/hold between CLK1 and CLK2 domains.” But that does not mean the paths are free — it means they need to be handled architecturally (synchronizer flops, async FIFOs, handshake protocols). CDC verification is a separate discipline with its own tools (Questa CDC, Conformal CDC, JasperGold CDC); STA is not sufficient.
If the two clocks are synchronous but unrelated (e.g., 100 MHz and 33 MHz from the same source), you have a multi-cycle or non-standard relationship that does need to be analyzed — usually with manually computed setup/hold requirements via set_multicycle_path or explicit set_max_delay / set_min_delay.
Timing exceptions
Not every path in a design needs to meet single-cycle timing. Four standard exceptions:
False paths
Paths that exist in the netlist but are never exercised functionally:
|
|
“Do not check this path.” Common uses: scan-mode-only paths, debug paths, some CDC paths (though CDC is usually handled by set_clock_groups).
Danger: false paths that are not actually false cause silicon failures. Every set_false_path needs justification.
Multi-cycle paths
Paths that take more than one clock cycle to propagate, by design:
|
|
The setup check now uses two clock periods. The hold check still uses the same launch-capture edge pair (that’s why the hold multi-cycle is N-1).
The hold multi-cycle trap: if you specify -setup 2 without -hold 1, the tool assumes you meant the launching flop actually holds its value for 2 cycles (because the default hold check would require 1 period of hold, which your combinational path can’t provide). This almost always requires the hold-side exception. Forgetting it is the single most common STA constraint bug in the industry.
set_max_delay / set_min_delay
Direct specification of the maximum or minimum delay along a path:
|
|
Used for point-to-point interfaces where “clock cycles” don’t apply — chip outputs to static IO, paths that transit through async boundaries with explicit timing budgets.
Case analysis
|
|
“Assume this signal is always 0 for timing.” The tool propagates the constant and doesn’t analyze paths that would only be active when TEST_MODE=1. Used to cleanly separate functional-mode and test-mode analyses.
SDC: the constraints file
The Synopsys Design Constraints (SDC) file is the way you tell the STA tool what it needs to know beyond the netlist and library. Reading an SDC is a core skill. A minimal file for a simple block:
|
|
Every line carries meaning the tool must know to analyze correctly. Missing constraints do not produce errors — they produce analysis of the wrong design, which looks fine but leads to silicon failures.
create_clock vs create_generated_clock
create_clock defines a primary clock (from a pad or an internal source); create_generated_clock defines a clock derived from another clock — a PLL output, a divided-by-2 clock, a gated clock.
|
|
If you create what should be a generated clock with create_clock, the tool treats it as a separate, uncorrelated clock. Setup/hold between the two clocks is now pessimistic (potentially badly so) or gets analyzed as async. Always identify generated clocks correctly.
Input and output delays
set_input_delay says “this input signal becomes valid N ns after the relevant clock edge.” Combined with your chip’s setup time, this gives the tool the full timing budget for the external path.
Imagine a 10 ns clock, set_input_delay -max 4 -clock CLK on a pin. That means the path from the pin through your combinational logic to the capture flop has 10 − 4 = 6 ns before the next clock edge, minus setup. If the combinational logic takes 7 ns, you fail.
Reading a timing report
Every STA tool produces a similar-shaped report for the worst-case path:
Startpoint: u_cpu/u_decode/opcode_reg_0_/CK (clk: CLK_CORE)
Endpoint: u_cpu/u_execute/alu_result_reg_0_/D (clk: CLK_CORE)
Path Group: CLK_CORE
Path Type: max
Point Incr Path
---------------------------------------------------------------
clock CLK_CORE (rise edge) 0.000 0.000
clock network delay (propagated) 0.185 0.185
u_cpu/u_decode/opcode_reg_0_/CK (DFFX1) 0.000 0.185 r
u_cpu/u_decode/opcode_reg_0_/Q (DFFX1) 0.082 0.267 f
u_cpu/u_decode/U123/ZN (INVX1) 0.041 0.308 r
u_cpu/u_decode/U456/Z (AOI22X2) 0.097 0.405 f
... 17 more cells ...
u_cpu/u_execute/U789/Z (NAND4X2) 0.134 2.241 r
u_cpu/u_execute/alu_result_reg_0_/D 0.012 2.253 r
data arrival time 2.253
clock CLK_CORE (rise edge) 2.500 2.500
clock network delay (propagated) 0.190 2.690
clock uncertainty -0.150 2.540
u_cpu/u_execute/alu_result_reg_0_/CK 0.000 2.540 r
library setup time -0.068 2.472
data required time 2.472
---------------------------------------------------------------
data required time 2.472
data arrival time -2.253
---------------------------------------------------------------
slack (MET) 0.219
Decoding this:
- Startpoint: the launching flop (or input port).
- Endpoint: the capturing flop (or output port).
- Path Type: max: this is a setup check.
Path Type: minwould be hold. - The upper block is the launch path: clock arrives at the launching flop, the flop’s Q output toggles (the
r/fsuffix is rise/fall), and data propagates cell by cell.Incris the per-stage delay;Pathis the cumulative time. - The lower block is the capture path: when the capture clock edge arrives at the capturing flop’s D input, plus the setup time, equals the required time.
- Slack = required − arrival. Positive slack means the path meets timing by that much.
Things to look for when you read a failing report (slack < 0):
- Number of cells in the path. Twenty? Forty? Too long — you need either pipelining (add a flop stage), synthesis effort (push for faster cells), or RTL restructuring (move logic around).
- Any unusually slow cell. A single INVX1 driving a big load can account for huge delay; a single high-fanout net can dominate. Look for a cell whose
Incris 5× its neighbors. - The clock path skew. If the capture clock arrives much earlier than the launch clock, you lose slack to negative skew — a layout/CTS problem, fixable by balancing the tree.
- Clock uncertainty. Large uncertainty often hides optimism assumed but not achieved.
- Setup time of the capture flop. If the capturing cell is a high-setup cell (multi-bit flop, low-power flop), swap to a faster variant if possible.
Hold reports look similar, but:
Path Type: min.- Incremental delays are the minimum (not maximum) delays of each cell.
- Required time is based on the capture flop’s hold requirement relative to the launching clock’s next edge. Hold fails when the arrival time is too small (data arrived too fast).
Common flows where STA goes wrong
Missing generated clocks. A PLL or divider where you forgot to create_generated_clock. Downstream flops get analyzed at the wrong clock period. Sometimes they look fine, sometimes the tool warns about “unconstrained path.” Fix: use report_clocks to enumerate every clock the tool knows about; look for flops on clocks you did not expect.
Wrong clock source for generated clocks. -source should be the pin feeding the generator, not the clock you derived it from. Mixing these up makes the tool compute the wrong arrival time.
Overly broad set_false_path. Someone wrote set_false_path -from [get_pins *test*] — and caught functional paths that happened to have “test” in their name. Always scope false paths as narrowly as you can and review with report_exceptions.
Missing hold multi-cycle paired with setup multi-cycle. As mentioned earlier. Always specify both.
Incorrect -clock reference in set_input_delay/set_output_delay. If the input is actually relative to CLK_IO but you constrained against CLK_CORE, you are analyzing a path that does not physically exist. check_timing may or may not catch this.
Post-route skew inflation. Pre-route STA uses ideal clocks; post-route uses propagated clock delays with actual skew. Paths that passed pre-route with zero skew budget can fail post-route.
Signoff at wrong corners. Only checking slow corner means your design will fail hold in production because hold violations only appear at fast corners. Run both (and really, all of them).
The check_timing command
Before trusting any STA run, run:
|
|
This reports unconstrained paths, ports without input/output delay, clocks that don’t reach all flops, generated clocks with missing sources, and several other sanity checks. Every message is a potential silicon bug. Zero of them before you sign off.
A practical report-reading routine
When someone hands you a report and says “why is this path failing?”:
- Identify the startpoint and endpoint. Do they make sense architecturally?
- Count cells. If it’s 25+ levels deep and you’re at a 2 GHz clock, the answer is “you need a pipeline stage.” Stop here.
- Look at the slack deficit. −100 ps means tuning; −1000 ps means restructuring.
- Look at the clock skew. If launch-to-capture skew is large and negative, it is a CTS problem, not a data-path problem.
- Look at fanout and cell sizes on the hot nets. Over-loaded nets with weak drivers are common.
- Is this a false path or a real path? If it’s real, is the RTL doing more work in one cycle than is realistic?
- Does it show up at multiple corners or just one? If just one (say slow-hot), the derate might be unusually pessimistic there, or a specific cell is uniquely slow in that corner.
- Are there multi-cycle paths nearby that should apply here but don’t?
Timing closure: the iterative loop
Closing timing on a real block is rarely one pass. It is a loop:
- Synthesize with current constraints.
- Run pre-route STA; identify critical paths.
- If they are false paths or multi-cycle, update constraints; re-synthesize.
- If they are real, push synthesis effort or restructure RTL.
- Place, clock-tree-synthesize, route.
- Extract parasitics; run post-route STA.
- Fix any new violations — often “ECO” (Engineering Change Order) fixes: add buffers, upsize cells, resize a few drivers.
- Check all corners and modes.
- Repeat until signoff criteria are met.
Signoff criteria vary, but common goals are “zero setup violations, zero hold violations, positive slack margin of 50 ps on setup, 15 ps on hold, across all corners, across all modes.”
Tools
The major signoff STA tools:
- Synopsys PrimeTime — industry standard for signoff; if a chip taped out, PrimeTime likely signed it off.
- Cadence Tempus — Cadence’s signoff STA, tight integration with Innovus P&R.
- Siemens (Mentor) Questa PowerAware Signoff and Tessent — less common as a primary signoff, present in some flows.
- OpenSTA — the open-source STA used by OpenROAD. Improving fast; reasonable for non-signoff analysis.
Implementation tools have built-in STA (Innovus, ICC2, OpenROAD) used during placement and routing. Signoff then re-runs with PrimeTime or Tempus against the final routed netlist with full extraction — their results are the authoritative ones.
A vocabulary cheat sheet
- Slack — required − arrival. Positive: meets timing. Negative: fails.
- WNS — Worst Negative Slack. The single worst failing path’s slack (a negative number if failing).
- TNS — Total Negative Slack. Sum of all negative slack across all paths. More useful than WNS for tracking total fix effort.
- FEP / Failing Endpoints — count of endpoints with negative slack.
- CPPR — Clock Path Pessimism Removal; recovers optimism the OCV model took away for the shared part of the clock tree.
- Useful skew — intentionally skewing the clock to borrow time from one path to another; the synthesis or CTS tool can do this.
- Transition / slew — the rise/fall time of a signal. Long slews cause downstream delay inflation.
- Max transition / max capacitance — DRC checks on how slow or loaded a net can be. Violations cause delay issues and reliability problems.
Wrapping up
Static timing analysis is not magic. It is a graph walk over cell delay models with a handful of checks (setup, hold, recovery, removal, pulse width). The depth of the field comes from the complexity of modern libraries (CCS, AOCV, multi-corner), the sheer number of constraints a real design needs (SDC files thousands of lines long), and the hair-pulling interactions between clock trees, skew, uncertainty, and OCV.
The skill that separates engineers who close timing from engineers who do not is fluency in reading timing reports — understanding what the columns mean, where the time is being spent, which knob fixes which problem. Every hour spent reading reports directly — not waiting for a tool to tell you what is wrong, but looking yourself — compounds. Reports are how the chip tells you what it needs from you. Learn to listen.
Comments