Multi-corner timing analysis
Timing a design at one operating point is rarely enough. A chip leaving the fab lands somewhere on a process-variation distribution, runs at a supply voltage that droops under load, and operates across a temperature range. Collectively these dimensions are called PVT — process, voltage, temperature — and each named combination we analyse is a corner.
Why multiple corners?
We usually care about two timing checks:
- Setup — is the data at the capturing flop’s D pin at least
T_setupbefore the next clock edge? Setup fails when the design runs too slow. - Hold — does the data at the capturing flop’s D pin remain stable for at least
T_holdafter the clock edge? Hold fails when the design runs too fast (a short path beats the clock from the launch flop to the capture flop).
Put together, you need to prove setup against the slow worst case and hold against the fast worst case. That’s the minimum — two corners.
In practice neither corner is a single point:
| Axis | Slow side | Fast side |
|---|---|---|
| Process | SS (slow-NMOS / slow-PMOS) | FF |
| Voltage | Low V_DD (min-rail after droop) | High V_DD (max-rail after rise) |
| Temperature | For setup: usually hot (100 °C+) for delay; for hold: cold (−40 °C) | Opposite for each check |
| Interconnect | High-R / high-C (“max” SPEF) | Low-R / low-C (“min” SPEF) |
The temperature story flips depending on technology: in older nodes hot = slowest, but modern nodes can show “inverse temperature dependence” where cold is the slow corner for some cells. This is another reason you analyse multiple corners rather than reasoning from first principles.
Modern designs routinely check dozens of corners — different on-chip variation seeds, multiple supply rails, ECO fixes, library recharacterisation — but the core pattern is small. The example below uses three: a typical (typ), a worst-case for setup (wc), and a best-case for hold (bc).
Defining corners
OpenSTA supports reading different Liberty, SPEF, and parasitic files per corner, all in one session:
define_corners wc bc typ
read_lib -corner wc $env(PDK_ROOT)/sky130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ss_100C_1v60.lib
read_lib -corner bc $env(PDK_ROOT)/sky130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__ff_n40C_1v95.lib
read_lib -corner typ $env(PDK_ROOT)/sky130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__tt_025C_1v80.lib
read_db odb/spm.odb
read_spef -corner wc spef/max/spm.max.spef
read_spef -corner bc spef/min/spm.min.spef
read_spef -corner typ spef/nom/spm.nom.spef
read_sdc sdc/spm.sdc
report_checks
Key points:
define_cornerslists the corner names. Each subsequent-corner <name>flag onread_lib/read_spefassociates a file with that corner.- The slow corner (
wc) gets thessLiberty at high temperature and low voltage and the “max” (worst-case R/C) SPEF — the combination that produces the worst setup margin. - The fast corner (
bc) gets theffLiberty at cold and high voltage and the “min” SPEF — worst hold margin. - The typical corner (
typ) usesttat 25 °C, 1.8 V, and the nominal SPEF. Typical is informational — sign-off gates are the wc/bc pair.
Reporting per corner
report_checks -corner <name> runs the path-based check in the context of a specific corner:
# Setup (max path) at slow corner
report_checks -corner wc -path_delay max
# Hold (min path) at fast corner
report_checks -corner bc -path_delay min
# Sanity-check at typical
report_checks -corner typ
Without -corner, OpenSTA walks every defined corner and returns the worst-slack path across all of them. That’s a good sign-off sweep:
report_checks -path_delay max # worst setup across all corners
report_checks -path_delay min # worst hold across all corners
Pair this with aggregated reports (see STA Reporting) to get per-corner TNS / WNS summaries rather than walking individual paths.