时序路径与约束:建立时间、保持时间、时序路径类型
各位同学,今天我们来聊聊时序分析里最基础、也最绕不开的两个概念——建立时间和保持时间。说实话,我刚入行那会儿,总觉得这两个东西就是背背公式的事。直到有一次,我负责的一个28nm项目在post-route阶段发现大量setup违例,改得我头皮发麻……从那以后,我才真正理解了什么叫「纸上得来终觉浅」。
建立时间与保持时间:芯片的「心跳」规则
先说说建立时间(setup time)。说白了,就是数据在时钟有效沿到来之前,必须提前稳定下来的那段时间。你想想看,寄存器内部有个采样窗口,数据如果来得太晚,采样结果就可能出错。
建立时间检查的本质:数据到达时间 ≤ 时钟到达时间 + 时钟周期 - 建立时间
保持时间(hold time)正好反过来。它要求数据在时钟有效沿之后,还要再维持一段时间不变。为什么?因为寄存器内部的锁存器需要时间把数据「锁住」。如果数据变化太快,刚采到的值就被冲掉了。
我记得有个项目,后端做完时钟树综合后,hold violation一大堆。排查了半天,发现是时钟偏斜太大,导致数据路径太短。嗯,这里要注意——hold violation通常跟时钟频率无关,只跟工艺偏差和时钟偏斜有关。你降频也救不了hold问题。
时序路径的四种类型
实际项目中,我们遇到的时序路径无非这四种。我习惯把它们画在一张图上,这样看全局更清楚。
| 路径类型 | 起点 | 终点 | 典型场景 |
|---|---|---|---|
| 输入到输出 | 芯片输入端口 | 芯片输出端口 | 纯组合逻辑路径 |
| 输入到寄存器 | 芯片输入端口 | 寄存器数据端 | 片外信号同步 |
| 寄存器到寄存器 | 寄存器时钟端 | 寄存器数据端 | 核心逻辑路径 |
| 寄存器到输出 | 寄存器时钟端 | 芯片输出端口 | 输出数据驱动 |
寄存器到寄存器路径:最核心的路径
这类路径占了芯片中90%以上的时序检查。它的公式很简单:
数据路径延迟 + 建立时间 ≤ 时钟周期 + 时钟偏斜
我曾经在一个高性能CPU项目中,发现某条关键路径的setup slack只有5ps。当时整个团队都在找优化方案——换VT单元、调整尺寸、甚至重做floorplan。最后发现是时钟树上一级buffer的驱动能力不够,换了个大尺寸的立马解决了。所以说,有时候问题不在数据路径,而在时钟路径。
我的个人习惯:在做完时钟树综合后,先跑一遍hold检查。因为hold violation往往意味着时钟结构有问题,早点发现能省很多事。
输入到输出路径:片外时序的桥梁
这类路径没有寄存器,全是组合逻辑。约束时需要用set_input_delay和set_output_delay来模拟外部器件的时序行为。
举个例子,如果芯片输出到外部存储器的数据需要在时钟上升沿后5ns内稳定,那你的output delay就要设成5ns。说白了,就是把外部器件的时序要求「翻译」成工具能理解的语言。
输入到寄存器与寄存器到输出路径
这两类路径其实可以看作「半条」寄存器到寄存器路径。输入到寄存器,约束的是从片外到片内第一个寄存器的路径;寄存器到输出,约束的是从片内最后一个寄存器到片外的路径。
我记得有个项目,客户给的input delay设得特别紧,导致setup一直过不了。后来跟客户沟通才发现,他们用的是最差情况下的数据,实际应用中根本不会那么极端。所以,我建议大家在拿到约束文件后,先跟前端和系统工程师确认一下这些数值的合理性。
避坑指南:我曾经遇到过一种情况——input delay设得太松,导致芯片内部逻辑过于乐观。流片回来后,片外信号稍微有点抖动就出错了。所以,input/output delay的设定要「恰到好处」,既不能太紧让后端没法做,也不能太松让芯片不可靠。
建立时间与保持时间的权衡
这里有个有意思的点——setup和hold其实是矛盾的。你优化setup,往往会让hold变差;反过来也一样。为什么?因为setup要求数据路径短,hold要求数据路径长。你想想看,是不是这个理?
实际项目中,我们通常先保证setup,再修hold。因为setup跟频率相关,频率上不去芯片就没法用;而hold问题可以通过插入buffer来修复,代价相对小一些。
好了,这一章的内容就到这里。时序路径和约束是STA的基石,理解透了,后面的分析才能得心应手。下一章我们聊聊如何用脚本自动化生成这些约束,省去手动输入的麻烦。