第二章:STA基础回顾——建立时间与保持时间、时序路径分类
各位同学,咱们今天聊点实在的。
静态时序分析,说白了就是检查你的芯片能不能跑在目标频率上。我刚开始做设计时总觉得这步可有可无,直到有一次流片回来芯片死活上不了高频……嗯,从那以后我再也不敢跳过STA了。
2.1 建立时间与保持时间——芯片的“心跳”规则
先问大家一个问题:为什么寄存器会采样到错误的数据?
答案就藏在两个时间参数里——建立时间(setup time)和保持时间(hold time)。
建立时间(Tsu):时钟有效沿到来之前,数据必须保持稳定的最短时间。
保持时间(Th):时钟有效沿到来之后,数据必须保持稳定的最短时间。
我习惯把这两个时间想象成“数据登车”的过程。时钟沿就像火车到站,建立时间是“你必须提前在站台等着”,保持时间是“车开了你别急着跳下来”。
咱们来看一个典型的时序检查公式:
// 建立时间检查
Tclk + Tskew >= Tcq + Tcomb + Tsu
// 保持时间检查
Tcq + Tcomb >= Th + Tskew
这里Tclk是时钟周期,Tskew是时钟偏斜,Tcq是寄存器输出延迟,Tcomb是组合逻辑延迟。
我的经验:在项目中,建立时间违例通常可以通过降低频率或优化组合逻辑来解决。但保持时间违例更棘手——它和频率无关,必须通过插入延迟单元或调整路径来修复。
我曾经在一个28nm的项目中遇到保持时间违例,查了三天才发现是时钟树综合时skew没控制好。嗯,从那以后我每次做CTS都会格外关注hold margin。
2.2 时序路径分类——四种路径,四种脾气
STA把时序路径分成四类。你想想看,这就像把芯片里的信号流动分成了四种“交通路线”。
咱们用一张图来直观理解:
2.3 四种路径的实战要点
reg2reg路径
这是STA中最常见的路径。说白了,就是两个寄存器之间的数据传输。
// reg2reg路径的约束示例
create_clock -name clk -period 10 [get_ports clk]
set_clock_uncertainty -setup 0.2 [get_clocks clk]
set_clock_uncertainty -hold 0.1 [get_clocks clk]
注意:reg2reg路径的时序裕量计算,一定要考虑clock skew和jitter。我见过有人只算逻辑延迟,结果流片回来发现setup margin不够。
reg2out路径
这类路径的难点在于——输出端口的负载是未知的。你想想看,芯片外面的PCB走线、接收端的输入电容,这些都会影响输出延迟。
我的做法是:在约束中给输出路径留出20%~30%的余量。比如:
set_output_delay -clock clk -max 4.0 [get_ports data_out]
set_output_delay -clock clk -min 1.0 [get_ports data_out]
in2reg路径
输入路径的约束,关键是要知道外部数据相对于时钟的相位关系。我曾经在一个项目中,因为输入延迟约束设得太紧,导致综合工具疯狂插入buffer,面积暴涨了15%。
避坑指南:我曾经在约束in2reg路径时,把输入延迟设成了0。结果STA报告全是绿的,但芯片实际工作时根本采不到正确数据。后来才明白——输入延迟必须根据外部器件的时序参数来设置。
in2out路径
这类路径没有寄存器,纯组合逻辑。通常用set_max_delay来约束。
set_max_delay -from [get_ports data_in] -to [get_ports data_out] 5.0
嗯,这里要注意:in2out路径的约束不能太紧,否则工具会拼命优化组合逻辑,导致面积和功耗失控。
2.4 四种路径的优先级
| 路径类型 | 优先级 | 常见问题 | 我的建议 |
|---|---|---|---|
| reg2reg | 最高 | setup/hold违例 | 先修这个,它决定芯片能否工作 |
| in2reg | 高 | 输入约束不准 | 和系统工程师对齐外部时序 |
| reg2out | 中 | 输出负载影响 | 留足余量,别太紧 |
| in2out | 低 | 纯组合路径 | 用set_max_delay约束即可 |
最后说一句:STA不是跑一遍就完事的。我习惯在综合后、布局后、时钟树综合后、布线后各跑一次STA,每次关注的重点都不一样。嗯,这个咱们后面章节再细聊。