本文以 AMD/Xilinx Vivado 和当前使用的
XCKU5P-FFVB676-2-I为主要环境,从“什么是时序”开始,逐步介绍时钟、I/O、CDC 和时序例外约束,解释 Vivado 时序报告中的 WNS、TNS、WHS、THS 等指标,并给出不同类型时序违例的定位与修改方法。文中的数值示例用于说明计算方法。RGMII、DDR4、JESD204 等接口的最终参数,必须以实际 PHY/存储器/转换器数据手册、原理图、PCB 走线时延和实现后的时序报告为准。
前言:为什么功能仿真正确,上板仍会偶发错误?
在 RTL 仿真中,寄存器似乎会在时钟上升沿“瞬间”采样数据,组合逻辑也经常被当成零延时逻辑。但真实 FPGA 内部存在:
- 寄存器 Clock-to-Q 延时;
- LUT、MUX、进位链、DSP、BRAM 等逻辑延时;
- 片内互连和跨 Clock Region/SLR 的布线延时;
- 时钟树插入延时和时钟偏斜;
- 外部器件的 Tco、Setup、Hold;
- PCB 走线时延;
- 晶振抖动、MMCM/PLL 相位误差;
- 温度、电压和工艺角变化。
如果数据在接收寄存器需要采样时还没有稳定,就会发生建立时间违例;如果采样边沿之后数据变化得太早,就会发生保持时间违例。
这类错误的典型表现不是“每次都错”,而是:
- 同一份 bitstream 有时正常、有时异常;
- 降低时钟频率后 setup 问题改善;
- 升温、降压或更换板卡后故障概率变化;
- 加入 ILA 后布局改变,原来的问题消失或转移;
- DDR 校准偶发失败、RGMII 偶发丢包、AXI 偶发卡死;
- 仿真完全正确,但硬件长时间运行后出现单比特错误。
因此,时序约束不是“让 Vivado 不报红”的附加文件,而是设计规格的一部分。它告诉工具:
- 时钟何时到来;
- 数据必须在何时到达;
- 哪些时钟彼此同步;
- 哪些路径跨异步时钟域;
- 哪些路径确实不需要按默认单周期分析;
- 综合、布局、布线应该优先优化哪些路径。
1. 什么是 FPGA 时序?
1.1 一条寄存器到寄存器的路径
最基本的同步路径由启动寄存器、组合逻辑和捕获寄存器组成:
数据从 FF1 被发射,到 FF2 被采样,需要经历:
启动时钟边沿
+ 启动端时钟插入延时
+ FF1 的 Clock-to-Q
+ 组合逻辑延时
+ 数据布线延时
= 数据到达时间 Data Arrival Time
FF2 对数据的要求由捕获时钟边沿、捕获端时钟延时、建立/保持时间和时钟不确定度共同决定。
1.2 Setup:数据不能来得太晚
建立时间检查关心最大延时。在下一个有效采样边沿到来之前,数据必须提前一段 Tsetup 稳定。
简化后的建立时间条件为:
T c q , m a x + T d a t a , m a x + T s e t u p + T u n c e r t a i n t y ≤ T p e r i o d + T s k e w T_{cq,max}+T_{data,max}+T_{setup}+T_{uncertainty} \le T_{period}+T_{skew} Tcq,max+Tdata,max+Tsetup+Tuncertainty≤Tperiod+Tskew
Vivado 中:
S e t u p S l a c k = D a t a R e q u i r e d T i m e − D a t a A r r i v a l T i m e Setup\ Slack = Data\ Required\ Time - Data\ Arrival\ Time Setup Slack=Data Required Time−Data Arrival Time
- Slack ≥ 0:该路径满足建立时间;
- Slack < 0:数据到得太晚,发生 setup violation。
1.3 Hold:数据不能变得太早
保持时间检查关心最小延时。在捕获边沿之后,旧数据还必须保持一小段时间。
简化后的保持时间条件为:
T c q , m i n + T d a t a , m i n ≥ T h o l d + T s k e w + T u n c e r t a i n t y T_{cq,min}+T_{data,min} \ge T_{hold}+T_{skew}+T_{uncertainty} Tcq,min+Tdata,min≥Thold+Tskew+Tuncertainty
Vivado 中可以理解为:
H o l d S l a c k = D a t a A r r i v a l T i m e − D a t a R e q u i r e d T i m e Hold\ Slack = Data\ Arrival\ Time - Data\ Required\ Time Hold Slack=Data Arrival Time−Data Required Time
- Slack ≥ 0:数据没有过早变化;
- Slack < 0:数据到得太快,发生 hold violation。
1.4 Setup 和 Hold 的直观区别
| 项目 | Setup | Hold |
|---|---|---|
| 检查目标 | 最大数据路径延时 | 最小数据路径延时 |
| 数据问题 | 到得太晚 | 变化太早 |
| 降低频率 | 通常有效 | 基本无效 |
| 常见修复 | 加流水、降低逻辑级数、改善布局布线 | 修正约束/时钟树,由路由增加最小延时 |
| Vivado 指标 | WNS、TNS | WHS、THS |
重点:降低时钟频率不能解决真正的 Hold 违例。 因为 Hold 检查发生在相邻或同一个采样边沿附近,而不是等待下一个周期。
2. 静态时序分析 STA 在做什么?
Vivado 使用静态时序分析(Static Timing Analysis,STA),不需要枚举所有输入数据,也不依赖测试向量。它会:
- 根据网表建立时序图;
- 根据器件、速度等级和 PVT 模型取得单元/布线延时;
- 根据 XDC 建立时钟波形和时钟关系;
- 枚举寄存器、I/O、RAM、DSP 等时序端点之间的路径;
- 分别执行最大延时、最小延时、恢复/移除和脉宽检查;
- 报告最差裕量与违例路径。
STA 的优势是覆盖面大,但前提是约束正确。一个没有约束的路径不会自动变安全;一个被错误设置为 false path 的路径也不会自动变成异步安全电路。
3. Vivado 中时序约束的基本对象
XDC 本质上是 Tcl 命令。约束前必须先正确取得对象。
| Tcl 查询 | 对象 | 常见用途 |
|---|---|---|
get_ports | 顶层端口 | 输入输出延时、主时钟、管脚属性 |
get_pins | 单元内部引脚 | 生成时钟源、精确起止点 |
get_cells | 网表单元 | 寄存器集合、同步器、层级范围 |
get_nets | 网表网络 | 物理/路由属性,不宜滥用于时序端点 |
get_clocks | 时序时钟对象 | 时钟组、uncertainty、I/O delay |
3.1 先在 Tcl Console 验证查询
get_ports sys_clk_p
get_cells -hier -filter {NAME =~ *axis_fifo*}
get_pins -hier -filter {NAME =~ *u_mmcm*/CLKOUT0}
get_clocks *
若对象查询结果为空,约束可能没有真正作用。建议对关键查询使用:
set rst_sync_regs [get_cells -hier -filter {ASYNC_REG == TRUE}]
puts "reset synchronizer count = [llength $rst_sync_regs]"
不要在层级名尚未确认时大量使用宽泛通配符。一条匹配范围过大的 false path 可能掩盖整个设计的问题。
4. 时序约束的正确顺序
推荐按以下顺序建立约束:
工程中可以按功能拆分 XDC:
constraints/
├── 00_primary_clocks.xdc
├── 10_generated_clocks.xdc
├── 20_clock_relationships.xdc
├── 30_io_delays.xdc
├── 40_cdc_exceptions.xdc
├── 50_interface_exceptions.xdc
└── 90_io_and_physical.xdc
IP 自带 XDC 应由 IP 管理。不要把 MIG、Clocking Wizard、JESD 或 GT IP 生成的约束全部复制到顶层后再修改,否则容易出现重复时钟和优先级冲突。
5. 主时钟约束:create_clock
5.1 单端 100 MHz 时钟
create_clock -name sys_clk_100m \
-period 10.000 \
-waveform {0.000 5.000} \
[get_ports sys_clk]
period单位为 ns;waveform中两个值分别为第一个上升沿和下降沿;- 50% 占空比时可以省略
-waveform。
5.2 差分时钟
当前板卡 Bank 65 的 V24/W24 为 100 MHz 差分参考时钟。通常只在 P 端建立时钟:
create_clock -name ref_clk_100m \
-period 10.000 \
[get_ports ref_clk_100_p]
IBUFDS 和后续时钟缓冲的传播会由时序引擎处理,不需要给 P、N 两端各创建一个时钟。
5.3 时钟抖动
外部时钟输入抖动可用 set_input_jitter 描述,全局系统抖动可用 set_system_jitter。不要为了“留裕量”随意增加很大的 uncertainty;Vivado 已包含器件模型和部分时钟结构的不确定度,重复加入会造成无意义的过约束。
set_input_jitter [get_clocks ref_clk_100m] 0.050
数值必须来自晶振/时钟芯片在相关积分带宽下的规格或工程预算,不能凭感觉填写。
6. 生成时钟:create_generated_clock
生成时钟来自另一个主时钟,例如:
- MMCM/PLL 输出;
- BUFGCE_DIV 分频输出;
- 寄存器翻转产生的分频时钟;
- ODDRE1 产生的转发时钟;
- GT 的 TXOUTCLK/RXOUTCLK。
6.1 MMCM/PLL 自动派生时钟
Vivado 通常能够从 MMCM、PLL 和 Clocking Wizard 自动推导输出时钟。首先运行:
report_clocks
确认频率、波形和主时钟来源正确。能自动派生时不要再人为创建同名时钟,否则可能产生 multiple clock 或覆盖关系错误。
6.2 自定义二分频时钟
如果用寄存器输出作为真正的时钟,应明确描述:
create_generated_clock -name clk_div2 \
-source [get_pins u_clk_div/clk_reg/C] \
-divide_by 2 \
[get_pins u_clk_div/clk_reg/Q]
不过,优先使用 MMCM/PLL、BUFGCE_DIV 或时钟使能,不推荐用普通寄存器/LUT 随意造时钟。
6.3 转发时钟
例如 RGMII TXC 通过 ODDRE1 输出:
create_generated_clock -name rgmii_txc \
-source [get_pins u_rgmii_tx/u_oddre1_txc/C] \
-divide_by 1 \
[get_ports rgmii_txc]
如果 ODDRE1 的输入时钟来自 90° 相移 MMCM 输出,生成时钟会继承该相位关系。实际层级和引脚名必须在综合后用 get_pins 验证。
7. 时钟关系:同步、异步与互斥
7.1 同源时钟通常是同步时钟
同一个 MMCM 产生的 100 MHz、200 MHz,或者主时钟经合法整数分频得到的时钟,通常存在固定相位关系,Vivado 应对它们之间的路径做时序分析。
不要因为频率不同,就直接设置为异步。
7.2 异步时钟组
两个独立晶振产生的时钟通常没有固定相位关系:
set_clock_groups -asynchronous \
-group [get_clocks sys_clk_100m] \
-group [get_clocks rgmii_rxc]
该命令会切断两组时钟之间双向的常规 setup/hold 分析。它只能在 CDC 结构已经正确实现之后使用。
7.3 物理互斥与逻辑互斥
通过 BUFGCTRL/MUX 选择、永远不会同时有效的时钟,可能需要 -physically_exclusive 或 -logically_exclusive。这两者语义不同,不能用 -asynchronous 一概代替。
7.4 查看 Vivado 认为的时钟关系
report_clock_interaction
颜色只是提示,必须进一步确认:
- 时钟是否真正相关;
- 是否存在 CDC;
- 是否已经有安全同步器/异步 FIFO;
- 某条 false path 或 clock group 是否覆盖范围过大。
8. 输入延时约束:set_input_delay
输入延时约束描述的是:相对于 FPGA 看到的参考时钟,外部数据最早和最晚何时到达 FPGA 管脚。
它不是 FPGA 内部 IBUF 的延时,也不是“希望 Vivado 给数据加多少延时”。
8.1 输入最大/最小延时的组成
以源同步输入为例:
I n p u t D e l a y m a x = T c o m a x + T p c b , d a t a , m a x − T p c b , c l k , m i n InputDelay_{max}=Tco_{max}+T_{pcb,data,max}-T_{pcb,clk,min} InputDelaymax=Tcomax+Tpcb,data,max−Tpcb,clk,min
I n p u t D e l a y m i n = T c o m i n + T p c b , d a t a , m i n − T p c b , c l k , m a x InputDelay_{min}=Tco_{min}+T_{pcb,data,min}-T_{pcb,clk,max} InputDelaymin=Tcomin+Tpcb,data,min−Tpcb,clk,max
其中:
Tco_max/min:外部器件从时钟到输出数据的最大/最小延时;Tpcb,data:数据走线延时;Tpcb,clk:时钟走线延时。
8.2 SDR 输入模板
set_input_delay -clock [get_clocks ext_rx_clk] \
-max <INPUT_MAX_NS> \
[get_ports {rx_data[*]}]
set_input_delay -clock [get_clocks ext_rx_clk] \
-min <INPUT_MIN_NS> \
[get_ports {rx_data[*]}]
8.3 DDR 输入模板
DDR 数据在上升沿和下降沿都有效,两个边沿都需要约束:
set_input_delay -clock [get_clocks rgmii_rxc] \
-max <RISE_MAX_NS> \
[get_ports {rgmii_rxd[*] rgmii_rx_ctl}]
set_input_delay -clock [get_clocks rgmii_rxc] \
-min <RISE_MIN_NS> \
[get_ports {rgmii_rxd[*] rgmii_rx_ctl}]
set_input_delay -clock [get_clocks rgmii_rxc] \
-clock_fall -add_delay \
-max <FALL_MAX_NS> \
[get_ports {rgmii_rxd[*] rgmii_rx_ctl}]
set_input_delay -clock [get_clocks rgmii_rxc] \
-clock_fall -add_delay \
-min <FALL_MIN_NS> \
[get_ports {rgmii_rxd[*] rgmii_rx_ctl}]
-add_delay 很重要,否则后写入的下降沿约束可能覆盖先前约束。
8.4 为什么 min 和 max 必须同时写?
-max主要用于 setup 分析;-min主要用于 hold 分析;- 只写 max 会导致 hold 侧不完整;
- 只写 min 会导致 setup 侧不完整。
check_timing 会报告 partial_input_delay,但不能依赖工具替你猜另一侧的数值。
9. 输出延时约束:set_output_delay
输出延时描述的是:外部器件相对于参考时钟,需要 FPGA 输出数据满足怎样的 setup/hold 窗口。
9.1 输出最大/最小延时的组成
常见计算形式为:
O u t p u t D e l a y m a x = T s e t u p e x t + T p c b , d a t a , m a x − T p c b , c l k , m i n OutputDelay_{max}=Tsetup_{ext}+T_{pcb,data,max}-T_{pcb,clk,min} OutputDelaymax=Tsetupext+Tpcb,data,max−Tpcb,clk,min
O u t p u t D e l a y m i n = − T h o l d e x t + T p c b , d a t a , m i n − T p c b , c l k , m a x OutputDelay_{min}=-Thold_{ext}+T_{pcb,data,min}-T_{pcb,clk,max} OutputDelaymin=−Tholdext+Tpcb,data,min−Tpcb,clk,max
注意:由于公式中是 -Thold_ext,输出 -min 很可能是负数。这是正常的时序语义,不应为了“看起来好看”强行改成 0。
9.2 DDR 输出模板
set_output_delay -clock [get_clocks rgmii_txc] \
-max <RISE_MAX_NS> \
[get_ports {rgmii_txd[*] rgmii_tx_ctl}]
set_output_delay -clock [get_clocks rgmii_txc] \
-min <RISE_MIN_NS> \
[get_ports {rgmii_txd[*] rgmii_tx_ctl}]
set_output_delay -clock [get_clocks rgmii_txc] \
-clock_fall -add_delay \
-max <FALL_MAX_NS> \
[get_ports {rgmii_txd[*] rgmii_tx_ctl}]
set_output_delay -clock [get_clocks rgmii_txc] \
-clock_fall -add_delay \
-min <FALL_MIN_NS> \
[get_ports {rgmii_txd[*] rgmii_tx_ctl}]
9.3 当前 RGMII 工程的注意事项
当前 RGMII 位于 Bank 67,VCCO=1.8 V,使用 LVCMOS18。1 Gb/s 模式下时钟为 125 MHz,周期 8 ns,数据在两个边沿传输。
此前使用的约 ±0.80 ns 只能作为早期估算,不能当作所有 PHY 和 PCB 的通用参数。最终约束需要先确认:
- PHY 配置为 RGMII、RGMII-ID、TXID 还是 RXID;
- TX/RX 内部 2 ns 延时由 PHY 还是 FPGA 提供;
- PHY 数据手册给出的 Tco、setup、hold;
- 时钟与数据 PCB 走线时延;
- FPGA MMCM 相移和 ODDRE1/IDDRE1 结构。
若 FPGA 使用 90° TX 时钟,同时又开启 PHY TX internal delay,就可能出现重复相移;若两侧都不加,又可能没有足够的采样裕量。
10. 时序例外:必须最后添加
默认情况下,Vivado 会按时钟边沿关系分析路径。只有当默认关系与真实功能不一致时,才应添加例外。
10.1 False Path
set_false_path \
-from [get_cells <SOURCE_REGS>] \
-to [get_cells <DEST_REGS>]
False path 表示该路径不参与常规时序分析。适用场景包括已经正确实现的异步同步器第一级路径、静态配置路径等。
危险用法:
# 不推荐:可能切断过多有效路径
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]
若两个时钟确实异步且双向均需切断,使用 set_clock_groups -asynchronous 更清晰;但无论使用哪种命令,都必须先实现正确 CDC。
10.2 Multicycle Path
如果功能上明确允许数据经过 N 个周期到达,可以使用多周期路径:
set_multicycle_path 2 -setup \
-from [get_cells <SOURCE_REGS>] \
-to [get_cells <DEST_REGS>]
set_multicycle_path 1 -hold \
-from [get_cells <SOURCE_REGS>] \
-to [get_cells <DEST_REGS>]
常见规则是:setup 放宽到 N 周期时,hold 需要配套设置为 N-1,使保持检查回到正确边沿。若只写 setup,不写 hold,可能制造非常大的 Hold 要求和布线绕路。
多周期路径必须有 RTL 功能保证,例如接收寄存器只在每两个周期一次的 clock enable 上采样。不能因为一条路径难收敛,就把它改成多周期。
10.3 set_max_delay / set_min_delay
它们适合需要直接限制数据路径延时的特殊场景,如部分 CDC 结构、总线偏斜控制或协议 IP 指定路径。
set_max_delay <MAX_NS> -datapath_only \
-from [get_cells <SRC>] \
-to [get_cells <DST>]
-datapath_only 会改变时钟偏斜参与分析的方式,不能作为普通 setup 违例的通用修复。
10.4 检查例外是否真的覆盖预期路径
report_exceptions
report_exceptions -coverage
关注:
- 例外是否匹配 0 个对象;
- 是否意外覆盖大量路径;
- 多条例外是否发生优先级覆盖;
- IP 自带例外与顶层例外是否冲突。
11. CDC:约束不能替代跨时钟电路
11.1 单比特电平:两级同步器
(* ASYNC_REG = "TRUE" *) reg sync_ff1;
(* ASYNC_REG = "TRUE" *) reg sync_ff2;
always @(posedge dst_clk) begin
sync_ff1 <= async_level;
sync_ff2 <= sync_ff1;
end
两级同步器降低亚稳态传播概率,但不能保证窄脉冲一定被捕获。
11.2 脉冲:握手或脉冲展宽
源时钟域中的单周期脉冲跨到更慢时钟域,可能完全落在两个采样边沿之间。应使用:
- toggle synchronizer;
- request/acknowledge 握手;
- 脉冲展宽;
XPM_CDC_PULSE。
11.3 多比特数据:异步 FIFO
不能把多位数据的每一位分别打两拍,因为各位可能在不同周期稳定。AXI-Stream、UDP 数据流、ADC 数据跨域应使用:
- AXIS Clock Converter;
- XPM asynchronous FIFO;
- Gray pointer 异步 FIFO;
- 协议级握手并保持数据稳定。
11.4 复位:异步拉低,同步释放
(* ASYNC_REG = "TRUE" *) reg [1:0] rst_sync;
always @(posedge clk or negedge arst_n) begin
if (!arst_n)
rst_sync <= 2'b00;
else
rst_sync <= {rst_sync[0], 1'b1};
end
wire srst_n = rst_sync[1];
异步复位可以立即生效,但释放应在每个时钟域分别同步,以避免 recovery/removal 违例和不同寄存器在不同周期退出复位。
11.5 CDC 报告
report_cdc -details
report_clock_interaction
不要在看到 CDC 路径报错后立刻 false path。先确认拓扑属于安全同步器、握手或异步 FIFO,再添加精确例外。
12. Vivado 如何生成时序报告?
12.1 GUI 操作
综合后可以:
- 在 Flow Navigator 中选择 Open Synthesized Design;
- 选择 Reports → Timing → Report Timing Summary;
- 选择 Setup、Hold、Pulse Width、路径数量和是否报告未约束路径。
实现后建议:
- 运行 Generate Bitstream 前的完整 Implementation;
- 选择 Open Implemented Design;
- 打开 Timing Summary;
- 展开 Intra-Clock Paths、Inter-Clock Paths、Other Path Groups;
- 双击最差路径,在 Device 窗口中交叉定位布局和布线。
综合后的报告使用估算布线延时,适合早期发现逻辑深度、缺失时钟和明显错误;最终签核必须以 post-route implemented design 为准。
12.2 Tcl 生成报告
open_run impl_1
check_timing -verbose
report_timing_summary \
-delay_type min_max \
-max_paths 20 \
-report_unconstrained \
-file timing_summary_post_route.rpt
report_timing \
-delay_type max \
-max_paths 50 \
-sort_by group \
-file setup_worst_50.rpt
report_timing \
-delay_type min \
-max_paths 50 \
-sort_by group \
-file hold_worst_50.rpt
report_clock_interaction -file clock_interaction.rpt
report_cdc -details -file cdc_details.rpt
report_methodology -file methodology.rpt
report_drc -file drc.rpt
建议将这些命令加入实现后的自动脚本,而不是每次只在 GUI 中临时点击。
12.3 针对某条路径分析
report_timing \
-from [get_pins <START_REG>/C] \
-to [get_pins <END_REG>/D] \
-delay_type max \
-path_type full_clock_expanded \
-max_paths 10
full_clock_expanded 有助于观察启动/捕获时钟树、clock skew 和 common path pessimism removal。
13. 如何阅读 Timing Summary?
13.1 四个最常看的指标
| 指标 | 全称 | 含义 |
|---|---|---|
| WNS | Worst Negative Slack | 所有 setup/max delay 路径中的最差裕量 |
| TNS | Total Negative Slack | 所有 setup 负裕量的总和 |
| WHS | Worst Hold Slack | 所有 hold/min delay 路径中的最差裕量 |
| THS | Total Hold Slack | 所有 hold 负裕量的总和 |
| WPWS | Worst Pulse Width Slack | 最差脉宽/最小周期检查裕量 |
| TPWS | Total Pulse Width Negative Slack | 脉宽负裕量总和 |
例如:
WNS = -0.420 ns
TNS = -38.700 ns
Failing Endpoints = 126
含义是最差 setup 路径晚了 0.420 ns,共有一批失败路径,所有负裕量累计为 -38.700 ns。TNS 不能用于估算系统“平均还能跑多快”,它主要反映违例规模。
13.2 Timing Summary 的主要区域
| 区域 | 作用 |
|---|---|
| Check Timing | 检查缺失时钟、未约束端点、部分 I/O delay、组合环等 |
| Design Timing Summary | 汇总 WNS/TNS/WHS/THS/WPWS |
| Clock Summary | 显示时钟周期、波形、来源 |
| Intra-Clock Paths | 同一时钟域内部路径 |
| Inter-Clock Paths | 不同时钟之间的路径 |
| Other Path Groups | 输入、输出、异步控制、特殊检查等 |
13.3 一条详细路径应看什么?
建议按下面顺序阅读:
- Path Type:Setup 还是 Hold;
- Source/Destination Clock:时钟关系是否符合设计;
- Requirement:要求是否合理,是否小得异常;
- Timing Exception:是否有 multicycle/max_delay 等;
- Data Path Delay:数据路径总延时;
- Logic Delay / Net Delay:逻辑和布线谁占主导;
- Logic Levels:经过多少级 LUT/MUX/CARRY/DSP;
- Clock Path Skew:启动/捕获时钟树差异;
- Clock Uncertainty:抖动与相位误差预算;
- Physical Location:是否跨 Clock Region、远距离 RAM/DSP/GT。
经验判断:
- Logic Delay 占比高:优先改 RTL、流水线或资源映射;
- Net Delay 占比高:检查扇出、拥塞、物理距离和 hold 修复绕线;
- Requirement 异常小:先检查生成时钟、相位和 clock relationship;
- Clock Skew 异常大:检查时钟是否走普通布线、是否跨不合理拓扑;
- 失败路径都集中在同一模块:优先做局部结构优化;
- 失败路径分散且接近 0:可能适合物理优化/实现策略探索。
14. Check Timing:比 WNS 更早检查
运行:
check_timing -verbose
重点项目包括:
| 检查项 | 含义 | 常见处理 |
|---|---|---|
no_clock | 寄存器时钟脚没有被时序时钟覆盖 | 补主时钟/生成时钟或修复时钟传播 |
constant_clock | 时钟脚被常量驱动 | 检查优化、复位或错误连接 |
unconstrained_internal_endpoints | 内部端点没有时序要求 | 找到缺失时钟或错误例外 |
no_input_delay | 普通输入没有输入延时 | 根据外设和 PCB 补 min/max |
no_output_delay | 普通输出没有输出延时 | 根据接收器件补 min/max |
partial_input_delay | 只有 min 或 max | 补齐另一侧 |
partial_output_delay | 只有 min 或 max | 补齐另一侧 |
multiple_clock | 一个时钟脚被多个时钟覆盖 | 检查时钟 MUX、重复 create_clock |
loops | 存在组合环 | 修改 RTL,不能依赖 STA 自动断环 |
一个 WNS=+1 ns、但存在大量 unconstrained endpoints 的工程,不能称为时序通过。
15. 时序违例有哪些类型?
后续逐类说明定位和修改方法。
16. Setup 违例:数据到得太晚
16.1 先判断是不是真实 Setup 问题
检查:
- 时钟周期是否写错,例如把 100 MHz 写成 1 ns;
- MMCM 生成时钟是否重复定义;
- 两个异步时钟是否被错误认为同步;
- 多周期路径是否缺少合理功能依据;
- I/O delay 的参考时钟和边沿是否选错;
- 输入/输出 max/min 是否正负号错误。
如果 Requirement 小于 2 ns,而设计本来只有 100/125 MHz,优先怀疑时钟关系或相位约束,不要立刻加流水线。
16.2 逻辑延时占主导
常见原因:
- 一拍完成过多加法、比较、优先级判断;
- 很长的
if/else if或 case 多路选择; - 大位宽乘加没有使用 DSP 内部寄存器;
- BRAM 输出后紧接大量组合逻辑;
- AXI 地址计算、长度判断和握手控制全部在同一拍完成。
修改方法:
- 增加流水级;
- 平衡组合逻辑树;
- 使用 DSP/BRAM 的输入、流水和输出寄存器;
- 将大比较器拆分;
- 降低单周期扇入;
- 允许综合 retiming(前提是复位/使能结构允许)。
例如原本一拍完成:
always @(posedge clk) begin
result <= (a * b) + (c * d) + offset;
end
可改为:
reg [2*W-1:0] mult_ab;
reg [2*W-1:0] mult_cd;
reg [2*W:0] sum_mult;
always @(posedge clk) begin
mult_ab <= a * b;
mult_cd <= c * d;
sum_mult <= mult_ab + mult_cd;
result <= sum_mult + offset;
end
注意同步修改 valid、地址、帧尾等旁带信号的延时,避免数据正确而控制错拍。
16.3 Net Delay 占主导
常见原因:
- 高扇出 reset、enable、状态译码;
- 模块跨较远 Clock Region;
- BRAM、DSP、GT、IOB 与逻辑距离过远;
- 资源利用率高、局部拥塞;
- 为修复 Hold 而出现很长路由绕线。
修改方法:
- 对高扇出控制信号进行寄存器复制/分层;
- 避免用一个全局同步复位驱动所有 datapath 寄存器;
- 在接口边界加入 Register Slice;
- 减少不必要的层级保持,让综合器跨层级优化;
- 使用
report_design_analysis、拥塞图和 Device 视图定位; - 在结构稳定后才考虑 Pblock,避免过早把逻辑框死;
- 运行布局后/布线后的
phys_opt_design。
16.4 AXI/AXIS 常见 Setup 修复
AXI/AXIS 的组合反压链很容易成为长路径:
下游 TREADY -> 多级模块组合逻辑 -> 上游 TREADY
可以加入:
- AXI Register Slice;
- AXIS Register Slice;
- skid buffer;
- FIFO;
- SmartConnect 的寄存级。
不能只给路径加 multicycle,因为 AXI 握手语义默认要求每拍都正确。
17. Hold 违例:数据变化得太早
17.1 Hold 违例为什么更危险?
Setup 小幅失败有时可以通过降低频率缓解;Hold 失败即使降低频率也仍可能失败。AMD 的时序分析建议中也强调,路由器通常优先修复 Hold。
17.2 常见根因
- 仅设置了 multicycle setup,没有设置配套 hold;
- 启动与捕获时钟树偏斜过大;
- 相关时钟被错误声明为异步或反之;
- 输入/输出
-min数值错误; - 外部时钟/数据走线差异未计入;
- 某条极短路径跨越了不同的时钟缓冲结构;
- route 为修复其他路径产生了冲突。
17.3 推荐修复顺序
- 检查路径 Requirement、时钟和例外;
- 检查 multicycle setup/hold 是否成对;
- 检查时钟树是否使用专用资源;
- 在 placement 阶段观察是否已经出现异常大的 Hold 负裕量;
- 让 router 和 post-route physical optimization 修复合理的小 Hold 违例;
- 对 I/O 路径重新计算板级 min delay;
- 只有在架构确实要求时,才使用精确的
set_min_delay或专用延时资源。
不要在 RTL 中随意串接 LUT 当“延时器”。LUT 和普通布线延时会随布局、PVT 和重新实现变化,不能提供可靠的固定模拟延时。
18. Recovery / Removal 违例:异步控制释放问题
Recovery/Removal 类似异步 reset/set 相对于时钟的 setup/hold 检查。
典型错误:一个外部异步复位直接扇出到整个设计,并在任意时刻释放。部分寄存器可能在当前时钟沿退出复位,另一些在下一时钟沿退出,导致状态机进入非法状态。
修改方法:
- 每个时钟域独立做“异步置位/复位,同步释放”;
- 对同步后的复位树进行合理复制;
- 不要在数据通路所有寄存器上都加不必要的异步复位;
- 检查 MMCM
LOCKED到下游复位的同步和稳定等待; - 不要简单 false path 掉整个复位网络,而忽略释放安全性。
对 Clocking Wizard、MIG、GT/JESD 等 IP,应遵循 IP 给出的复位序列和同步域要求。
19. Pulse Width / Minimum Period 违例
脉宽检查验证到达内部硬核/寄存器时钟脚的高电平、低电平和周期是否满足器件要求。常见于:
- 时钟周期约束过快;
-waveform占空比设置错误;- MMCM/PLL 输出频率或 VCO 配置非法;
- 时钟经过普通 LUT 逻辑产生窄脉冲;
- 时钟树偏斜过大;
- GT、DSP、BRAM 等硬核超过允许工作范围。
修改方法:
- 核对 create_clock 波形;
- 检查 Clocking Wizard/GT Wizard 配置;
- 使用 BUFGCE、BUFGCTRL 等专用无毛刺资源;
- 不要用普通逻辑门控时钟;
- 降低硬核时钟频率或更换合法分频;
- 检查器件 Data Sheet 的最小周期/脉宽限制。
20. I/O 时序违例
20.1 输入 Setup 失败
可能原因:
- 外部器件 Tco 太大;
- 数据走线比时钟长太多;
- 输入寄存器没有放入 IOB;
- 采样相位不合适;
- IDELAY 未校准或 tap 设置不合理;
- 输入 max delay 计算错误。
修改方法:
- 使用 IOB 输入寄存器/IDDRE1;
- 在 HP Bank 使用 IDELAYE3 调整采样点;
- 用 MMCM 调整采样相位;
- 对多 Lane 接口做训练和 deskew;
- 重新计算 PCB 与外部器件预算。
20.2 输入 Hold 失败
可能原因:数据过早到达、时钟 PCB 延时过大、输入 min 约束错误或内部时钟偏斜异常。可通过合法的 IDELAY、时钟相位和 PCB 关系调整,不能只增加时钟周期。
20.3 输出 Setup/Hold 失败
优先检查:
- 输出寄存器/ODDRE1 是否位于 IOB;
- 转发时钟是否被正确创建;
set_output_delay -min的负号是否正确;- 外部接收器 setup/hold 和 PCB 时延是否完整;
- PHY internal delay 与 FPGA 相移是否重复。
21. 跨时钟路径与时钟关系违例
21.1 AXI 两侧频率不同
例如 MIG UI AXI 为 300 MHz,而用户 AXI 为 125 MHz,仅修改接口 FREQ_HZ 属性并不能完成跨时钟。必须使用:
- AXI Clock Converter;
- SmartConnect 内部合法异步转换;
- 异步 FIFO/协议桥。
完成结构转换后,再正确声明异步时钟关系。若直接把 AXI 两侧设为 false path,而数据通路没有 CDC,硬件会出现随机握手错误。
21.2 AXIS UDP 到 DDR DMA
当前工程的数据通路可以抽象为:
各接口时钟不同时,应在边界放置协议级 CDC。TVALID/TREADY/TDATA/TLAST 不能逐根打两拍。
21.3 JESD/GT
当前 XCKU5P-FFVB676 使用 GTY。GT Wizard/JESD IP 会生成 GTYE4_*、BUFG_GT 和相关时钟约束。用户需要:
- 保留 IP XDC;
- 核对 TX/RX user clock 与 core clock 关系;
- 对进入用户逻辑的数据边界做正确 CDC;
- 不要自行 false path 掉所有 GT 输出时钟路径;
- 结合
report_clock_interaction检查 auto-derived clocks。
22. DDR4 MIG 时序约束注意事项
当前 DDR4 器件为 Micron MT40A1G16TB-062E,MIG 会管理 DDR I/O、字节组、内部生成时钟、校准路径及大量 IP XDC。
用户工程应重点约束的是:
- MIG 输入的差分系统时钟;
- MIG UI 时钟与用户逻辑时钟之间的关系;
- AXI Clock Converter/SmartConnect 的 CDC;
- 用户侧 AXI/AXIS 数据路径;
- 复位与
init_calib_complete使用方式。
不要:
- 手工覆盖 MIG 的 DDR DQ/DQS input/output delay;
- 把 MIG 内部校准路径随意 false path;
- 用用户 MMCM 输出去级联驱动 MIG MMCM,除非 MIG 明确支持该配置;
- 因接口属性显示 125 MHz/300 MHz 不一致,就只修改
FREQ_HZ文本属性。
MIG 的 init_calib_complete=1 只能证明存储器训练完成,不能证明用户 AXI 数据路径、缓存或软件地址访问一定正确。
23. 约束错误与真正 RTL 问题的区分流程
推荐每次分析都回答以下问题:
- 这条路径的启动和捕获时钟是谁?
- Vivado 选择的采样边沿是否符合协议?
- Requirement 为什么是这个数?
- 路径是否本应跨异步域?
- 数据延时主要花在逻辑还是布线?
- 是否存在高扇出或远距离硬核?
- 这类路径有一条还是成百上千条?
- 修改后是否影响了 valid/address/TLAST 等配套信号?
24. 从综合到布线的时序收敛流程
24.1 综合后
重点:
check_timing;- 时钟是否完整;
- 是否有异常逻辑级数;
- 资源是否按预期推断为 DSP/BRAM/SRL;
- 是否出现组合环和 latch;
- XDC 对象是否匹配。
24.2 opt_design 后
查看是否有明显网表结构问题、常量传播或控制集过多。
24.3 place_design 后
重点判断:
- 最差 setup 路径的物理跨度;
- 高扇出与拥塞;
- 大于约 0.5 ns 的异常 Hold 负裕量;
- Clock Region/SLR 跨越;
report_clock_utilization。
24.4 phys_opt_design
物理优化可进行单元复制、重定时、扇出优化、布局改善和部分 Hold 修复。它适合解决已经接近收敛的物理问题,不能修复错误的时钟关系和错误的 RTL 功能。
24.5 route_design 后
这是最终签核重点:
- 所有路由完成;
- WNS、TNS、WHS、THS、WPWS 均通过;
- 无未约束有效路径;
- DRC 和 Methodology 关键问题处理完成;
- CDC 结构通过检查;
- I/O 时序使用最终布线结果;
- 多个关键 path group 均有合理裕量。
25. 常用时序分析命令清单
# 时钟
report_clocks
report_clock_networks
report_clock_utilization
report_clock_interaction
# 约束覆盖
check_timing -verbose
report_exceptions
report_exceptions -coverage
# 时序路径
report_timing_summary -delay_type min_max
report_timing -delay_type max -max_paths 20
report_timing -delay_type min -max_paths 20
# CDC 与设计分析
report_cdc -details
report_design_analysis
report_methodology
report_qor_suggestions
# DRC
report_drc
不同 Vivado 版本的个别选项可能调整,脚本定稿前可用:
report_timing_summary -help
report_timing -help
26. 常见“错误修复方法”
26.1 把所有红色路径设成 false path
这只是删除检查,并没有修复硬件。只有功能上确实不需要同步分析、且 CDC 电路正确时才能使用。
26.2 为了通过报告随意降低 input/output delay
I/O delay 来自外部器件和 PCB,不是优化旋钮。降低数值相当于修改接口规格,硬件不会因此变快。
26.3 Setup 失败就不断切换实现 Strategy
若失败数 ns、逻辑级数很深或约束错误,换 Strategy 很难解决根因。先重构路径或修正约束;当 WNS 已接近 0 时,再探索实现策略更有效。
26.4 Hold 失败就降低频率
无效。应检查 min delay、时钟偏斜、multicycle hold 和路由修复。
26.5 在数据线上串 LUT 制造延时
普通逻辑延时不稳定,也可能被综合优化。I/O 精细延时使用 IDELAY/ODELAY,内部 Hold 通常交给路由器处理。
26.6 看到两个时钟频率相同,就认为同步
两个独立 100 MHz 晶振没有固定相位关系,仍属于异步时钟;同一 MMCM 输出的不同频率则可能同步。判断依据是相位关系来源,不是频率数字是否相等。
26.7 只看 WNS,不看未约束路径
这是最危险的“假通过”。必须同时检查 Check Timing、Clock Interaction、CDC、I/O delay 和时序例外覆盖。
27. 一个适合工程自动化的签核脚本
set report_dir ./timing_reports
file mkdir $report_dir
check_timing -verbose \
-file $report_dir/check_timing.rpt
report_timing_summary \
-delay_type min_max \
-max_paths 20 \
-report_unconstrained \
-file $report_dir/timing_summary.rpt
report_clock_interaction \
-file $report_dir/clock_interaction.rpt
report_cdc -details \
-file $report_dir/cdc.rpt
report_exceptions -coverage \
-file $report_dir/exceptions_coverage.rpt
report_methodology \
-file $report_dir/methodology.rpt
report_drc \
-file $report_dir/drc.rpt
report_qor_suggestions \
-file $report_dir/qor_suggestions.rpt
可以将脚本设置为 implementation 完成后的 hook,确保每次构建都生成同一套报告,便于版本对比和回归。
28. 工程签核检查清单
28.1 时钟
- 所有外部时钟均已
create_clock; - 周期、占空比和抖动来源正确;
- MMCM/PLL/GT 生成时钟频率与相位正确;
- 没有意外的 multiple clocks;
- 所有时钟使用合法专用资源;
- Clock Interaction 与真实同步关系一致。
28.2 I/O
- 所有同步输入均有 min/max input delay;
- 所有同步输出均有 min/max output delay;
- DDR 接口同时约束上升沿和下降沿;
- 外部 Tco/setup/hold 来自正确工作模式;
- PCB 时钟/数据走线差异已计入;
- IOB/IDDRE1/ODDRE1 实际放置符合预期。
28.3 CDC 与复位
- 单比特使用同步器;
- 多比特/AXI/AXIS 使用握手或异步 FIFO;
- 窄脉冲使用 pulse/toggle synchronizer;
- 异步复位在各时钟域同步释放;
-
ASYNC_REG属性正确; -
report_cdc中的问题已逐项解释。
28.4 时序例外
- 每条 false path 都有功能依据;
- Multicycle setup 和 hold 成对设置;
- 例外匹配的对象数符合预期;
- 不存在过宽的通配符;
- IP XDC 与用户 XDC 没有冲突;
-
report_exceptions -coverage已检查。
28.5 最终报告
- 使用 post-route implemented design;
- WNS ≥ 0、TNS = 0;
- WHS ≥ 0、THS = 0;
- WPWS ≥ 0、TPWS = 0;
- 没有应受约束却未约束的端点;
- DRC 和关键 Methodology 问题已经处理;
- 多板、温度、电压和长时间运行测试通过。
29. 总结
时序约束的核心不是记住 Tcl 命令,而是建立正确的时间模型:
- create_clock/create_generated_clock 描述时钟从哪里来、何时发生;
- set_input_delay/set_output_delay 描述 FPGA 与外部器件之间的时间预算;
- set_clock_groups 和 CDC 电路共同处理异步时钟域;
- false path、multicycle 等例外只能描述真实功能,不能用来隐藏违例;
- Setup 看最大延时,Hold 看最小延时,Pulse Width 看硬核和时钟波形限制;
- 先验证约束,再判断 Logic Delay、Net Delay、Clock Skew,最后选择 RTL 或物理优化方法;
- 最终签核必须同时检查约束覆盖、WNS/TNS、WHS/THS、脉宽、CDC、DRC 和 Methodology。
一个真正完成时序收敛的工程,不是 Timing Summary 顶部出现绿色字样,而是设计者能够解释每一个时钟、每一种跨域、每一条例外和每一类接口的时间预算。
参考资料
- AMD Vivado Design Suite User Guide: Using Constraints (UG903)
- AMD Vivado Design Suite User Guide: Design Analysis and Closure Techniques (UG906)
- AMD UltraFast Design Methodology Guide for FPGAs and SoCs (UG949)
- AMD Vivado Design Suite User Guide: Implementation (UG904)
- AMD Vivado Design Suite Tcl Command Reference Guide (UG835)
- AMD Vivado Design Suite Properties Reference Guide (UG912)
- AMD UltraScale Architecture Clocking Resources User Guide (UG572)
- AMD UltraFast Design Methodology:Design Closure
- AMD UG906:Check Timing Section
- AMD UG906:Pulse Width Checks
AMD 文档和 Vivado 命令选项会随版本更新。使用新版本 Vivado 时,应通过命令
-help和对应版本的官方文档核对选项;器件延时和硬核频率限制以目标 Part、封装与速度等级的数据为准。
334



被折叠的 条评论
为什么被折叠?



