Quick Start
- 打开Vivado,创建一个新工程(选择目标器件,例如xc7a35tcsg324-1)。
- 添加一个包含两个时钟域(clk_a, clk_b)的简单设计,并在两个域之间传递一个单比特信号。
- 编写一个基本的XDC约束文件,定义两个时钟的周期(例如:clk_a 100 MHz, clk_b 50 MHz)。
- 运行综合(Synthesis),然后打开综合后的设计(Open Synthesized Design)。
- 点击“Report Timing Summary”,在“Report Timing”对话框中,将“Path Type”设为“Setup”,并勾选“Report CDC Paths”。
- 观察生成的时序报告:你会看到跨时钟域路径被标记为“Unconstrained”(未约束)。
- 在XDC中添加“set_false_path”或“set_clock_groups”约束来正确处理这些CDC路径。
- 重新运行综合并再次报告时序,确认CDC路径不再显示为违例或未约束。
预期结果:用户应能识别出默认情况下Vivado对跨时钟域路径的处理方式,并学会用基本约束消除虚假的时序违例。
前置条件与环境
| 项目 | 推荐值 | 说明 | 替代方案 |
|---|---|---|---|
| 器件/板卡 | Xilinx Artix-7 (xc7a35tcsg324-1) | 入门级FPGA,支持多时钟域 | 其他7系列或UltraScale器件 |
| EDA版本 | Vivado 2024.2 | 推荐最新稳定版 | Vivado 2023.x / 2022.x |
| 仿真器 | Vivado Simulator | 内置于Vivado | ModelSim / Questa / VCS |
| 时钟/复位 | 两个独立时钟源(clk_a, clk_b) | 频率不同,例如100 MHz和50 MHz | 使用MMCM/PLL生成异步时钟 |
| 接口依赖 | 无外部接口,仅内部逻辑 | 可扩展至AXI等总线 | |
| 约束文件 | XDC文件 | 定义时钟、输入输出延迟、CDC约束 | SDC(Synopsys格式) |
目标与验收标准
- 功能点:设计能够在两个时钟域之间正确传递数据(单比特或简单同步器)。
- 性能指标:无时序违例(WNS ≥ 0),CDC路径被正确约束(false_path或clock_groups)。
- 资源/Fmax:资源消耗在合理范围内(例如少于100个LUT/FF),Fmax满足目标时钟频率。
- 验收方式:
- 打开Vivado的“Report Timing Summary”,确认Setup和Hold报告中无跨时钟域路径的违例。
- 在“CDC Report”中确认所有跨时钟域路径都被正确标记为“False Path”或“Clock Group”。
- 运行功能仿真,验证数据在跨时钟域传输时无丢失或错误。
实施步骤
1. 工程结构与RTL设计
创建一个简单的CDC示例:一个单比特信号从clk_a域传递到clk_b域,使用两级同步器。以下为完整RTL代码:
module cdc_example (
input wire clk_a,
input wire clk_b,
input wire rst_n,
input wire data_in, // 来自clk_a域
output wire data_out // 同步到clk_b域
);
reg data_a;
reg sync_ff1, sync_ff2;
always @(posedge clk_a or negedge rst_n) begin
if (!rst_n)
data_a <= 1'b0;
else
data_a <= data_in;
end
always @(posedge clk_b or negedge rst_n) begin
if (!rst_n) begin
sync_ff1 <= 1'b0;
sync_ff2 <= 1'b0;
end else begin
sync_ff1 <= data_a;
sync_ff2 <= sync_ff1;
end
end
assign data_out = sync_ff2;
endmodule逐行说明
- 第1行:定义模块名为cdc_example,端口列表开始。
- 第2行:输入端口clk_a,来自时钟域A。
- 第3行:输入端口clk_b,来自时钟域B。
- 第4行:输入端口rst_n,低电平有效的异步复位。
- 第5行:输入端口data_in,来自clk_a域的待同步单比特数据。
- 第6行:输出端口data_out,同步到clk_b域后的数据。
- 第8行:模块端口声明结束。
- 第10行:声明data_a寄存器,用于在clk_a域内寄存data_in。
- 第11行:声明sync_ff1和sync_ff2寄存器,构成两级同步器链。
- 第13行:always块,敏感列表为clk_a上升沿或rst_n下降沿。
- 第14行:如果rst_n为低电平(复位有效),则执行复位操作。
- 第15行:data_a被赋值为0。
- 第16行:else分支,非复位条件下。
- 第17行:data_a寄存data_in的值。
- 第19行:always块,敏感列表为clk_b上升沿或rst_n下降沿。
- 第20行:如果rst_n为低电平,则执行复位操作。
- 第21行:sync_ff1赋值为0。
- 第22行:sync_ff2赋值为0。
- 第23行:else分支,非复位条件下。
- 第24行:sync_ff1寄存data_a的值(从clk_a域捕获)。
- 第25行:sync_ff2寄存sync_ff1的值(第二级同步)。
- 第27行:assign语句,将sync_ff2连接到输出data_out。
- 第29行:模块结束。
2. XDC约束文件编写
创建约束文件(例如cdc_example.xdc),内容如下:
# 定义时钟
create_clock -period 10.000 -name clk_a [get_ports clk_a]
create_clock -period 20.000 -name clk_b [get_ports clk_b]
# 跨时钟域约束:将clk_a到clk_b的路径设为false path
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]
# 或者使用clock_groups(二选一)
# set_clock_groups -asynchronous -group [get_clocks clk_a] -group [get_clocks clk_b]逐行说明
- 第1行:注释行,说明以下为时钟定义部分。
- 第2行:创建clk_a时钟,周期10 ns(100 MHz),并将时钟源绑定到端口clk_a。
- 第3行:创建clk_b时钟,周期20 ns(50 MHz),并将时钟源绑定到端口clk_b。
- 第5行:注释行,说明以下为跨时钟域约束。
- 第6行:使用set_false_path命令,禁止对从clk_a时钟域到clk_b时钟域的所有路径进行时序分析。
- 第8行:注释行,说明另一种约束方式。
- 第9行:使用set_clock_groups命令,将clk_a和clk_b定义为异步时钟组,效果与set_false_path类似。
3. 综合与时序分析
在Vivado中运行综合(Synthesis),然后打开综合后的设计(Open Synthesized Design)。执行以下操作:
- 点击“Report Timing Summary”。
- 在“Report Timing”对话框中,将“Path Type”设为“Setup”。
- 勾选“Report CDC Paths”选项。
- 点击OK生成报告。
观察生成的时序报告:你会看到跨时钟域路径被标记为“Unconstrained”(未约束)。这是因为默认情况下,Vivado不会自动识别跨时钟域路径,而是将其视为同步路径进行分析,导致虚假的时序违例。
4. 应用约束并验证
在XDC中添加上述的set_false_path或set_clock_groups约束后,重新运行综合并再次报告时序。此时,CDC路径不再显示为违例或未约束。在“CDC Report”中,所有跨时钟域路径应被正确标记为“False Path”或“Clock Group”。
5. 功能仿真验证
编写一个简单的testbench,驱动clk_a和clk_b,并观察data_out是否正确反映data_in的变化。注意:由于同步器引入了两拍延迟,data_out的变化会比data_in滞后两个clk_b周期。
验证结果
完成上述步骤后,应满足以下验收标准:
- Setup和Hold报告中无跨时钟域路径的违例。
- CDC报告中所有跨时钟域路径被正确标记为“False Path”或“Clock Group”。
- 功能仿真显示数据在跨时钟域传输时无丢失或错误。
排障指南
- 问题:时序报告中仍有CDC路径违例
原因:可能未正确添加set_false_path或set_clock_groups约束。检查XDC语法和时钟名称是否匹配。
- 问题:CDC报告未显示任何路径
原因:可能未勾选“Report CDC Paths”选项,或者设计中确实没有跨时钟域路径。
- 问题:功能仿真中数据丢失
原因:同步器级数不足或复位不同步。对于单比特信号,两级同步器通常足够;对于多比特信号,需使用FIFO或握手协议。
扩展实践
本指南仅涉及单比特CDC的基础约束。在实际项目中,你可能需要处理:
- 多比特CDC(使用异步FIFO)。
- 控制信号CDC(使用握手协议)。
- 复杂时钟拓扑(多个PLL/MMCM生成的时钟)。
- 使用set_max_delay约束来限制CDC路径的最大延迟。
参考资源
- Vivado Design Suite User Guide: Using Constraints (UG903)
- Vivado Design Suite User Guide: Design Analysis and Closure Techniques (UG906)
- Xilinx Answer Record 65444: CDC Constraints and Reports
附录:完整XDC示例
# 时钟定义
create_clock -period 10.000 -name clk_a [get_ports clk_a]
create_clock -period 20.000 -name clk_b [get_ports clk_b]
# 跨时钟域约束
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]
# 可选:使用clock_groups
# set_clock_groups -asynchronous -group [get_clocks clk_a] -group [get_clocks clk_b]逐行说明
- 第1行:注释,说明以下为时钟定义。
- 第2行:创建clk_a时钟,周期10 ns,绑定到端口clk_a。
- 第3行:创建clk_b时钟,周期20 ns,绑定到端口clk_b。
- 第5行:注释,说明以下为跨时钟域约束。
- 第6行:设置false path,禁止从clk_a到clk_b的时序分析。
- 第8行:注释,说明另一种约束方式。
- 第9行:使用clock_groups命令,将两个时钟设为异步组。

评论 0