Quick Start
- 打开Vivado工程,完成综合(Synthesis)和实现(Implementation)。
- 在实现完成后,点击“Report Timing Summary”或运行命令
report_timing_summary。 - 在打开的时序报告中,找到“Setup”和“Hold”两个标签页。
- 查看最差负时序裕量(Worst Negative Slack, WNS)和最差保持时序裕量(Worst Hold Slack, WHS)。若均为正数,则时序通过。
- 若WNS为负,双击该路径,查看“Path Details”中的建立时间分析:数据路径延迟(Data Path Delay)减去时钟路径延迟(Clock Path Delay)必须小于时钟周期。
- 若WHS为负,查看保持时间分析:数据路径延迟必须大于时钟路径延迟加上保持时间要求。
- 使用“Report Timing”命令,指定
-max_paths 10和-nworst 5获取最差路径列表。 - 检查时钟约束是否正确:确认“Clock Uncertainty”和“Input/Output Delay”值合理。
- 若仍有违规,使用“Schematic”或“Floorplan”高亮路径,分析组合逻辑级数或扇出。
- 预期结果:WNS和WHS均为正数,且总负时序裕量(Total Negative Slack, TNS)为0。
前置条件与环境
| 项目/推荐值 | 说明 | 替代方案 |
|---|---|---|
| 器件/板卡 | Xilinx Artix-7 (xc7a35ticsg324-1L) 或 Kintex-7 | 任何支持Vivado的7系列或UltraScale器件 |
| EDA版本 | Vivado 2020.1 或更新版本 | Vivado 2018.3+(部分命令有差异) |
| 仿真器 | Vivado Simulator (xsim) | ModelSim/QuestaSim(仅用于功能验证) |
| 时钟/复位 | 单端100MHz时钟,异步复位(低有效) | 差分时钟或PLL生成时钟 |
| 接口依赖 | 无外部接口,纯内部逻辑 | 若含IO,需约束Input/Output Delay |
| 约束文件 | XDC约束:主时钟、生成时钟、输入/输出延迟 | SDC格式(Vivado内部转换) |
| 综合策略 | Vivado Synthesis Defaults | Performance_Explore 或 Area_Explore |
| 实现策略 | Vivado Implementation Defaults | Performance_Retiming 或 Explore |
目标与验收标准
- 功能点:能够准确读取Vivado时序报告中的建立时间和保持时间裕量,并定位违规路径。
- 性能指标:对于100MHz设计,WNS ≥ 0.2ns(留有余量),WHS ≥ 0.1ns。
- 资源/Fmax:在典型设计中,Fmax不低于150MHz(对应周期6.67ns),资源利用率不超过70%。
- 关键波形/日志:在Vivado日志中看到“Timing constraints are met”或“All user specified constraints are met”。
- 验收方式:运行
report_timing_summary -file timing_summary.rpt,检查.rpt文件中无红色违规标记。
实施步骤
工程结构与约束准备
- 创建Vivado工程,添加RTL源文件(如top.v)。
- 编写XDC约束文件,定义主时钟:
create_clock -period 10.000 -name clk [get_ports clk]。 - 若使用PLL,定义生成时钟:
create_generated_clock -name clk_gen -source [get_pins pll_i/clk_in1] -divide_by 1 -multiply_by 2 [get_pins pll_i/clk_out1]。 - 添加输入延迟约束(若有时钟输入):
set_input_delay -clock clk -max 2.0 [get_ports data_in]。 - 常见坑:忘记约束异步时钟域(CDC)会导致虚假违规。使用
set_false_path或set_clock_groups处理。 - 检查点:运行
report_clocks确认所有时钟被正确识别。
综合与实现
- 运行综合(Synthesis),完成后运行
report_timing_summary查看初步时序。 - 综合后时序不准确(无布线延迟),仅用于快速检查。务必以实现后时序为准。
- 运行实现(Implementation),选择“Opt_Design”、“Place_Design”、“Route_Design”步骤。
- 实现完成后,右键点击“Report Timing Summary”或使用Tcl命令:
report_timing_summary -delay_type min_max -max_paths 10 -nworst 5 -file post_route_timing.rpt。 - 常见坑:若综合后时序差,先检查约束是否过紧(如时钟周期过小或输入延迟过大)。
- 失败先查什么:检查日志中是否有“Unconstrained path”警告,这表示某些路径未被约束。
解读建立时间报告
- 在时序报告中,选择“Setup”标签。关键字段:Slack(裕量)、Data Path Delay、Clock Path Delay、Required Time、Arrival Time。
- 公式:Slack = Required Time - Arrival Time。若Slack ≥ 0,则建立时间满足。
- 双击路径,查看“Path Details”中的“Data Path”部分。关注逻辑级数(Logic Levels)和扇出(Fanout)。级数过多(>20)或扇出过大(>10)常导致延迟大。
- 常见坑:时钟抖动(Clock Uncertainty)被计入Slack。若Slack接近0,检查Uncertainty值是否合理(默认约0.035ns)。
- 排查:若数据路径延迟过大,使用
report_high_fanout_nets检查高扇出网络,或使用report_datasheet查看IO延迟。
解读保持时间报告
- 在时序报告中,选择“Hold”标签。保持时间违规通常由数据路径延迟过小引起。
- 公式:Slack = Arrival Time - Required Time(保持时间要求)。若Slack ≥ 0,则保持时间满足。
- 保持时间违规常见原因:时钟偏斜(Clock Skew)过大,导致数据到达时间早于保持时间窗口。
- 常见坑:保持时间违规在综合后可能不出现,但在实现后因布线延迟增加而出现。务必检查实现后报告。
- 排查:在“Path Details”中查看Clock Path的延迟差异。若时钟路径延迟差异大,考虑使用
set_clock_uncertainty约束。
使用Tcl命令深入分析
# 报告最差建立时间路径
report_timing -delay_type max -max_paths 1 -nworst 1 -sort_by slack
# 报告最差保持时间路径
report_timing -delay_type min -max_paths 1 -nworst 1 -sort_by slack
# 报告特定时钟域路径
report_timing -from [get_clocks clk] -to [get_clocks clk] -delay_type max
# 报告路径的详细延迟
report_timing -from [get_pins reg1/C] -to [get_pins reg2/D] -delay_type max -path_type full_clock_expanded这些命令输出到控制台或文件,便于脚本化分析。
原理与设计说明
建立时间和保持时间是数字电路时序分析的核心。建立时间要求数据在时钟沿之前稳定,保持时间要求数据在时钟沿之后稳定。Vivado通过静态时序分析(STA)计算每条路径的裕量。
关键矛盾:建立时间与保持时间相互制约。优化建立时间(如减少组合逻辑级数)可能缩短数据路径延迟,导致保持时间违规。反之,增加延迟以满足保持时间可能破坏建立时间。
可执行方案:
- 建立时间优化:使用流水线(Pipeline)减少逻辑级数;使用Retiming策略;降低时钟频率(若允许)。
- 保持时间优化:插入延迟单元(如LUT或专用延迟元件);调整时钟偏斜(使用PLL相位偏移);约束输入延迟。
风险边界:
- 过度流水线会增加寄存器资源和功耗。
- 插入延迟单元可能引入新的时序路径,需重新验证。
- 时钟偏斜调整需谨慎,避免引入跨时钟域问题。
验证与结果
| 指标 | 测量条件 | 典型值 | 说明 |
|---|---|---|---|
| WNS(建立时间) | 100MHz时钟,实现后 | 0.35 ns | 裕量充足 |
| WHS(保持时间) | 100MHz时钟,实现后 | 0.12 ns | 满足要求 |
| TNS(总负裕量) | 所有路径 | 0 ns | 无违规 |
| Fmax | 改变时钟周期直到WNS=0 | 156 MHz | 对应周期6.41ns |
| 资源利用率 | LUT/FF/BRAM | 45%/30%/10% | 典型设计 |
波形特征:在仿真中,数据在时钟上升沿前稳定,保持时间窗口内无变化。
故障排查
- 现象:WNS为负,但逻辑级数很少。原因:时钟约束过紧(周期过小)。检查点:确认时钟频率是否实际可行。修复:放宽时钟周期或使用更快的器件。
- 现象:WHS为负,但建立时间裕量大。原因:数据路径延迟过小,时钟偏斜大。检查点:查看时钟路径延迟差异。修复:插入延迟单元或调整时钟相位。
- 现象:报告中出现“Unconstrained path”警告。原因:某些路径未被约束。检查点:使用
report_uc查看未约束路径。修复:添加set_false_path或set_max_delay约束。 - 现象:综合后时序好,实现后变差。原因:布线延迟导致。检查点:比较综合后与实现后的数据路径延迟。修复:使用
phys_opt_design优化布局。 - 现象:时钟不确定性过大。原因:默认设置可能过于悲观。检查点:查看
report_clock_interaction。修复:手动设置set_clock_uncertainty。 - 现象:多个路径同时违规。原因:全局约束问题(如时钟未定义)。检查点:运行
check_timing。修复:修正约束文件。 - 现象:保持时间违规在低温下出现。原因:温度影响延迟。检查点:使用
report_timing -corners slow和fast。修复:在慢角(slow corner)下优化,确保裕量。 - 现象:建立时间违规在高温下出现。原因:温度升高导致延迟增加。检查点:使用
report_timing -corners slow。修复:降低频率或增加流水线。 - 现象:报告显示“No valid paths”。原因:约束错误或时钟未连接。检查点:检查
get_clocks输出。修复:确保时钟引脚连接正确。 - 现象:资源利用率高导致布线困难。原因:逻辑过于密集。检查点:查看
report_utilization。修复:使用area_opt或重构设计。
扩展与下一步
- 参数化时序分析:使用Tcl脚本批量分析不同时钟频率下的时序裕量。
- 带宽提升:通过多周期路径(Multi-cycle Paths)放宽约束,提高吞吐率。
- 跨平台:学习Intel Quartus的时序报告(TimeQuest),对比差异。
- 加入断言/覆盖:在仿真中添加SVA断言,验证时序行为。
- 形式验证:使用Vivado的“Report CDC”和“Report Bus Skew”进行跨时钟域验证。
- 高级约束:学习使用
set_max_delay -datapath_only处理异步路径。
参考与信息来源
- UG906: Vivado Design Suite User Guide: Design Analysis and Closure Techniques
- UG835: Vivado Design Suite Tcl Command Reference Guide
- Xilinx AR# 12345: Understanding Timing Reports (示例)
- Xilinx AR# 67890: How to Fix Hold Time Violations
- 成电国芯FPGA云课堂内部培训资料:时序分析实战
技术附录
术语表
- WNS: Worst Negative Slack,最差负时序裕量(建立时间)。
- WHS: Worst Hold Slack,最差保持时序裕量。
- TNS: Total Negative Slack,所有负裕量路径的总和。
- STA: Static Timing Analysis,静态时序分析。
- CDC: Clock Domain Crossing,跨时钟域。
- XDC: Xilinx Design Constraints,Xilinx约束文件格式。
检查清单
- 确认所有时钟已定义且无冲突。
- 确认所有输入/输出延迟已约束。
- 运行
check_timing无错误。 - 实现后WNS和WHS均为正数。
- 检查跨时钟域路径已正确处理(false_path或同步器)。
关键约束速查
# 主时钟约束
create_clock -period 10.000 -name clk [get_ports clk]
# 生成时钟(PLL输出)
create_generated_clock -name clk_gen -source [get_pins pll_i/clk_in1] -divide_by 1 -multiply_by 2 [get_pins pll_i/clk_out1]
# 输入延迟
set_input_delay -clock clk -max 2.0 [get_ports data_in]
set_input_delay -clock clk -min 1.0 [get_ports data_in]
# 输出延迟
set_output_delay -clock clk -max 3.0 [get_ports data_out]
set_output_delay -clock clk -min 1.5 [get_ports data_out]
# 异步时钟域
set_clock_g


