The Liberty File
Section 2.2 ran synthesis and compared results. Section 2.3 opens the files that made those results possible.
Every -liberty flag so far in this module, read_liberty, dfflibmap -liberty, abc -liberty, points at the same kind of file, and it is time to open one. A .lib (Liberty) file is the single source synthesis consults for every cost decision: which cell is faster, which is smaller, which drives more downstream logic without slowing down. Without it, ABC has no way to compare sky130_fd_sc_hd__nand2_1 against sky130_fd_sc_hd__nand2_4; they would be two names.
What Liberty describes
A Liberty file is a text-based (though machine-generated and machine-read) description of every cell in a library, characterised under specific process, voltage and temperature conditions (a PVT corner, which Module 7 returns to for multi-corner STA). For each cell it holds roughly four categories of data:
- Function: the Boolean behaviour of the cell, so tools can verify a substitution preserves logic.
- Input pin capacitance: how much load the cell’s inputs present to whatever drives them.
- Timing arcs: for every input-to-output path through the cell, a delay model, typically a lookup table indexed by input transition time and output load.
- Power: leakage, and dynamic switching power per transition.
Synthesis reads all four. Mapping (Section 2.1) leans mainly on function and timing arcs to pick a covering; the area-versus-delay bias of SYNTH_STRATEGY (Section 2.2) is a bias in how heavily the cost function weighs area (implied by cell size and drive strength) against those timing-arc delays.
Reading a cell entry
A representative entry, in the structure of the real Liberty syntax, for a 2-input NAND:
cell (sky130_fd_sc_hd__nand2_1) {
area : 3.75 ;
pin(A) {
direction : input ;
capacitance : 0.00218 ;
}
pin(B) {
direction : input ;
capacitance : 0.00206 ;
}
pin(Y) {
direction : output ;
function : "(A * B)'" ;
timing() {
related_pin : "A" ;
timing_sense : negative_unate ;
cell_rise(delay_template_7x7) {
index_1 ("0.0100, 0.0400, ..."); /* input slew */
index_2 ("0.0050, 0.0200, ..."); /* output load */
values ("0.0421, 0.0512, ...", \
"0.0509, 0.0601, ...");
}
}
}
}
Two fields to be able to point at without hesitation:
- Pin capacitance:
pin(A) { capacitance : 0.00218 ; }. This is the load, in picofarads, that theAinput presents to whatever drives it. Every input pin on every cell has one. - Delay: inside
cell_rise, thevaluestable gives propagation delay in nanoseconds fromAtoY, indexed by two variables: how slow the incoming edge is (index_1, input slew) and how much capacitance the output has to drive (index_2, output load). Real delay is not one number; it depends on both.
That two-dimensional table is the mechanism behind a fact you will rely on constantly from Module 4: a gate’s delay is not fixed. It depends on what drives it and what it drives. A nand2_1 feeding one nearby gate is faster than the same nand2_1 feeding a long, high-capacitance net across the die. Same cell, same entry, a different point in the same table.
One thing not to confuse: the area field is a relative sizing number useful for area estimates. It says nothing about a cell’s physical shape or pin locations. Liberty describes timing, power and function, and nothing about where pins sit or how big the footprint is on silicon. That is a different file, and the next article.
Practice Exercise
Given this trimmed entry for a buffer:
cell (sky130_fd_sc_hd__buf_2) {
area : 6.25 ;
pin(A) {
direction : input ;
capacitance : 0.00394 ;
}
pin(X) {
direction : output ;
function : "A" ;
}
}
What is the input pin capacitance, and what does function : "A" tell you about what the cell does logically, as opposed to what it is for?
Solution
The input capacitance is 0.00394 pF on pin A. function : "A" says the output is logically identical to the input; a buffer does not change the Boolean value at all. That looks pointless (why insert a gate that computes nothing?) but it is the point of a buffer: it exists for its electrical properties, restoring signal strength and driving more downstream capacitance than the original weak source could, not to compute. Buffers get inserted for exactly this reason throughout later modules, especially in clock tree synthesis in Module 5.
Liberty tells synthesis how fast and how power-hungry a cell is, but nothing about where its pins sit or how big a rectangle it occupies. In the next article we open the file that does: LEF.