Tcl · Module 26
Corners
A corner selects a library, a parasitic file and a derate. Encoding that in a file name is a 20-character budget for data that includes two paths, and the parser fails on the corner hold sign-off depends on.
Advanced21 min readtcledapart-iimcmmcornerspvt
Part II · Module 26 · Chapter 26.3 · Corners
A corner is a set of physical conditions, plus the characterised data that models the silicon under them. Chapter 26.2 was about what the chip is being asked to do; this is about the conditions it is being asked to do it in.
1. The three axes of a corner
Process — where the fabricated transistors landed in the manufacturing distribution. ss (slow-slow, both device types slow), tt (typical), ff (fast-fast). Real decks have more: sf and fs where the two device types went opposite ways, and ssg/ffg global variants.
Voltage — the supply the block actually sees, which is lower than nominal under IR drop. 0p72v is 0.72 V; the lowest voltage is the slowest.
Temperature — junction temperature. Hot is usually slow, but not always: at low voltages, carrier mobility and threshold voltage move in opposite directions with temperature and the device can be slower cold. That is temperature inversion, and it is why a modern corner list includes a cold slow corner as well as a hot one rather than assuming hot is worst.
2. The tempting shortcut
Corner names are built to be readable, and they are so readable that they look like a data structure:
ss_0p72v_125c
Process, voltage, temperature — all right there. So why declare it twice? Parse it back out:
proc parse_corner_name {name} {
if {![regexp {^(ss|tt|ff)_(\d)p(\d+)v_(\d+)c$} $name -> proc_ whole frac temp]} {
return [list FAILED $name]
}
return [list OK $proc_ [expr {$whole + $frac / 100.0}] $temp]
}=== parsing the corner name back into data ===
ss_0p72v_125c -> OK ss 0.72 125
tt_0p80v_25c -> OK tt 0.8 25
ff_0p88v_m40c -> FAILED ff_0p88v_m40cThe repair reflex is to widen the pattern — (\d+|m\d+)c, then handle ssg, then the corner that has a library version suffix. That is Chapter 24.7's treadmill: each fix is correct and the set of names is not yours to control.
3. The argument that actually settles it
Fragility is the weaker objection. Here is the stronger one:
=== the same three corners, read from the declaration ===
ss_0p72v_125c process ss voltage 0.72 temp 125 derate 1.30
tt_0p80v_25c process tt voltage 0.80 temp 25 derate 1.00
ff_0p88v_m40c process ff voltage 0.88 temp -40 derate 0.72=== and what the name could never have carried ===
library : libs/ss_0p72v_125c.db
spef : spef/ss_125c.spef
derate : 1.30The name cannot hold the data that matters. A corner selects:
- a timing library — the
.dbor.libcharacterised at that PVT point, - an extracted parasitic file — the
.speffor the RC corner paired with it, - a derate factor, or several, applied on top,
and two of those three are file paths. You cannot encode a path inside a 20-character identifier, and the derate is a number nobody would guess from ss.
Note also that the .spef name is spef/ss_125c.spef — it does not match the corner name. RC extraction corners are a different axis from timing corners (§6), so the two file names genuinely differ, and any scheme that derives one from the other is wrong on purpose.
So the declaration is not duplication. The name is a label; the dict is the data, and the only thing the name should ever be used for is identifying which dict entry to look up.
4. The corner table
define_corner ss_0p72v_125c -process ss -voltage 0.72 -temp 125 -derate 1.30 \
-library libs/ss_0p72v_125c.db -spef spef/ss_125c.spef
define_corner tt_0p80v_25c -process tt -voltage 0.80 -temp 25 -derate 1.00 \
-library libs/tt_0p80v_25c.db -spef spef/tt_25c.spef
define_corner ff_0p88v_m40c -process ff -voltage 0.88 -temp -40 -derate 0.72 \
-library libs/ff_0p88v_m40c.db -spef spef/ff_m40c.spefNote -temp -40: a real negative number, because it is a number and not part of a string. The m40c spelling exists only in the filename, and converting it once at the boundary — rather than carrying m40 around as a pseudo-number — is what lets arithmetic and sorting work. That is Chapter 3.11's rule: parse at the edge, work with values inside.
What else belongs in a corner entry in a real flow:
define_corner ss_0p72v_125c \
-library libs/ss_0p72v_125c.db \
-spef spef/ss_125c.spef \
-derate 1.30 \
-opcond ss_0p72v_125c \
-rc_corner cworst \
-checks {setup} \
-reason "hot slow corner — setup sign-off"-checks {setup} is the one worth noticing. It says what this corner is for, and it is the data Chapter 26.4 prunes the cross-product with. Putting it on the corner rather than in the pruning rules keeps the justification next to the thing it justifies — the same reason Chapter 25.3 §4 pairs each filter rule with its sentence.
5. Why the derate decides which check fails where
=== the derate each corner applies ===
ss_0p72v_125c derate 1.30
tt_0p80v_25c derate 1.00
ff_0p88v_m40c derate 0.72One path, one base delay, three corners:
=== one path, the same base delay, at all three ===
base (cell + net) = 3.4500
ss_0p72v_125c arrival 4.4850 (3.4500 x 1.30)
tt_0p80v_25c arrival 3.4500 (3.4500 x 1.00)
ff_0p88v_m40c arrival 2.4840 (3.4500 x 0.72)The mock computes arrival = (cell_delay + net_delay) × derate, which is the whole of its physics — and it is enough to reproduce the real behaviour:
- Slow corner, derate 1.30. Everything arrives 30% later. Setup, which asks "did the data arrive in time", gets harder. Hold, which asks "did it arrive too early", gets easier.
- Fast corner, derate 0.72. Everything arrives 28% early. Setup gets easier; hold gets harder.
That is the whole reason there are at least two corners in any sign-off: the corner that is dangerous for one check is comfortable for the other. Chapter 26.1 §3's table is this arithmetic applied to three paths and three corners.
A real flow derates with more structure than one number — separately for cells and nets, separately for early and late paths, and often separately for the clock network and the data path, because applying the same pessimism to both cancels out a difference that matters. The single factor here is a teaching simplification and the chapter says so; what it models correctly is the direction.
6. Timing corners and RC corners are different axes
The honest complication, and the one that catches people moving from one-corner analysis to MCMM.
A timing corner is a PVT point: it selects the cell library. A parasitic corner is an extraction condition — how the metal came out — and it selects the .spef. They are characterised by different people from different data, and the conventional RC corner names (cworst, cbest, rcworst, rcbest, typical) have nothing to do with ss/tt/ff.
Which means the real corner list is itself a cross-product: PVT points × RC corners, pruned to the pairings the foundry and the project consider meaningful. And that is why -rc_corner cworst is a separate field from -library in §4 — the two are chosen independently and paired deliberately.
7. Exercises
Exercise 1. What are the three axes of a corner, and what does the corner select?
Exercise 2. Why is "hot is the slow corner" no longer a safe rule?
Exercise 3. The name parser worked on two of three corners. Which failed, why, and why is that the worst one to lose?
Exercise 4. What second, quieter defect did the tt parse have?
Exercise 5. Give the argument against name-parsing that does not depend on the pattern being fragile.
Exercise 6. Why does the .spef filename not match the corner name?
Exercise 7. Why is -temp -40 stored as a negative number rather than as m40?
Exercise 8. What does -checks {setup} on a corner do, and why keep it there?
Exercise 9. How does one derate factor reproduce the setup-slow/hold-fast behaviour?
Exercise 10. Someone says "we ran 5 corners". What three things might they mean?
Where this fits
Part of the Tcl curriculum.
