Vivado 时钟约束缺失:unconstrained clock 速查
更新时间:2026-10-25。FAQ 速查页,属于 FPGA 工具排错系列。Vivado 时序分析的前提是「每个时钟都被定义」:漏一条
create_clock,挂在它下面的所有路径就整个从时序分析里消失——不是变宽松,是根本不被检查,综合实现照样过,板子上才翻车。这类问题的凶险之处恰恰是「不报 ERROR,只报 WARNING」。跨工具对照见 Quartus 时钟约束缺失 与 Yosys 时钟约束缺失,约束入门见 XDC 约束入门。
本文要回答的问题
- 怎么确认设计里有没有漏约束的时钟?
create_clock该写在哪一级,引脚还是内部节点?- 哪些路径该用虚假路径、哪些该用多周期,写错了有什么后果?
- 多个 XDC 文件的作用域与顺序有什么坑?
一、报错原文与现象
CRITICAL WARNING: [Timing 38-282] The design failed to meet the timing requirements.
WARNING: [Timing 38-313] There are 2 user clock(s) that are not constrained.
CRITICAL WARNING: [Vivado 12-4739] No clocks defined on pin 'sys_clk_p'.
check_timing 报告: no_clock (124 endpoints) / unconstrained_internal_pins最典型的现象是:report_timing_summary 里 WNS 一栏显示 NA 或者分析的路径数少得反常,而 check_timing 报告里 no_clock、unconstrained_internal_pins 挂着几百上千个端点。时钟没定义时,相关路径整体缺席,报告看起来「很干净」——干净是假象。
二、可能原因总览
| 报错/现象 | 可能原因 | 处置 |
|---|---|---|
| no_clock 端点很多 | 主时钟没写 create_clock | 在外部时钟引脚上补 create_clock |
| 内部时钟未被分析 | 生成时钟靠自动推导失败 | 手写 create_generated_clock 或修主时钟 |
| 路径数异常少 | 时钟定义在错误节点被截断 | 时钟定义移到源引脚,检查穿越逻辑 |
| 跨异步域大量违例刷屏 | 缺 set_false_path / set_clock_groups | 对真异步路径补约束,别全局放松 |
| 低速使能路径违例 | 该用多周期没写 multicycle | 按使能节拍写 set_multicycle_path |
| 输入输出时序不收敛 | 缺 set_input_delay / set_output_delay | 按外部器件时序补 IO 约束 |
| 复位路径报时序违例 | 异步复位被当时序路径分析 | false_path 复位 + 同步释放 |
| 改了一个 XDC 全乱了 | 多 XDC 顺序与作用域冲突 | 统一成一个约束集,明确加载顺序 |
三、逐条排查展开
第一步永远是 check_timing,不是看 WNS。 它是 Vivado 自带的「约束体检」,直接列出所有没分析到的角落:
check_timing -verbose -file check_timing.rpt重点看四个小节:no_clock(有时钟波形但没定义的端点)、unconstrained_internal_pins(时钟到达不了的内部时序引脚)、no_input_delay / no_output_delay(没写 IO 约束的端口)、loops(组合环)。这份报告清不干净,时序收敛数字再好听都不可信。
主时钟写在外部引脚上,一个都不能漏。 每一个从封装引脚进来的时钟都要有一条 create_clock,写在 port 上而不是内部 net 上:
create_clock -period 10.000 -name sys_clk [get_ports sys_clk_p]
create_clock -period 8.000 -name gtx_ref [get_ports gtx_refclk_p]差分时钟只约束 p 端。写完后用 report_clocks 核对:每个时钟的周期、来源引脚、驱动的负载数是否符合预期——负载数为 0 说明约束名拼错或没匹配到任何对象。
生成时钟优先让工具推导,推导不了再手写。 MMCM/PLL 的输出时钟一般不需要手写 create_generated_clock,Vivado 会自动从主时钟推导;但如果时钟路径上经过了自己写的分频寄存器或门控逻辑,自动推导就断了。判别方法还是 report_clocks:该有的时钟不在列表里,就手写补上:
create_generated_clock -name clk_div2 -source [get_pins clkdiv_reg/C] \
-divide_by 2 [get_pins clkdiv_reg/Q]跨异步域:用 set_clock_groups 一刀切,别逐条 false_path。 两个真正异步的时钟域之间(比如本地时钟与外部收发时钟),推荐声明异步组:
set_clock_groups -asynchronous -group [get_clocks sys_clk] -group [get_clocks gtx_clk]这比逐条 set_false_path -from ... -to ... 更彻底也更安全——false_path 写错方向会漏检,set_clock_groups -asynchronous 是双向的。但注意前提:跨域处必须有正确的同步器或异步 FIFO;约束只是告诉工具「别检查时序」,不替你做时钟域穿越设计。异步复位的释放路径同理:set_false_path -from [get_ports sys_rst_n],然后设计里做同步释放。
多周期路径按节拍写,不要拍脑袋放宽。 每 N 拍更新一次的使能路径(典型:低速控制寄存器、分频使能的数据通路),用多周期约束告诉工具真实的建立保持关系:
set_multicycle_path 4 -setup -from [get_cells slow_reg*] -to [get_cells datapath_reg*]
set_multicycle_path 3 -hold -from [get_cells slow_reg*] -to [get_cells datapath_reg*]setup 给 N、hold 必须给 N-1,这是最常见的写错点——只写 setup 不写 hold,保持时间检查会立刻报一大堆违例。写之前先在波形上确认这个路径真的是 N 拍一拍有效,多周期写错等于把假路径变成真时序漏洞。
IO 约束照外部器件数据手册算。 set_input_delay / set_output_delay 表达的是板级对端器件的建立保持需求,照对端芯片手册的时序参数填:
set_input_delay -clock gtx_ref -max 2.5 [get_ports rx_data*]
set_output_delay -clock sys_clk -min -1.0 [get_ports tx_data*]max 值对应对端最苛刻的建立时间需求,min 值对应保持时间需求(常为负数),两个值都要写——只写 max 不写 min,保持时间侧等于没约束。写完后 report_timing -to [get_ports ...] 抽查输出路径,确认延迟确实被计入了分析。
多个 XDC 的顺序就是约束的生效顺序。 工程里多个 XDC 并存时,Vivado 按 Properties 里的加载顺序执行,后写的 -add_delay、被 get_clocks 匹配不到的对象,都会静默改变语义。纪律:时钟定义集中放在最先加载的一个 XDC 里,其余文件只做 false_path/multicycle 等路径级约束;get_ports 通配符写宽了会误伤,写完用 report_timing -from ... -to ... 抽查几条关键路径确认约束真的命中了。
四、排查流程图
图的主线是从上到下逐级收敛:先体检列全漏点,再按「主时钟 → 生成时钟 → 路径级约束」的层级补——顺序不能反,先写 false_path 而主时钟还缺着,等于在没地基的墙上刷漆。红色是入口告警,蓝色是排查动作,橙色是补齐动作,绿色是复核通过,紫色是长期纪律。
五、预防与纪律
- check_timing 清零才算约束完成:no_clock、unconstrained_internal_pins、loops 三小节必须为空或每条都有书面理由。
- 时钟定义集中管理:所有 create_clock / create_generated_clock 放一个最先加载的 XDC,路径级约束放后面的文件。
- 新增时钟必配约束评审:RTL 里每引入一个新时钟源(新 PLL 输出、新分频器),同一提交里必须带对应约束。
- false_path 逐条带注释:每条放松约束注释说明「这条路径为什么物理上不可能违例」,没有理由的放松就是漏检。
- 多周期先画波形再写约束:setup N、hold N-1 成对出现,写完用 report_timing 抽查命中。
- 版本升级后重跑 check_timing:工具版本更迭会改变时钟推导行为,升级当天就体检一遍,别等时序出问题才回头查约束。
还有一个容易忽略的交叉点:约束缺失会让实现的优化方向整个跑偏。布局布线器只优化「被约束的路径」,没被约束的路径在工具眼里没有时序要求,可能被打散到器件的任意角落——板子上表现出来的就是「报告全绿、功能偶发错」。这正是为什么 check_timing 清零要放在看 WNS 之前:先保证分析的完整性,再谈分析的结果。
这一篇在知识体系里的位置
本篇是 FPGA 排错速查簇中「时序约束」节点的 Vivado 页:与 Quartus 时钟约束缺失、Yosys 时钟约束缺失 互为跨工具对照;约束语法系统学习见 时序约束基础 与 XDC 约束入门,系列总览见 FPGA 知识版图。
一句话总结
Vivado 时钟约束缺失先用 check_timing -verbose 做体检列出所有漏约束点,然后按层级补齐:外部引脚逐个 create_clock、自动推导断掉的生成时钟手写 create_generated_clock、真异步域用 set_clock_groups -asynchronous、低速使能路径成对写 set_multicycle_path(setup N 配 hold N-1)、IO 按对端手册写 input/output delay;纪律上时钟定义集中在一个最先加载的 XDC,check_timing 清零才放行实现。