On paper vs in silicon
In the Digital Front-End track you checked timing the way a city planner checks travel times on a fresh blueprint: every road is perfectly straight, perfectly smooth, and traffic moves at the speed limit. The wires were ideal — no resistance, no capacitance, signals snapping from one gate to the next with no drag. That was the right simplification for learning, and it's roughly what your tools assume before a design has been placed and routed. But silicon isn't a blueprint. It's a real city with real roads.
Once your design is physically built — cells placed, wires routed across stacked metal layers — every wire becomes a real, physical thing with two stubborn properties. It has resistance (R): the metal fights the flow of current, like a narrow pipe throttling water. And it has capacitance (C): the wire and its neighbours hold charge, like a bucket you must fill before the voltage on the far end will rise. To switch a wire from 0 to 1, you don't flip a bit — you charge a bucket through a pipe. That takes time, and that time is now part of your delay.
Parasitic extraction (R and C)
Parasitic extraction is the step that turns your finished layout into numbers. An extraction tool reads the exact geometry of every routed wire — how long it is, how wide, which metal layer it runs on, how close it sits to its neighbours — and computes the resistance and capacitance of each segment. Picture taking a tape measure to every road in the city and writing down how narrow and how long each one is; extraction does that for millions of wire segments at once, from the as-built layout rather than an estimate.
The result is written to a standard file called a SPEF (Standard Parasitic Exchange Format). Think of it as the as-built survey of your chip's wiring: a giant table that says *this net has this much R and this much C, spread across these segments*. Crucially, this is post-route data — it reflects the wires that actually exist, not the rough guess the tools used while placing. The SPEF is what makes the next step honest.
# Extraction consumes the routed layout + a parasitic model, emits SPEF
extract_parasitics \
-layout routed.def \
-tech rc_corner.techfile \
-output design.spef ;# R + C per net, fed into signoff STA
# A SPEF line, simplified: net 'clk_buf_out' carries ~12 fF of C and ~8 ohm of R
# *D_NET clk_buf_out 12.4 ;# total cap in femtofaradsWhy post-route timing is the real timing
Now we feed that SPEF back into static timing analysis. Remember the f_max picture from the front-end track? The fastest clock you could run was roughly:
f_max = 1 / (t_clk-to-q + t_logic + t_setup - t_skew)
In the front-end track, t_logic was just the gate delays along the path, because the wires were ideal — instant. Now that you've extracted parasitics, t_logic carries the real wire delay too: every charge-the-bucket-through-a-pipe along the route. On a modern node that wire portion can dominate. The same path that looked comfortable on ideal wires can blow its budget once the metal is accounted for. That's not a surprise; it's the point.
This is why post-route, parasitic-aware STA is the authoritative timing check — the one that counts. Pre-route timing on estimated wires is a useful early steer, like checking your route on a map before you drive. But the map doesn't know about the roadworks, the hills, or the traffic. Only the as-built numbers tell you whether the chip will actually meet its clock. Everything before this was rehearsal; [[timing-signoff|signoff]] is the performance.
Corners: PVT & MMMC
Here's the catch: no two chips off the line are identical, and no chip runs in just one environment. Three things vary, summarised as PVT. Process (P): manufacturing scatter makes transistors come out a touch faster or slower — the *fast* and *slow* process corners. Voltage (V): the supply sags or rises a little; lower voltage means slower transistors. Temperature (T): heat changes how fast transistors switch. A process corner is one specific worst-case combination of these — a named scenario your chip must survive.
Why corners instead of one nominal run? Because you're not shipping one chip — you're shipping millions, into hot phones and cold servers, on good silicon and marginal silicon. If timing closes only at the typical case, a meaningful fraction of parts fail in the field. So you check the extremes. The key insight is that setup and hold fail at *opposite* corners:
- Setup (data arriving too late) is worst at the slow corner — slow process, low voltage, and the temperature that makes that path slowest. If the data can make it here, it makes it everywhere.
- Hold (data arriving too soon, racing past the capture edge) is worst at the fast corner — fast process, high voltage. Fast silicon is the *dangerous* one for hold, because data sprints through and can overtake the clock.
- Each corner pairs with its matching extracted SPEF — slow-RC wires for the slow setup corner, fast-RC for the fast hold corner — so the wire delay is consistent with the transistor speed.
Doing this one corner at a time is slow and error-prone, so signoff uses MMMC — Multi-Mode Multi-Corner. *Multi-corner* is the PVT spread above. *Multi-mode* means the different operating modes your chip has — full-speed mode, low-power mode, test mode — each with its own clock setup and constraints. MMMC checks every mode against every relevant corner in one analysis, so a fix that helps one scenario can't quietly break another. You don't sign off a chip; you sign off the whole grid of modes × corners.
# An MMMC setup pairs each timing 'view' with its corner + SPEF + constraints create_clock -name clk -period 1.0 [get_ports clk] ;# 1 ns => 1 GHz target # slow corner drives the SETUP check (data must still arrive in time here) create_view view_slow -corner ss_0p72v_125c -spef slow.spef -check setup # fast corner drives the HOLD check (data must NOT race ahead here) create_view view_fast -corner ff_0p88v_m40c -spef fast.spef -check hold
On-chip variation
Corners cover variation *between* chips. But variation also happens *within a single chip*: two identical cells, side by side, won't switch at exactly the same speed, because of microscopic differences in doping, line edges, local heat, and supply. This is [[on-chip-variation|on-chip variation]], or OCV. The same clock edge might reach one flip-flop a hair sooner than its neighbour even though the wiring looks symmetric. Picking a single corner number for the whole die would ignore this — and pretending every cell on the chip is identical is exactly the kind of optimism that gets a chip back from the fab broken.
The fix is de-rating: deliberately pessimistic adjustment of delays so the analysis assumes the unlucky case. For a setup check, you make the data path a little slower than nominal and the capture clock path a little faster — squeezing the budget from both ends. For a hold check, you flip it: the launch path runs fast and the capture clock runs slow, exposing any race. You apply this skepticism to both sides at once, so the path has to survive the worst plausible mismatch, not just the average.
# Classic OCV: de-rate late paths slower, early paths faster (worst-case both ways) set_timing_derate -late 1.05 ;# late paths run +5% slower than nominal set_timing_derate -early 0.95 ;# early paths run -5% faster than nominal
Slack, signed off
After extraction, all corners, all modes, and OCV de-rating, every timing check still collapses to the one number you met in the front-end track — but now it's earned. Slack is the margin between when a signal is *required* and when it actually *arrives*:
slack = required - arrival ;# must be >= 0 to sign off # slack > 0 : pass, with margin to spare # slack = 0 : exactly on the deadline # slack < 0 : FAIL — the path violates timing at this corner
The rule for signoff is unforgiving and simple: slack must be ≥ 0 for every path, in every mode, at every corner, with OCV applied — for both setup and hold. One negative number anywhere in that grid means the chip isn't signed off. The worst single slack is the WNS (worst negative slack); the total across all failing paths is the TNS (total negative slack). WNS tells you how bad the worst path is; TNS tells you how *many* paths are hurting. You read both.
The closure loop & ECOs
What if signoff turns up negative slack? You don't redo the whole place-and-route from scratch — by this stage the layout is mostly clean, DRC-correct, and you don't want to disturb the thousands of paths that already pass. Instead you make a small, surgical change: an [[engineering-change-order|ECO]] (Engineering Change Order). An ECO is a minimal edit to the netlist and layout that fixes the violation while touching as little else as possible — like patching one cracked road overnight, not rebuilding the city.
Typical ECO moves: swap a cell for a faster (higher-drive) variant to win back setup slack, or insert a delay buffer to fix a hold violation by slowing a too-eager path. The tool finds open space near the offending cells and routes only the few nets it disturbed. Then — and this is the part that makes it a *loop* — you re-extract the parasitics for whatever you changed and re-run signoff STA, because your fix added its own wires and its own RC. The numbers are only true after re-extraction.
- Run full signoff STA — extracted parasitics, all modes, all corners, OCV applied — and collect every path with negative slack (worst first, by WNS).
- Generate an ECO that targets the violations: resize/swap cells for setup, insert delay buffers for hold, choosing fixes that don't break paths that already pass.
- Apply the ECO to the netlist and layout, placing and routing only the changed cells and nets.
- Re-extract the affected parasitics — the fix moved metal, so the RC changed — and write a fresh SPEF.
- Re-run signoff STA. Confirm the targeted paths now pass and that the fix didn't push a neighbouring path negative.
- Repeat until WNS ≥ 0 for setup AND hold across every mode and corner. Now timing is closed — and the design can move toward physical verification and tapeout.