时序违例Debug步骤清单:setup与hold分流排查,从slack符号到修复手法
本篇是「芯片设计」入门层的一篇排查清单。时序分析讲了 STA(静态时序分析)的整体框架,setup 与 hold 违例的根源辨析讲清了两类违例的物理成因。那一类文章回答「为什么」;本篇回答「怎么办」——打开一份时序报告,从第一行 slack 到最终修复,每一步看什么、怎么判、怎么修,按 setup / hold 分流成两条独立的排查链,照单执行即可。
本文要回答的问题
- 时序报告里哪个字段第一时间告诉你违例类型?slack 的正负和量级各说明什么?
- setup 违例的排查链有哪几站,每一站「看什么、怎么判、怎么修」?
- hold 违例为什么几乎只在数据路径太短一侧,修法和 setup 为何方向相反?
- 为什么说修违例前必须先核对约束(false path / multicycle),而不是先动电路?
先把整条分流排查流程压成一张封面卡,后文逐站展开:
读这张卡抓住一个反直觉的顺序:「查约束」排在「动电路」之前。新手拿到违例报告的第一反应是改 RTL 或加 buffer,但实测项目里约有两到三成「违例」其实是约束没写全——路径本来就不该在这个周期内被检查。下面按公共步骤、setup 链、hold 链三段展开。
一、公共步骤:先读报告,再谈修复
不管哪类违例,前三个动作完全相同。
第 1 步:看 slack 定类型。 报告末尾的 slack 字段是总开关:setup 检查段(常标 max 或 Path Type: max)里的负 slack 是 setup 违例;hold 检查段(min)里的负 slack 是 hold 违例。量级也有信息量:负几皮秒通常是边界余量不足,负几百皮秒甚至纳秒级则多半是结构性问题(逻辑太深或约束错了),修法完全不同。
第 2 步:看路径两端与中间段。 报告的 Startpoint / Endpoint 给出起点触发器与终点触发器,中间逐行列出经过的单元和每级延迟。先扫一眼两端是否在同一个时钟域——跨时钟域路径出现在 setup 报告里,十有八九是 CDC(跨时钟域)处理缺失,那属于另一类问题,见 亚稳态与同步器 的方向,不走本文清单。
第 3 步:确认重现的 PVT corner。 STA 在不同工艺角(PVT:Process/Voltage/Temperature)下各跑一遍。setup 最差通常出现在 ss 角 + 低压 + 高温(管子慢、延迟大);hold 最差出现在 ff 角 + 高压 + 低温(管子快、数据跑得太快)。报告头部或文件名会标注 corner,修之前先确认你修的是哪个角的违例——在 ss 角修 hold 是白费力气。
| 报告字段 | 看什么 | 怎么判 |
|---|---|---|
| slack | 符号与量级 | 负 = 违例;ps 级 = 余量问题,ns 级 = 结构/约束问题 |
| Path Type | max 还是 min | max = setup 链,min = hold 链 |
| Startpoint/Endpoint | 两端时钟域 | 跨域先走 CDC 检查,不在本清单 |
| 路径逐行延迟 | 哪几级吃掉大头 | 某一级延迟占总量 30% 以上就是优化靶点 |
| corner 标注 | ss/tt/ff + 电压温度 | setup 修 ss 低压高温,hold 修 ff 高压低温 |
二、setup 排查链:数据总是「来不及」
setup 违例的本质是数据在一个时钟周期内没走完组合逻辑。按出现频率从高到低,依次查四站。
第 1 站:数逻辑层级。 把报告里起点到终点经过的组合单元数一遍,除以周期预算,算平均每级能分到的延迟。经验值:一级标准单元(NAND2 量级)在典型工艺下约几十皮秒,如果 1ns 周期里塞了 25 级以上组合逻辑,就是「层级过多」型违例。修法是减级或打拍:把组合逻辑拆成两段、中间插一级寄存器(流水线),或用进位链、并行结构重写关键运算。这是性价比最高的一站,大违例(ns 级)几乎都归这一类。
第 2 站:看时钟偏斜(clock skew)。 报告会分别给出 launch clock 与 capture clock 的到达时间。如果终点时钟比起点时钟早到(负偏斜),等于周期被进一步压缩。偏斜超过周期 5% 就值得追时钟树——是否跨了不同的时钟缓冲层级、是否有门控时钟插在路径上。修法通常交给物理实现侧做时钟树平衡(CTS,见 时钟树综合),RTL 侧能做的是减少门控层级。
第 3 站:查约束是否缺声明。 两条最常见的「假性 setup 违例」:一是路径本来允许跨多个周期却没写 set_multicycle_path,工具按单周期严卡;二是异步路径(如配置寄存器、按键输入)根本没必要做同步时序检查,却没写 set_false_path。判据很直接:问设计负责人「这条路径真的要求单周期到达吗」,答不上来就先去看 SDC 约束写法 与 多周期与伪路径 的判定标准,把约束补齐再重跑,违例往往直接消失。
第 4 站:换单元、降负载。 前三站都排不掉、违例又是 ps 级的边界余量问题,就走微调手法:把路径上的单元换成同功能高速型号(LVT 低阈值管)、加大驱动(upsizing)、给高扇出线网插 buffer 降延迟。这类手法只搬得动几十皮秒,量级对不上时别指望它。
setup 链四个修复手法按适用场景汇总:
| 手法 | 适用违例量级 | 代价 | 副作用 |
|---|---|---|---|
| 流水线打拍 / 重写结构 | ns 级 | 改 RTL,加一级延迟 | 吞吐不变但延迟 +1 拍,需验证 |
| 补 multicycle / false path | 任意(假性) | 改 SDC | 声明错了会放掉真违例 |
| 时钟树平衡 | 百 ps 级 | 后端重跑 CTS | 面积/功耗微增 |
| 换 LVT / upsizing / buffer | 几十 ps 级 | 改网表 | 功耗上升,hold 可能恶化 |
注意最后一行:setup 的微调手法几乎都会让数据路径更快,也就是向 hold 违例的方向推。所以 setup 修完必须重跑 min 检查——这正是两条链的接口。
三、hold 排查链:数据总是「换得太快」
hold 违例的本质是新数据在旧数据还没被采稳时就冲到了终点触发器。它的排查链比 setup 短得多,因为根因只有两大类。
第 1 站:确认数据路径确实太短。 hold 报告里数据路径延迟常常只有零点几纳秒甚至更短。先确认这不是「假短」:终点触发器的 hold 时间要求(库参数,报告里单列一行)是否异常偏大——某些特殊单元(高保持时间的 IO 寄存器)会放大违例。正常情况下,数据路径延迟必须大于「capture 时钟到达时间 + hold 要求」。
第 2 站:看时钟偏斜方向。 与 setup 相反,hold 怕的是终点时钟晚到(正偏斜)——终点触发器晚开门,等于要求数据保持更久。如果偏斜是主要贡献,修法仍归 CTS 平衡;一个常见坑是终点挂在门控时钟后面、起点没有,门控延迟直接变成正偏斜。
第 3 站:修复手法——给数据路径「加阻力」。 方向与 setup 完全相反:
- 插 delay buffer:在数据路径中间插入专用延迟单元(不是普通反相器对,综合工具会优化掉),每次增加几十到几百皮秒,最常用;
- 换低驱动单元(downsizing):把路径上的单元换成小驱动型号,延迟自然变大;
- 换高阈值管(HVT):同功能但更慢,顺带省漏电。
hold 修复的黄金法则是「在 ff 角修,修完回 ss 角验证 setup 不受影响」——因为加阻力的手法在慢角下会进一步拖慢数据路径,两头都要照顾。实操中 ECO 工具(如 signoff 阶段的 fix_eco_timing)会自动按这个顺序批量插 buffer,手工修时自己复刻这个流程即可。
四、一张对照表收束两条链
| 维度 | setup 违例 | hold 违例 |
|---|---|---|
| 一句话本质 | 数据走太慢,一拍没到 | 数据换太快,旧值没采稳 |
| 最差 corner | ss / 低压 / 高温 | ff / 高压 / 低温 |
| 偏斜敏感方向 | 终点时钟早到(负偏斜) | 终点时钟晚到(正偏斜) |
| 首选修法 | 减逻辑层级、打拍 | 插 delay buffer |
| 微调修法 | LVT / upsizing | downsizing / HVT |
| 修完必做 | 回 ff 角查 hold 没被带坏 | 回 ss 角查 setup 没被带坏 |
这一篇在知识体系里的位置
- 原理层:setup 与 hold 违例的根源辨析(两类违例的物理成因,本篇的「为什么」);
- 框架层:时序分析(STA 整体框架与检查类型),OpenSTA setup 检查原理实测(用开源工具看 slack 怎么算出来);
- 约束层:SDC 约束写法、多周期与伪路径(清单第 3 站的展开);
- 时钟层:时钟树综合(偏斜修复的后端手段)。
总结
时序违例排查先分流:报告 max 段负 slack 走 setup 链(数层级 → 看偏斜 → 查约束 → 换单元),min 段负 slack 走 hold 链(确认路径过短 → 看反向偏斜 → 插 buffer / 降驱动);动电路之前先核对 false path 与 multicycle 约束,修完一侧必须回相反 corner 复测另一侧。