第二章:时序分析基础——建立时间与保持时间、时钟偏斜、时钟抖动、时序路径分类
各位同学,咱们今天聊聊时序分析里最基础、也最绕不开的几个概念。说实话,我刚开始接触芯片设计那会儿,觉得时序分析就是算算延迟,没什么大不了的。直到有一次,我负责的一个28nm项目在post-sim阶段发现数据老是抓错,折腾了两周才发现是保持时间违例——从那以后,我再也不敢小看这些基础概念了。
2.1 建立时间与保持时间——寄存器的“脾气”
每个寄存器都有它的“脾气”。你给它送数据,它可不是随时都能稳稳接住的。它有两个硬性要求:
- 建立时间(Setup Time):时钟有效沿到来之前,数据必须提前稳定下来的最短时间。
- 保持时间(Hold Time):时钟有效沿到来之后,数据必须继续保持稳定的最短时间。
说白了,数据就像赶火车。建立时间要求你提前到站台等着,保持时间要求你上车后别急着下车。两个条件缺一不可。
核心公式(建立时间检查):
T_launch + T_clk2q + T_data_path + T_setup ≤ T_capture + T_cycle - T_skew
核心公式(保持时间检查):
T_launch + T_clk2q + T_data_path ≥ T_capture + T_hold + T_skew
我在项目中遇到过一件事:有个模块在慢工艺(0.18μm)下跑得好好的,换到28nm后频繁出错。查了半天,发现是保持时间违例。为什么?因为工艺越先进,线延迟占比越大,数据路径变短了,保持时间反而更难满足。嗯,这个坑我替你们踩过了。
我的个人习惯:做时序约束时,setup margin我会留5%~10%的余量,hold margin留3%~5%。别卡得太死,PVT变化会教你做人。
2.2 时钟偏斜(Clock Skew)——时钟到达时间的“偏差”
理想情况下,时钟信号应该同时到达所有寄存器。但现实是,时钟树有长度、有负载、有RC延迟。同一个时钟沿到达不同寄存器的时间差,就是时钟偏斜。
时钟偏斜分两种:
- 正偏斜(Positive Skew):捕获时钟晚于发射时钟。对setup有利,对hold有害。
- 负偏斜(Negative Skew):捕获时钟早于发射时钟。对hold有利,对setup有害。
你想想看,这就像接力赛——你希望下一棒选手稍微晚点出发(正偏斜),这样你有更多时间跑过去。但如果你跑得太慢,下一棒选手等不及先跑了(保持时间违例),那就掉棒了。
我曾经踩过的坑:在一个高性能CPU项目中,为了追求高频,我刻意引入了正偏斜来放松setup。结果hold时间全面崩盘,ECO修了整整两周。后来我学乖了——时钟树综合时,先保证hold,再优化setup。顺序搞反了,后面有你哭的。
2.3 时钟抖动(Jitter)——时钟周期的“不确定性”
时钟抖动,说白了就是时钟周期不是绝对固定的。PLL有相位噪声,电源有纹波,温度有变化——这些都会导致每个时钟周期的长度有微小波动。
抖动主要分两类:
- 周期抖动(Period Jitter):相邻周期之间的差异。影响setup分析。
- 长期抖动(Long-term Jitter):多个周期累积的偏差。影响hold分析?其实影响不大,因为hold只关心同一个时钟沿附近的行为。
我记得有一次做DDR控制器,频率跑到1.6Gbps,PLL的jitter指标是±30ps。算下来,setup margin被吃掉了一大半。没办法,只能降频到1.4Gbps才稳定。所以啊,选PLL的时候别只看频率,jitter指标同样要命。
时序分析中如何处理jitter?
// 典型STA工具中的jitter设置示例
set_clock_uncertainty -setup 0.15 [get_clocks clk_sys]
set_clock_uncertainty -hold 0.05 [get_clocks clk_sys]
setup的uncertainty通常包含jitter + margin,hold的uncertainty主要留margin。别搞混了。
2.4 时序路径分类——四种路径,四种“性格”
静态时序分析把路径分成四类。每种路径的约束方法和分析重点都不一样。我习惯把它们想象成四种不同的“交通路线”:
| 路径类型 | 起点 | 终点 | 特点 |
|---|---|---|---|
| 输入到寄存器 | 输入端口 | 寄存器D端 | 受input delay约束,外部路径不可控 |
| 寄存器到寄存器 | 寄存器CK端 | 寄存器D端 | 最核心的路径,综合工具主要优化对象 |
| 寄存器到输出 | 寄存器CK端 | 输出端口 | 受output delay约束,要留够外部接口时间 |
| 输入到输出 | 输入端口 | 输出端口 | 纯组合路径,通常要加约束或插入寄存器 |
为什么这么分?因为每种路径的约束来源不同。
- 寄存器到寄存器:这是你的“主场”,综合工具能帮你优化。我一般先看这条路径的slack,如果这里都违例,那基本是代码风格或架构问题。
- 输入到寄存器:外部芯片的延迟你管不了,只能通过input delay约束来“告诉”工具。我曾经遇到一个客户,input delay设得太乐观,结果芯片回来接口时序全挂——嗯,这个锅得前端设计背。
- 寄存器到输出:同理,output delay要留够余量。特别是驱动大负载时,输出缓冲的延迟会很大。
- 输入到输出:纯组合路径最危险。我建议除非有特殊原因,否则尽量在中间插一级寄存器。不然PVT一变化,这条路径第一个崩。
一个小技巧:在做时序报告分析时,我习惯先看“寄存器到寄存器”路径的WNS(最差负slack)。如果WNS是负的,别急着改代码,先确认时钟约束和input/output delay设得对不对。很多时候,问题出在约束上,而不是电路本身。
2.5 小结——这些概念怎么串起来?
建立时间和保持时间是寄存器的“底线”,时钟偏斜和抖动是“干扰因素”,时序路径分类是“分析对象”。四者合在一起,就是STA的完整框架。
我个人习惯在做完综合后,先跑一遍setup检查,再跑hold检查。如果setup违例,先看是不是时钟频率设太高;如果hold违例,先看是不是时钟树偏斜太大。别一上来就改代码,先分析,再动手。
下一章我们会聊时序约束的具体写法。到时候我会拿一个实际项目中的SDC文件来拆解——嗯,那个文件当年改了我整整三天。