Quick Start
- 打开 Vivado 2026.1,创建或打开一个包含多时钟域的设计工程(例如:主时钟 100 MHz,派生时钟 50 MHz 和 25 MHz)。
- 完成综合(Synthesis)并打开综合后的设计(Open Synthesized Design)。
- 在 Tcl Console 中输入
report_clock_interaction,查看时钟域间是否存在路径。 - 输入
report_timing_summary -delay_type min_max -report_unconstrained -max_paths 10,生成默认时序总结报告。 - 在 GUI 中点击 Reports → Report Timing Summary,勾选“Group by Clock Domains”和“Report Unconstrained Paths”。
- 观察报告中的“Clock Domain Crossings”部分,确认每个跨时钟域路径是否被正确分组。
- 使用
report_timing -from [get_clocks clk_a] -to [get_clocks clk_b] -nworst 5检查特定时钟域间的路径。 - 预期结果:报告按源时钟和目标时钟分组,每个分组内列出最差路径(Worst Negative Slack, WNS),且无未约束路径(Unconstrained Paths)警告。
前置条件与环境
| 项目 | 推荐值 | 说明 | 替代方案 |
|---|---|---|---|
| 器件 / 板卡 | Xilinx Artix-7 XC7A35T(示例) | 任何 7 系列或 UltraScale+ 器件,如 Kintex-7、Virtex-7 | — |
| EDA 版本 | Vivado 2026.1(本文基准版本) | Vivado 2023.2+ 也可,但部分 GUI 选项位置可能微调 | — |
| 仿真器 | Vivado Simulator (xsim) | — | ModelSim/Questa、VCS、Verilator |
| 时钟 / 复位 | 至少两个异步时钟域(如 100 MHz 和 50 MHz),同步复位 | 异步复位亦可,但需额外 CDC 处理 | — |
| 接口依赖 | 无特殊 IP 要求,纯 RTL 设计即可 | 若含 IP,需确保 IP 的时钟约束已正确生成 | — |
| 约束文件 | XDC 文件包含主时钟、生成时钟、异步时钟组(set_clock_groups) | 若无 XDC,Vivado 会自动推断,但结果不可靠 | — |
目标与验收标准
- 功能点:正确识别设计中所有跨时钟域路径,并按源/目标时钟分组。
- 性能指标:每个时钟域内时序收敛(WNS ≥ 0),跨时钟域路径的 Slack 被正确计算(若未约束则显示为 Unconstrained)。
- 资源 / Fmax:Fmax 满足设计要求(示例:100 MHz 域 ≥ 100 MHz,50 MHz 域 ≥ 50 MHz)。
- 关键波形 / 日志:时序总结报告中“Clock Domain Crossings”表格列出所有跨时钟域分组,且每个分组内路径条数非零(若存在跨域路径)。
实施步骤
工程结构与约束准备
创建一个简单的多时钟域设计,包含两个异步时钟域之间的数据路径。以下 RTL 代码示例:
module multi_clock_demo (
input wire clk_100m, // 100 MHz 主时钟
input wire clk_50m, // 50 MHz 派生时钟(来自 MMCM/PLL)
input wire rst_n,
input wire [7:0] data_in,
output reg [7:0] data_out
);
reg [7:0] sync_reg1, sync_reg2;
// 跨时钟域同步器(2 级触发器)
always @(posedge clk_50m or negedge rst_n) begin
if (!rst_n) begin
sync_reg1 <= 8'd0;
sync_reg2 <= 8'd0;
end else begin
sync_reg1 <= data_in;
sync_reg2 <= sync_reg1;
end
end
// 在 50 MHz 域输出
always @(posedge clk_50m or negedge rst_n) begin
if (!rst_n)
data_out <= 8'd0;
else
data_out <= sync_reg2;
end
endmodule逐行说明
- 第 1 行:模块声明,输入端口 clk_100m 和 clk_50m 为两个时钟,rst_n 为低电平有效复位。
- 第 2–3 行:两个时钟输入,分别来自外部晶振和 MMCM/PLL 输出。
- 第 4 行:异步复位,低电平有效。
- 第 5–6 行:8 位数据输入和输出。
- 第 8 行:声明两个 8 位寄存器,用于两级同步。
- 第 11–17 行:在 clk_50m 域内实现两级同步器。第一级采样 data_in(来自 clk_100m 域),第二级采样第一级输出。这是标准的 CDC 同步器结构,用于避免亚稳态传播。
- 第 20–25 行:将同步后的数据赋值给 data_out,完成跨时钟域数据传输。
对应的 XDC 约束文件(demo.xdc):
# 主时钟约束
create_clock -period 10.000 -name clk_100m [get_ports clk_100m]
# 派生时钟约束(假设由 MMCM 生成)
create_clock -period 20.000 -name clk_50m [get_ports clk_50m]
# 将两个时钟域声明为异步组,避免 Vivado 自动分析跨域路径时序
set_clock_groups -asynchronous -group [get_clocks clk_100m] -group [get_clocks clk_50m]逐行说明
- 第 1 行:定义 100 MHz 主时钟,周期 10 ns,端口名为 clk_100m。
- 第 2 行:定义 50 MHz 派生时钟,周期 20 ns,端口名为 clk_50m。实际工程中 clk_50m 通常由 MMCM/PLL 输出,此处为简化直接使用端口。
- 第 5 行:使用 set_clock_groups 将两个时钟域声明为异步。这告诉 Vivado 不要分析这两个时钟域之间的时序路径,因为跨域路径已由同步器处理。若不添加此约束,Vivado 会尝试计算跨域路径的 Slack,导致大量误报(false paths)。
时序分析:生成分组报告
综合后,运行以下 Tcl 命令生成分组时序报告:
# 生成带分组的时序总结报告
report_timing_summary -delay_type min_max -report_unconstrained -max_paths 20 -group_by clock_domains逐行说明
- 第 1 行:-delay_type min_max 同时报告建立时间和保持时间检查。
- 第 2 行:-report_unconstrained 显示未约束路径(例如跨异步时钟域但未用 set_clock_groups 的路径)。
- 第 3 行:-max_paths 20 每个分组最多显示 20 条路径。
- 第 4 行:-group_by clock_domains 按源时钟和目标时钟分组输出。
预期输出片段(示例):
Clock Domain Crossings:
From clk_100m to clk_50m: 1 paths (Unconstrained)
From clk_50m to clk_100m: 0 paths
From clk_100m to clk_100m: 10 paths (WNS = 0.123 ns)
From clk_50m to clk_50m: 5 paths (WNS = 0.456 ns)逐行说明
- 第 1 行:标题,指示跨时钟域分组。
- 第 2 行:从 clk_100m 到 clk_50m 有 1 条路径,标记为 Unconstrained,因为我们使用了 set_clock_groups,Vivado 不计算其 Slack。
- 第 3 行:反向路径数为 0,因为设计中无此方向路径。
- 第 4 行:同时钟域 clk_100m 内部路径,WNS 为 0.123 ns(正 Slack,满足时序)。
- 第 5 行:同时钟域 clk_50m 内部路径,WNS 为 0.456 ns。
验证结果
| 测量项 | 示例值 | 测量条件 |
|---|---|---|
| Fmax(clk_100m 域) | 125 MHz | Vivado 2026.1 综合后时序报告,Artix-7 -1 速度等级 |
| Fmax(clk_50m 域) | 150 MHz | 同上 |
| 资源(LUT) | 12 个 | 仅同步器逻辑,不含其他功能 |
| 资源(FF) | 16 个 | 8 位数据 × 2 级同步 |
| 跨域路径 WNS | N/A(Unconstrained) | 因 set_clock_groups 跳过 |
| 同域路径 WNS | 0.123 ns | clk_100m 域最差路径 |
以上数值基于示例设计,实际结果以具体工程和数据手册为准。
故障排查(Troubleshooting)
- 现象 1:报告显示大量跨域路径且 Slack 为负。
原因:未使用 set_clock_groups 或 set_false_path。
检查点:在 Tcl Console 输入 report_clock_interaction 查看时钟交互。
修复建议:在 XDC 中添加 set_clock_groups -asynchronous -group [get_clocks clk_a] -group [get_clocks clk_b]。 - 现象 2:分组报告中缺少某个时钟域。
原因:该时钟域未正确约束或未连接任何路径。
检查点:运行 report_clocks 确认时钟存在。
修复建议:检查 XDC 中 create_clock 是否正确,或检查 RTL 中时钟连接。 - 现象 3:Unconstrained Paths 部分显示非零值。
原因:存在未使用 set_clock_groups 的跨域路径。
检查点:查看 Unconstrained Paths 的源和目标时钟。
修复建议:在 XDC 中添加对应约束。 - 现象 4:同域路径 WNS 为负。
原因:逻辑延迟过大或时钟周期过紧。
检查点:使用 report_timing -max_paths 1 查看最差路径的详细延迟。
修复建议:优化 RTL(减少组合逻辑级数)或降低时钟频率。 - 现象 5:报告显示“No constrained paths”。
原因:未添加任何时钟约束。
检查点:检查 XDC 文件是否被包含在工程中。
修复建议:添加 create_clock 约束。 - 现象 6:GUI 中“Group by Clock Domains”选项不可用。
原因:Vivado 版本低于 2023.2 或当前视图不支持。
检查点:确认在“Open Synthesized Design”或“Open Implemented Design”下操作。
修复建议:使用 Tcl 命令 report_timing_summary -group_by clock_domains 替代。 - 现象 7:跨域路径被错误地标记为“Unconstrained”,但实际需要约束。
原因:误将同步路径用 set_clock_groups 排除。
检查点:检查同步器是否应被约束(例如握手协议需要时序检查)。
修复建议:对同步器路径使用 set_max_delay 或 set_false_path 替代异步组。 - 现象 8:报告生成时间过长。
原因:-max_paths 设置过大或设计规模大。
检查点:降低 -max_paths 值(如 10)。
修复建议:先使用 report_clock_interaction 快速预览。
扩展与下一步
- 参数化同步器:将同步级数作为参数,便于在不同可靠性要求间切换。
- 异步 FIFO:使用 Vivado 的 FIFO IP 或自行设计异步 FIFO,处理批量数据跨时钟域传输。
- 跨平台:将约束和设计移植到 Intel Quartus 或 Lattice Diamond,注意命令差异(如 set_clock_groups 对应 set_false_path)。
- 断言与覆盖:在仿真中添加 SVA(SystemVerilog Assertion)检查跨域数据完整性,如数据丢失或重复。
- 形式验证:使用 Vivado 的 formal 工具或第三方工具(如 OneSpin)验证 CDC 同步器的正确性。
参考与信息来源
- Xilinx UG906: Vivado Design Suite User Guide: Design Analysis and Closure Techniques (2026.1)
- Xilinx UG949: Vivado Design Suite User Guide: Methodology (2026.1)
- Xilinx AR# 123456: Understanding Clock Domain Crossing Reports in Vivado (示例)
- Clifford E. Cummings, “Clock Domain Crossing (CDC) Design & Verification Techniques”, SNUG 2008
技术附录
术语表
- CDC:Clock Domain Crossing,时钟域交叉。
- WNS:Worst Negative Slack,最差负时序裕量。
- MTBF:Mean Time Between Failures,平均无故障时间。
- XDC:Xilinx Design Constraints,Xilinx 约束文件格式。
检查清单
- [ ] 所有时钟已用 create_clock 约束。
- [ ] 异步时钟域已用 set_clock_groups 分组。
- [ ] 同步器路径已正确处理(set_false_path 或 set_max_delay)。
- [ ] 时序总结报告无 Unconstrained Paths 警告。
- [ ] 同域路径 WNS ≥ 0。
关键约束速查
# 主时钟
create_clock -period 10.000 -name clk_a [get_ports clk_a]
# 派生时钟(若由 MMCM 生成,IP 会自动添加)
create_clock -period 20.000 -name clk_b [get_ports clk_b]
# 异步时钟组
set_clock_groups -asynchronous -group [get_clocks clk_a] -group [get_clocks clk_b]
# 若需对同步器路径设置最大延迟(可选)
set_max_delay -from [get_cells sync_reg1] -to [get_cells sync_reg2] 5.000逐行说明
- 第 1–2 行:定义主时钟 clk_a,周期 10 ns。
- 第 4–5 行:定义派生时钟 clk_b,周期 20 ns。
- 第 7 行:将 clk_a 和 clk_b 设为异步时钟组,避免跨域路径的时序分析。
- 第 9 行:可选约束,对同步器路径设置最大延迟 5 ns,用于 CDC 验证。



