时序库(liberty)详解:单元延时、查找表、时序弧
各位,咱们今天来聊聊 liberty 库。说实话,这玩意儿是 STA 的“字典”。没有它,你连门延时都算不出来。我刚入行那会儿,以为 liberty 就是一堆表,后来被坑过一次才明白——里面藏着芯片速度的命脉。
什么是 Liberty 库
Liberty(通常叫 .lib)是 Synopsys 定义的标准时序库格式。它描述了一个标准单元库里每个单元的:
- 输入引脚到输出引脚的传播延时
- 时序约束(setup / hold / recovery / removal)
- 功耗、面积、电容等参数
我个人习惯把 liberty 文件叫作“单元的身份证”。每个工艺节点、每个电压温度(PVT)组合都会生成一份独立的 .lib。你想想看,一个 7nm 库可能有几千个单元,每个单元有十几条时序弧,光解析就得花点功夫。
查找表(LUT)的结构
先看一段真实的 .lib 片段。别怕,我拆开讲。
cell (AND2X1) {
pin (A) {
direction : input;
capacitance : 0.0032;
timing () {
related_pin : "Y";
timing_sense : positive_unate;
cell_rise (delay_template_7x7) {
index_1 ("0.01, 0.05, 0.1, 0.2, 0.5, 1.0, 2.0"); // 输入转换时间 (ns)
index_2 ("0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1.0"); // 输出负载电容 (pF)
values ( \
"0.012, 0.018, 0.025, 0.040, 0.065, 0.110, 0.200", \
"0.015, 0.020, 0.030, 0.045, 0.070, 0.120, 0.210", \
... // 共7x7=49个值
);
}
}
}
}
一个查找表由两个索引(index_1, index_2)和一个二维数组组成。索引是固定的采样点,实际工作时要靠线性插值算出非采样点的延时。
我曾经遇到一个问题:某库的 index_1 只给了3个点,导致高频下延时误差大。嗯,后来我跟库厂商吵了一架,让他们加了密度。
延时模型的计算
一个典型的两输入与非门,它的cell_rise和cell_fall分别对应输出上升沿和下降沿的传播延时。每个查找表的名字指向一个模板(template),模板定义了索引轴的范围和单位。
| 模板名 | 索引1(输入转换) | 索引2(输出负载) | 单位 |
|---|---|---|---|
| delay_template_5x5 | 0.01, 0.1, 0.5, 1.0, 2.0 | 0.01, 0.05, 0.1, 0.5, 1.0 | ns / pF |
| delay_template_7x7 | 0.01, 0.05, 0.1, 0.2, 0.5, 1.0, 2.0 | 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1.0 | ns / pF |
你可能会问:为什么不直接用公式?因为现代工艺下延时跟输入转换和负载的关系非常非线性,查表加插值才是最精确的办法。说白了,这是用存储空间换精度。
时序弧详解
除了传播延时,liberty 里还有一堆“弧”(arc)。每条弧描述的是两个引脚之间的时序关系。我把它分为两类:
- 组合弧:从输入到输出的直通延时,比如 AND 门的 A→Y。
- 约束弧:定义时序检查,包括 setup、hold、recovery、removal、minimum pulse width 等。
看一个 setup 弧的例子:
pin (CK) {
timing () {
related_pin : "D";
timing_type : setup_rising;
rise_constraint (constraint_template_5x5) {
index_1 ("0.01, 0.1, 0.5, 1.0, 2.0"); // CK 的转换时间
index_2 ("0.01, 0.1, 0.5, 1.0, 2.0"); // D 的转换时间
values ( ... );
}
}
}
这里 timing_type 指定了弧类型。常见的类型有:
| timing_type | 含义 | 用于 |
|---|---|---|
| setup_rising | 上升沿触发的建立时间 | D 相对 CK 上升沿 |
| hold_falling | 下降沿触发的保持时间 | D 相对 CK 下降沿 |
| recovery_rising | 复位信号的恢复时间 | 复位相对时钟 |
| removal_falling | 复位信号的移除时间 | 复位相对时钟 |
| min_pulse_width_high | 高电平最小脉宽 | 时钟、复位 |
你可能会问,为什么 setup 和 hold 也要用查找表?因为信号转换时间越慢,需要预留的余量越大。举个例子,如果 D 的转换时间很长(比如 2ns),setup 时间可能比 0.1ns 转换时要多出好几倍。这就是 LUT 存在的意义。
个人习惯总结
- 新项目拿到 liberty 后,我会先跑一遍
report_lib看是否有缺失的模板或奇怪的索引范围。 - 对于高频模块(>1GHz),我建议要求库厂商提供 7x7 以上的 LUT,否则延时误差会吃掉时序裕量。
- 注意 timing_sense:positive_unate(同向变化)、negative_unate(反向变化)、non_unate(未知)。这影响你判断路径是否可能同时翻转。
report_timing -nosplit -transition_time -capacitance 看每个 pin 的 actual transition 和 load,然后手动查 .lib 验证插值结果。我曾经用这个方法抓到一个库的错误。
好了,关于 liberty 库的核心就这些。下次你再看到那些密密麻麻的表,心里要清楚:它们就是芯片性能的“天气预报”——依赖它,才能知道你的设计能不能按时到达终点。