静态时序分析STA基础
各位工程师,今天我们来聊聊STA。说白了,它就是检查你的芯片能不能跑在目标频率上的一套数学方法。我刚接触数字设计时总觉得这步可有可无,直到有一次流片回来芯片死活上不了高频——后来一查,就是时序路径没分析透。嗯,从那以后,我再也不敢跳过STA了。
一句话理解STA: 静态时序分析不依赖测试向量,而是穷举所有可能的路径,计算每条路径的延迟,然后检查是否满足时序约束。它跟动态仿真最大的区别就是——不需要你给激励,它自己把所有情况都覆盖了。
1. 到底什么是STA?
静态时序分析,英文叫 Static Timing Analysis,简称 STA。它不是仿真,而是用一种穷举的方式去算每一条时序路径的延迟。你想想看,动态仿真跑一万个向量可能只覆盖了20%的路径,但STA一次性把所有路径都扫了一遍。
我个人的理解是:STA就像给芯片做一次全面的体检,每条路径都是体检项目,时序约束就是体检标准。超标的地方就是violation,必须修。
STA的核心输入有三个:网表(netlist)、时序约束(SDC)、工艺库(Liberty)。输出就是一份详细的时序报告,告诉你哪些路径过了,哪些没过的。
知识卡片: STA是同步数字电路设计的标配。只要你的设计是同步时序逻辑(有时钟),STA就是必须过的关口。异步电路不适用STA,得用专门的异步分析方法。
2. 四种路径类型,你搞清楚了吗?
STA把时序路径分成四类。这可不是随便分的——每种路径对应的约束命令和检查方式都不一样。我在项目里见过不少新人把input delay和output delay搞反,结果时序报告一片红。
四种路径分别是:
- 输入到输出(Input to Output) —— 路径从芯片的输入端口开始,经过组合逻辑,直接到输出端口。这种路径没有寄存器,纯组合路径。
- 寄存器到寄存器(Register to Register) —— 从触发器的时钟端到下一个触发器的数据输入端。这是最核心的路径类型,决定了芯片的主频。
- 输入到寄存器(Input to Register) —— 从芯片输入端口到第一个触发器的数据输入端。需要约束输入延时。
- 寄存器到输出(Register to Output) —— 从最后一个触发器的时钟端到芯片输出端口。需要约束输出延时。
避坑提醒: 我曾经在一个项目中,把输入到寄存器的路径约束写错了——set_input_delay给的是max值,但忘了给min值,结果setup和hold都跑偏了。两种延时都要给,别漏。
下面这个表把这四种路径的关键信息做了对比,建议你收藏:
| 路径类型 | 起点 | 终点 | 约束方式 | 典型场景 |
|---|---|---|---|---|
| 输入→输出 | 输入端口 | 输出端口 | set_input_delay + set_output_delay | 纯组合通路 |
| 寄存器→寄存器 | 寄存器时钟端 | 寄存器数据端 | create_clock | 核心时序路径 |
| 输入→寄存器 | 输入端口 | 寄存器数据端 | set_input_delay | 片外到片内 |
| 寄存器→输出 | 寄存器时钟端 | 输出端口 | set_output_delay | 片内到片外 |
举个例子,假设你有一个芯片,外部数据从PIN进来先经过一段组合逻辑再打到寄存器。这就是典型的「输入到寄存器」路径。你在SDC里要这么写:
# 约束输入路径
create_clock -name clk -period 10 [get_ports clk]
set_input_delay -clock clk -max 3.0 [get_ports data_in]
set_input_delay -clock clk -min 1.5 [get_ports data_in]
你看,max和min都要给。max用于setup检查,min用于hold检查。
3. 时序弧——时序分析的基本单元
时序弧(Timing Arc)是什么?说白了,就是从一个引脚到另一个引脚的延迟路径。在Liberty库里,每个标准单元都定义了一组时序弧。
时序弧分两大类:
- 组合时序弧: 从一个输入引脚到输出引脚,中间是组合逻辑。比如与门从A到Y,或非门从B到ZN。这种弧只跟输入转换时间和输出负载有关。
- 寄存器时序弧: 跟时钟相关的弧。包括:
- 建立时间(setup time):数据必须在时钟沿之前多久稳定
- 保持时间(hold time):数据必须在时钟沿之后保持多久
- 时钟到输出(clock-to-Q):时钟沿到数据输出的延迟
- 恢复时间(recovery)和移除时间(removal):针对异步复位/置位端
我刚开始学STA时,对「时序弧」这个概念很模糊。后来有一次debug一个hold violation,查了半天发现是库里的时序弧定义有问题——那个寄存器的hold弧用的是负值,工具没正确处理。从此我每次换库都会先看一眼时序弧的定义。
在Liberty库中,时序弧的描述大概是这样的:
pin (Q) {
timing () {
related_pin : "CK";
timing_type : "rising_edge";
cell_rise (delay_template_7x7) {
index_1 ("0.1, 0.3, 0.7, 1.2, 2.0, 3.0, 5.0");
index_2 ("0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1.0");
values ( \
"0.12, 0.15, 0.19, 0.25, 0.35, 0.55, 0.85", \
"0.14, 0.17, 0.21, 0.27, 0.37, 0.57, 0.87", \
...
);
}
}
}
这是一个从CK到Q的上升沿clock-to-Q时序弧。index_1是输入转换时间,index_2是输出负载电容,values就是对应的延迟值。查表的时候工具会根据实际的转换时间和负载做二维插值。
实用技巧: 查时序弧时要注意是「上升沿」还是「下降沿」,还有是「rise」还是「fall」的延迟。同一个引脚对不同边沿的延迟可能差很大,尤其是不对称的单元。
4. 延迟计算——不只是加加减减
延迟计算是STA的核心算术。一条路径的总延迟 = 所有cell延迟之和 + 所有net延迟之和。但每个cell和net的延迟怎么算?这里头有门道。
单元延迟(Cell Delay): 跟两个因素有关——输入转换时间(input transition)和输出负载电容(output load)。在Liberty库里,每个时序弧对应一个二维查找表(NLDM模型)。工具用线性插值或二次插值算出具体值。
连线延迟(Net Delay): 跟互连线的RC有关。在深亚微米工艺下,net delay越来越重要,甚至超过cell delay。常用的模型包括:
- 集总RC模型(lumped RC)
- π模型(pi model)
- 分布式RC模型(distributed RC)
我记得在一个28nm的项目中,有一条关键路径,cell delay只占了40%,剩下的60%都是net delay。当时我们优化了半天cell尺寸没效果,最后发现是绕线太长,插了几个缓冲器才把时序修通。
避坑指南: 我曾经吃过一次亏——做post-layout STA时发现一条路径的setup违例很严重,但前仿真明明都过了。后来查出来是连线延迟计算时用的RC parasitic文件版本不对,用了pre-route的数据。记住:post-layout一定要用提取出来的真实RC,别偷懒。
下面这个表总结了延迟计算的关键因素:
| 延迟类型 | 影响因素 | 计算模型 | 工艺相关性 |
|---|---|---|---|
| 单元延迟 | 输入转换时间 / 输出负载 / PVT | NLDM / CCS / ECSM | 高(随工艺角变化大) |
| 连线延迟 | 线长 / 线宽 / 线间距 / 层数 | RC π模型 / 分布式模型 | 中(主要受尺寸影响) |
| 时钟延迟 | 时钟树结构 / buffer插入 | 同单元延迟计算 | 高 |
在实际项目中,延迟计算还跟工艺角(Process Corner)强相关。常见的工艺角有tt(典型)、ss(慢)、ff(快)等。你的芯片必须在所有工艺角下都满足时序约束,这就是所谓的「全角收敛」。
核心公式(理解即可,不用背):
路径总延迟 = Σ(Cell Delay) + Σ(Net Delay)
Setup Slack = 时钟周期 - (数据路径延迟 - 时钟路径延迟) - Setup Time
Hold Slack = 数据路径延迟 - 时钟路径延迟 - Hold Time
slack > 0 表示路径满足要求,slack < 0 就是violation。
嗯,STA的这些基础概念说复杂也复杂,说简单也简单。关键是你得把路径类型、时序弧、延迟计算这三块串起来理解。它们不是孤立的,而是互相联动的——路径类型决定了你要约束哪些弧,而每条弧的延迟计算又决定了路径最终的slack。搞明白这个逻辑链条,STA就算入门了。