Every delay number you see in a timing report comes from a Liberty (.lib) file. Liberty is the standard-cell timing database that tells STA tools how fast each gate switches, what slew rates it produces, and what setup/hold constraints each flip-flop imposes. Understanding how Liberty files are structured — and how STA tools query them — is the difference between guessing at timing results and actually understanding them.
A Liberty (.lib) file is a plain-text timing database provided by your standard cell library vendor (e.g., TSMC, Samsung, GlobalFoundries). Every cell in the library — inverters, AND gates, flip-flops, MUXes, memories — has an entry in the .lib file describing its timing, power, and area characteristics.
The STA tool reads the .lib file alongside your gate-level netlist. For every cell instance in the design, the tool looks up that cell’s timing arcs in the Liberty database, queries the appropriate delay given the actual input slew and output load, and uses that delay to compute path arrival times.
A typical 28nm standard cell library has one .lib file per PVT corner — so you might have sc9_ss_0p81v_125c.lib (slow-slow corner), sc9_tt_1p0v_25c.lib (typical), and sc9_ff_1p1v_n40c.lib (fast-fast), plus many more combinations.
Liberty uses a hierarchical block syntax. The top level is the library block; inside it are cell blocks; inside those are pin blocks; inside pin blocks are timing groups with the actual delay tables.
/* ── Top-level library block ── */
library (sc9_tt_1p0v_25c) {
/* Library-level attributes */
technology (cmos);
delay_model : table_lookup; /* NLDM */
time_unit : "1ns";
voltage_unit : "1V";
capacitive_load_unit (1, pf);
nom_process : 1.0;
nom_voltage : 1.0;
nom_temperature : 25;
/* Default output transition (slew) thresholds */
slew_lower_threshold_pct_rise : 20.0;
slew_upper_threshold_pct_rise : 80.0;
/* Operating conditions block */
operating_conditions (typical) {
process : 1.0;
voltage : 1.0;
temperature : 25;
}
/* ── Cell block ── */
cell (AND2X2) {
area : 4.32;
/* ── Pin block: output ── */
pin (Z) {
direction : output;
function : "(A*B)";
max_fanout : 16;
/* ── Timing arc: A → Z (combinational) ── */
timing () {
related_pin : "A";
timing_type : combinational;
timing_sense : positive_unate;
/* Cell delay table (NLDM) */
cell_rise (delay_template_7x7) {
index_1 ("0.01,0.02,0.04,0.08,0.16,0.32,0.64"); /* input transition */
index_2 ("0.001,0.002,0.004,0.008,0.016,0.032,0.064"); /* output cap */
values (
"0.021,0.025,0.033,0.048,0.078,0.138,0.258",
"0.026,0.030,0.038,0.053,0.083,0.143,0.263",
"0.036,0.040,0.048,0.063,0.093,0.153,0.273",
...
);
}
/* rise_transition, cell_fall, fall_transition tables follow */
}
}
/* ── Pin block: clock of internal FF (sequential) ── */
pin (CK) {
direction : input;
clock : true;
}
} /* end cell AND2X2 */
} /* end library */
Liberty supports multiple delay model types. The two most commonly used in STA are NLDM and CCS.
| Attribute | NLDM (Non-Linear Delay Model) | CCS (Composite Current Source) |
|---|---|---|
| Model approach | Precharacterised delay + output slew as 2D tables (input_transition × output_cap) | Cell modeled as a time-varying current source; captures actual output waveform shape |
| Accuracy | Good for 90nm–28nm; less accurate for steep-slew or receiver-dominated paths | High accuracy at 28nm and below; models waveform distortion and receiver dependence |
| Runtime | Fast; bilinear table lookup | Slower; requires waveform integration at each receiver |
| Liberty keyword | delay_model : table_lookup | delay_model : ccs; uses output_current_rise tables |
| Typical use | Synthesis, early STA, RTL sign-off, most 65nm+ flows | Post-layout sign-off at 28nm and below; SI-aware STA |
For most 65nm–28nm sign-off flows, NLDM is accurate enough and is the default. For 16nm/7nm and below — where receiver input capacitance and waveform shape significantly affect timing — CCS (or its ECSM equivalent from Cadence) is required for accurate sign-off. Your foundry PDK will specify which model type to use per node.
When STA encounters a cell during path propagation, it needs to know: (a) how long before the output switches after the input switches (cell delay), and (b) how fast the output transitions (output slew, which becomes the next cell’s input transition). Both are in NLDM tables indexed by two variables:
The tool performs bilinear interpolation when the actual values fall between table entries. If the actual input slew or output cap exceeds the table range, the tool extrapolates — which can be less accurate, which is why libraries are typically characterised to cover realistic on-chip ranges.
/* cell_rise table for INV_X1, arc: A → ZN */
cell_rise (delay_template_5x5) {
/* index_1 = input transition time (ns) */
index_1 ("0.01, 0.04, 0.10, 0.20, 0.40");
/* index_2 = output load capacitance (pF) */
index_2 ("0.001, 0.004, 0.010, 0.020, 0.040");
values (
/* cap: 0.001 0.004 0.010 0.020 0.040 */
"0.018, 0.024, 0.034, 0.053, 0.091", /* trans=0.01 */
"0.022, 0.028, 0.038, 0.057, 0.095", /* trans=0.04 */
"0.030, 0.036, 0.046, 0.065, 0.103", /* trans=0.10 */
"0.043, 0.049, 0.059, 0.078, 0.116", /* trans=0.20 */
"0.068, 0.074, 0.084, 0.103, 0.141" /* trans=0.40 */
);
}
/* Example lookup:
Actual input transition = 0.07 ns (between 0.04 and 0.10)
Actual output cap = 0.007 pF (between 0.004 and 0.010)
Bilinear interpolation:
- At trans=0.04: delay(0.007) = 0.028 + (0.007-0.004)/(0.010-0.004)*(0.038-0.028) = 0.033
- At trans=0.10: delay(0.007) = 0.036 + 0.5*0.010 = 0.041
- Final: 0.033 + (0.07-0.04)/(0.10-0.04)*(0.041-0.033) = 0.037 ns
*/
A timing arc describes the timing relationship between two pins of a cell. Liberty defines several arc types:
| Arc type | Liberty keyword | Description | Example |
|---|---|---|---|
| Combinational | combinational | Data flows from input pin to output pin through combinational logic | AND gate: A→Z, B→Z |
| Rising_edge | rising_edge | Sequential arc: output changes on rising clock edge (clock-to-Q) | DFF: CK→Q |
| Falling_edge | falling_edge | Output changes on falling clock edge | Negative-edge DFF: CK→Q |
| Setup_rising | setup_rising | Setup constraint arc: D must be stable before rising CK | DFF: D to CK setup |
| Hold_rising | hold_rising | Hold constraint arc: D must be stable after rising CK | DFF: D to CK hold |
| Three_state_enable | three_state_enable | Output enable arc for tri-state buffer | TBUF: OE→Z |
| Three_state_disable | three_state_disable | Output disable (high-Z) arc for tri-state buffer | TBUF: OE→Z (high-Z) |
Each arc also carries a timing_sense attribute that describes how the input signal polarity affects the output:
STA uses timing_sense to determine whether to propagate a rising or falling transition through a path, which affects which delay table (cell_rise vs cell_fall) to look up.
Flip-flops have two special arc types that define their timing constraints. These are different from propagation arcs — they don’t produce delay, they consume margin from the path budget.
cell (DFFX1) {
area : 6.48;
/* Flip-flop state description */
ff (IQ, IQN) {
next_state : "D";
clocked_on : "CK";
}
/* ── Clock-to-Q arc (propagation) ── */
pin (Q) {
direction : output;
function : "IQ";
timing () {
related_pin : "CK";
timing_type : rising_edge; /* triggers on CK rising edge */
timing_sense : non_unate;
cell_rise (delay_template_7x7) {
/* Q rises after CK: table[input_transition][output_cap] */
index_1 ("0.01,0.02,...");
index_2 ("0.001,0.002,...");
values ( "0.045,0.052,...", ... );
}
cell_fall (delay_template_7x7) { ... }
}
}
/* ── Setup arc (D → CK) ── */
pin (D) {
direction : input;
timing () {
related_pin : "CK";
timing_type : setup_rising; /* D must be valid before CK rises */
/* Setup time vs input transition (1D table indexed by D slew) */
rise_constraint (constraint_template_7x7) {
index_1 ("0.01,0.02,..."); /* D transition */
index_2 ("0.01,0.02,..."); /* CK transition */
values ( "0.041,0.044,...", ... );
}
fall_constraint (constraint_template_7x7) { ... }
}
/* ── Hold arc (D → CK) ── */
timing () {
related_pin : "CK";
timing_type : hold_rising; /* D must remain valid after CK rises */
rise_constraint (constraint_template_7x7) { ... }
fall_constraint (constraint_template_7x7) { ... }
}
}
} /* end DFFX1 */
In modern standard cell libraries, hold time values are often negative — this means the data can change slightly before the clock edge and still be captured correctly. STA interprets a negative hold time by requiring a shorter minimum path. Negative hold values are not a mistake; they are the result of the flip-flop’s internal circuitry having a built-in time slack on its data latch path.
Liberty arcs can carry additional attributes that modify how STA handles them:
when — conditional arc that only applies when a Boolean expression on other pins is true (e.g., MUX select = 0 for one input arc, MUX select = 1 for the other). STA checks only arcs whose when condition matches set_case_analysis settings.sdf_cond — SDF back-annotation condition; connects to timing annotation during gate-level simulationmode — functional mode conditioning; allows different timing models for scan vs functional operationcell (MUX2X1) {
pin (Z) {
direction : output;
function : "(S*B) + (!S*A)";
/* Arc A→Z only active when S=0 */
timing () {
related_pin : "A";
when : "!S";
timing_type : combinational;
timing_sense : positive_unate;
cell_rise (delay_template_7x7) { ... }
}
/* Arc B→Z only active when S=1 */
timing () {
related_pin : "B";
when : "S";
timing_type : combinational;
timing_sense : positive_unate;
cell_rise (delay_template_7x7) { ... }
}
/* Select arc: S→Z (non-unate) */
timing () {
related_pin : "S";
timing_type : combinational;
timing_sense : non_unate;
cell_rise (delay_template_7x7) { ... }
}
}
}
The STA tool’s delay computation follows this sequence for every cell in a timing path:
timing_type and any when conditions (from set_case_analysis)cell_rise or cell_fall) at (input_transition, output_load)rise_transition or fall_transition) to get the output slew for the next cellAt flip-flop endpoints, the tool uses the setup_rising arc to get the required setup time and subtracts it from the clock arrival to compute the required time. Slack = required time − arrival time.
One Liberty file represents one operating condition (one PVT corner). For setup analysis you read a slow corner .lib; for hold you read a fast corner .lib. The tool loads multiple .lib files when running MCMM (Multi-Corner Multi-Mode) analysis. Every number in a Liberty table — delays, setup times, hold times — is valid only at the PVT corner it was characterised for.
## Load a Liberty file
read_lib /pdk/tsmc28/lib/sc9_tt_1p0v_25c.lib
## Check which cells are loaded
list_libs
## Query timing arcs for a specific cell
get_lib_attribute sc9_tt_1p0v_25c/AND2X2 cell_footprint
report_lib sc9_tt_1p0v_25c/DFFX1
## Query setup time for a flip-flop at specific slew values
set_lib_attribute sc9_tt_1p0v_25c/DFFX1/D \
setup_rising rise_constraint
## Report all timing arcs for a cell (from netlist instance)
report_timing -through [get_cells u_adder/FF_result] \
-delay_type max -nworst 1
## Check if a Liberty arc is being used
get_lib_timing_arcs -from [get_lib_pins sc9/AND2X2/A] \
-to [get_lib_pins sc9/AND2X2/Z]
A Liberty (.lib) file is the timing database for a standard cell library. It contains cell delay, output slew, setup/hold constraints, and power data for every cell, modelled as lookup tables indexed by input transition time and output capacitance. STA tools read Liberty files to compute cell delays during path analysis.
NLDM (Non-Linear Delay Model) stores delay as a precomputed 2D table — fast to look up via bilinear interpolation. CCS (Composite Current Source) models the cell output as a time-varying current source, capturing the actual output waveform and receiver-dependent delay with higher accuracy. NLDM is used for 90nm–28nm; CCS is required for accurate sign-off at 16nm and below.
A timing arc is the timing relationship between two pins of a cell. Combinational arcs model input-to-output propagation delay. Sequential arcs model clock-to-Q delay for flip-flops. Setup and hold arcs are constraint arcs that define how much time the data must be stable before/after the clock edge. Three-state arcs model tri-state buffer enable/disable timing.
The STA tool computes the actual input slew (from the previous cell’s output transition table) and the actual output load (wire cap from SPEF + receiver capacitances from Liberty). It then does bilinear interpolation in the NLDM cell_rise or cell_fall table at those two coordinates to get the exact cell delay and output slew.
A negative hold time means the flip-flop’s internal latch can correctly capture data that changes slightly before the clock edge. This occurs because the latch’s master stage has a small propagation delay, giving it an effective negative hold window. STA handles negative hold values correctly — it means the minimum path only needs to be slightly longer than the clock-to-Q of the previous flip-flop, not necessarily longer than the entire clock period.