本节摘要:时序报告回答"电路跑多快、差在哪"。本节讲建立与保持两类违例的物理含义、WNS 与 WHS 两个关键数字、最差路径的逐级拆读方法,以及按优先级排列的时序优化动作清单。
打开时序报告,先看汇总区的两个数字。WNS(最差建立余量,Worst Negative Slack):每条寄存器到寄存器路径的"周期预算减去实际耗时",全设计取最小值。正数代表全部收敛,负数代表最差路径超时——负零点三纳秒的意思是"这条路径慢了零点三纳秒"。WHS(最差保持余量):检查数据不能"到得太快"以致覆盖了下一级的保持窗口。建立违例是"太慢",降频可救;保持违例是"太快",与频率无关,必须靠布线修——这是两类违例最本质的区别。
| 指标 | 含义 | 违例原因 | 补救方向 |
|---|---|---|---|
| WNS(建立) | 周期内还剩多少余量 | 组合逻辑太深、扇出太大、布线太长 | 减逻辑级数、降频 |
| WHS(保持) | 数据是否晚于保持窗口 | 路径太短、时钟偏斜异常 | 工具插延迟,一般自动修 |
初学项目里 WHS 违例罕见(布线器基本都能自动修复),绝大多数精力花在 WNS 上。看汇总时还要留意违例路径条数:一条违例与五百条违例是两种性质的问题——前者是个别路径超长,后者可能是时钟周期定得不切实际。
点开 WNS 对应的最差路径,报告列出路径上的每一站:源触发器、途经的每个 LUT、目的触发器,每站标注自身延迟与累计延迟。拆读示范(数值为示例):
Source: cnt_reg[3] (触发器输出延迟 0.42 ns) → LUT3 (加法器低位) 逻辑 0.31 ns + 布线 0.55 ns 累计 1.28 → CARRY4 (进位链) 逻辑 0.06 ns + 布线 0.10 ns 累计 1.44 → LUT5 (比较器 MAX 判断) 逻辑 0.31 ns + 布线 0.85 ns 累计 2.60 Destination: cnt_reg[2]/D 建立时间 0.35 ns,周期预算 20 ns → 余量 +16.4 ns(远未到极限)
拆读看三件事:累计时间都花在哪一站(布线占比高说明布局差或扇出远)、级数有多深(LUT 数量多说明组合逻辑写复杂了)、余量差多少(差零点几纳秒与差五纳秒的对策完全不同)。多数初学项目的 WNS 都相当宽裕——50 兆时钟、几十级逻辑的规模远未逼近器件极限;真正紧张的是高速接口与深流水线场景。

案例一:比较器挡路。 计数器里 if cnt = MAX then ... 的比较器串在自增路径上,LUT 级数偏深。改法是把比较挪出关键路径:单独一个并发语句算 cnt = MAX,寄存一拍后再参与判断,比较延迟从数据路径移到控制路径。功能等效(判断晚一拍知晓,计数行为不变),WNS 明显改善。案例二:高扇出使能。 一个使能信号驱动两百个触发器,布线延迟劣化。改法是让工具复制寄存器(综合属性 max_fanout)或手工按区域拆成几个使能寄存器,扇出分摊。两个案例的共同套路:先从报告找到"最疼的那一站",再对着那一站动刀,盲目改代码撞运气是时序优化的大忌。
⚠️ 常见坑:把 WNS 为负当成代码错误,上来就大改逻辑。实际上先查约束误伤——同步器没标伪路径、多周期没声明,这两类"假违例"占新手项目违例的相当比例。约束改一行、日志重跑,比重构代码便宜百倍。
💡 关键直觉:时序收敛是"预算管理"。周期是收入,逻辑、布线、建立时间是支出,WNS 是结余。优化就是砍支出(减级数、降扇出)或增收入(降频放宽周期);先查有没有记错账(约束例外),再谈砍支出。
report_timing_summary 输出三个核心指标:
Setup 违例(建立时间不满足):
max_fanout 约束让工具复制高扇出信号place_design 后做 phys_opt_designHold 违例(保持时间不满足):
Vivado 的 report_cdc 工具能识别跨时钟域路径,并检查是否有合适的同步器。Quartus 的 Timing Analyzer 集成了类似功能。
| 违例类型 | 常见根因 | 修法 |
|---|---|---|
| Setup 违例 | 组合逻辑链太长、扇出过高、跨时钟域无同步 | 插寄存器、复制高扇出信号、加入同步器 |
| Hold 违例 | 路径延迟太短、跨时钟域信号无同步 | 插 buffer、做物理优化、修改时钟 skew |
| Recovery/Removal 违例 | 异步复位信号撤销时未同步 | 异步复位同步释放(推荐做法) |
| Input Delay 违例 | 外部信号到达时间超出约束范围 | 调整 set_input_delay、加入输入寄存器 |
| Output Delay 违例 | 输出寄存器建立时间不够 | 加入输出寄存器、调整 set_output_delay |
Vivado 的 report_timing 能列出每条失败路径的具体位置和延迟。点击路径能跳到 RTL 源码。Quartus 的 Timing Analyzer 也有类似功能。