Quick Start
- 打开 Vivado 2026.1,创建新工程,器件选择 Xilinx Artix-7 XC7A35T(示例)。
- 添加两个时钟源:clk_a(50 MHz)和 clk_b(75 MHz),通过 MMCM 生成。
- 编写一个简单的单比特 CDC 模块,使用双级触发器同步器。
- 编写一个多比特 CDC 模块,使用异步 FIFO(XPM 原语)。
- 添加时序约束:对两个时钟域分别定义 create_clock,对跨时钟路径设置 set_false_path 或 set_clock_groups。
- 运行综合与实现,检查时序报告,确认无违规路径。
- 编写 testbench,仿真验证 CDC 数据正确性。
- 上板测试,通过 ChipScope 观察同步后的信号。
前置条件与环境
| 项目 | 推荐值 | 说明 | 替代方案 |
|---|---|---|---|
| 器件/板卡 | Xilinx Artix-7 XC7A35T | 入门级 FPGA,支持 MMCM 与 XPM | Intel Cyclone V / Lattice ECP5 |
| EDA 版本 | Vivado 2026.1 | 最新稳定版,支持 XPM 与 CDC 约束向导 | Vivado 2024.2 / Quartus Prime Pro 24.3 |
| 仿真器 | Vivado Simulator | 内置于 Vivado,支持混合语言仿真 | ModelSim / Questa / Verilator |
| 时钟/复位 | 差分 100 MHz 板载晶振 | 经 MMCM 分频出 50 MHz 与 75 MHz | 单端晶振 + PLL |
| 接口依赖 | UART 或 GPIO | 用于观察同步后信号(可选) | ILA(Integrated Logic Analyzer) |
| 约束文件 | XDC(Xilinx Design Constraints) | 定义时钟与 CDC 例外 | SDC(Synopsys Design Constraints) |
目标与验收标准
- 功能点:单比特信号从 clk_a 到 clk_b 正确同步,无亚稳态传播;多比特数据通过异步 FIFO 无损传输。
- 性能指标:同步器引入延迟 ≤ 3 个目标时钟周期(双级触发器);异步 FIFO 吞吐 ≥ 90% 理论带宽。
- 资源/Fmax:双级同步器占用 2 个 FF + 0 LUT;异步 FIFO 占用 ≤ 2 个 BRAM(深度 512);Fmax ≥ 200 MHz(示例配置)。
- 验收方式:时序报告无 setup/hold 违规;仿真波形显示同步后信号无毛刺;上板后 ChipScope 捕获数据与预期一致。
实施步骤
1. 工程结构与模块划分
创建顶层模块 top,例化时钟生成模块 clk_gen、单比特 CDC 模块 sync_bit、多比特 CDC 模块 fifo_cdc。时钟生成:使用 MMCM 原语(MMCME2_BASE),输出 clk_a(50 MHz)和 clk_b(75 MHz)。单比特 CDC:双级 D 触发器链,输入 data_in(clk_a 域),输出 data_out(clk_b 域)。多比特 CDC:例化 XPM 异步 FIFO(xpm_fifo_async),深度 16,数据宽度 8 bit。验证模块:在 clk_a 域生成递增数据,写入 FIFO;在 clk_b 域读出并比对。
2. 关键模块实现
2.1 单比特同步器
module sync_bit (
input wire clk_b, // 目标时钟域
input wire rst_n, // 异步复位,低有效
input wire data_in, // 源时钟域信号
output wire data_out // 同步后输出
);
reg sync_ff1, sync_ff2;
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_in;
sync_ff2 <= sync_ff1;
end
end
assign data_out = sync_ff2;
endmodule逐行说明
- 第 1–5 行:模块端口声明。clk_b 是目标时钟,rst_n 是异步复位(低有效),data_in 来自源时钟域,data_out 是同步后输出。
- 第 7 行:定义两个寄存器 sync_ff1 和 sync_ff2,构成双级触发器链。
- 第 9–15 行:时序逻辑,在 clk_b 上升沿触发。复位时清零;否则将 data_in 打入第一级,再将第一级输出打入第二级。
- 第 17 行:将第二级寄存器输出赋给 data_out。此信号已与 clk_b 同步,亚稳态概率极低。
2.2 多比特 CDC(异步 FIFO)
module fifo_cdc #(
parameter DEPTH = 16,
parameter WIDTH = 8
)(
input wire wr_clk,
input wire rd_clk,
input wire rst,
input wire wr_en,
input wire [WIDTH-1:0] wr_data,
output wire full,
input wire rd_en,
output wire [WIDTH-1:0] rd_data,
output wire empty
);
xpm_fifo_async #(
.FIFO_MEMORY_TYPE ("auto"),
.FIFO_WRITE_DEPTH (DEPTH),
.WRITE_DATA_WIDTH (WIDTH),
.READ_DATA_WIDTH (WIDTH),
.PROG_EMPTY_THRESH (4),
.PROG_FULL_THRESH (12)
) u_fifo (
.sleep (1'b0),
.rst (rst),
.wr_clk (wr_clk),
.wr_en (wr_en),
.din (wr_data),
.full (full),
.rd_clk (rd_clk),
.rd_en (rd_en),
.dout (rd_data),
.empty (empty)
);
endmodule逐行说明
- 第 1–4 行:模块参数化,DEPTH 为 FIFO 深度,WIDTH 为数据位宽。
- 第 6–15 行:端口声明,包括写时钟 wr_clk、读时钟 rd_clk、复位 rst、写使能 wr_en、写数据 wr_data、满标志 full、读使能 rd_en、读数据 rd_data、空标志 empty。
- 第 17–30 行:例化 Xilinx 提供的 XPM 异步 FIFO 原语 xpm_fifo_async。参数设置:存储器类型自动选择,深度 16,数据宽度 8 bit,可编程空阈值 4,可编程满阈值 12。
- 第 31–42 行:端口连接,sleep 固定为 0(不休眠),其余端口与模块端口相连。
3. 时序约束与 CDC 处理
# 时钟定义
create_clock -name clk_a -period 20.000 [get_ports clk_a]
create_clock -name clk_b -period 13.333 [get_ports clk_b]
# 异步时钟组:clk_a 与 clk_b 之间不做时序分析
set_clock_groups -asynchronous -group [get_clocks clk_a] -group [get_clocks clk_b]
# 或使用 set_false_path(不推荐,因为会忽略所有跨时钟路径)
# set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]逐行说明
- 第 1–2 行:定义 clk_a 周期 20 ns(50 MHz),clk_b 周期 13.333 ns(75 MHz)。
- 第 4 行:使用 set_clock_groups -asynchronous 将两个时钟域设为异步,工具不会分析它们之间的时序路径。这是 CDC 设计的标准做法。
- 第 6–7 行:备选方案 set_false_path,但会忽略所有跨时钟路径,包括已经过同步器处理的路径,可能导致遗漏违规。不推荐。
4. 验证与仿真
编写 testbench:在 clk_a 域每 5 个时钟周期翻转 data_in,在 clk_b 域观察 data_out。仿真检查:data_out 应在 data_in 变化后 2–3 个 clk_b 周期内稳定,无毛刺。异步 FIFO 验证:写满后停止写,读空后停止读,检查数据完整性与顺序。常见坑:仿真中可能看到 data_out 在 data_in 变化前就变化(由于 delta 延迟),需设置合理延迟。
5. 上板测试
生成 bitstream,下载到 FPGA。使用 ChipScope 或 ILA 核,触发条件设为 data_in 上升沿,观察 data_out。对比仿真波形,确认同步后信号无毛刺。常见坑:ILA 时钟必须与同步器目标时钟一致(clk_b),否则采样错误。
原理与设计说明
为什么需要 CDC 同步器?
当信号从一个时钟域进入另一个时钟域时,如果目标时钟沿刚好在信号变化沿附近,触发器可能进入亚稳态,导致输出不确定,甚至传播到后续逻辑。同步器通过多级触发器链,给亚稳态足够时间恢复,降低其传播概率。
双级 vs 三级同步器
双级同步器(2-FF)在大多数设计中足够,MTBF(平均无故障时间)可达数十年。三级同步器(3-FF)用于极高可靠性要求(如航天、医疗),但增加延迟。对于普通消费电子,2-FF 是标准选择。
单比特 vs 多比特 CDC
单比特信号(如控制信号)可用 2-FF 同步器。多比特信号(如数据总线)不能用 2-FF,因为各比特可能在不同时钟周期稳定,导致数据错误。必须使用异步 FIFO 或握手协议(如格雷码指针)。异步 FIFO 内部使用格雷码指针,保证多比特指针在跨时钟域时只有一位变化,从而安全同步。
Trade-off 分析
- 资源 vs Fmax:同步器增加寄存器数量,但不会影响 Fmax,因为路径在同一时钟域内。异步 FIFO 使用 BRAM,深度越大资源越多,但 Fmax 受 BRAM 访问速度限制。
- 吞吐 vs 延迟:异步 FIFO 延迟取决于深度与读写速率,深度越大延迟越高。对于高吞吐场景,应选择适当深度避免溢出。
- 易用性 vs 可移植性:XPM 原语是 Xilinx 专用,移植到其他厂商需替换为对应原语或通用 FIFO 代码。通用 FIFO 代码可移植性好,但需自行处理 CDC 与格雷码。
验证与结果
| 指标 | 测量值(示例) | 测量条件 |
|---|---|---|
| Fmax(clk_a 域) | 250 MHz | Vivado 2026.1,Artix-7,速度等级 -1 |
| Fmax(clk_b 域) | 240 MHz | 同上 |
| 双级同步器延迟 | 2 个 clk_b 周期(约 8.33 ns) | 仿真与上板一致 |
| 异步 FIFO 吞吐 | 95% 理论带宽 | 写时钟 50 MHz,读时钟 75 MHz,深度 16 |
| 资源(双级同步器) | 2 FF | 综合报告 |
| 资源(异步 FIFO) | 1 BRAM(18K) | 深度 16,宽度 8 |
说明:以上数值为示例配置下的典型结果,实际值以具体工程与数据手册为准。
故障排查(Troubleshooting)
- 现象:时序报告显示 setup/hold 违规在跨时钟路径 → 原因:未设置 set_clock_groups 或 set_false_path → 检查点:约束文件中是否包含异步时钟组 → 修复:添加 set_clock_groups -asynchronous。
- 现象:仿真中 data_out 出现毛刺 → 原因:testbench 中 data_in 变化与 clk_b 沿太近 → 检查点:在 data_in 变化后加延迟 → 修复:使用非阻塞赋值或调整激励时序。
- 现象:上板后 data_out 不稳定 → 原因:ILA 采样时钟错误 → 检查点:ILA 核时钟是否连接 clk_b → 修复:重新配置 ILA 时钟。
- 现象:异步 FIFO 数据丢失 → 原因:写使能过早拉低或读使能过早拉高 → 检查点:full/empty 标志逻辑 → 修复:确保在 full 为低时写,empty 为低时读。
- 现象:综合报告显示同步器被优化掉 → 原因:data_in 被综合为常量 → 检查点:data_in 是否连接真实信号 → 修复:添加 (* keep = "true" *) 属性。
- 现象:时序分析报告显示跨时钟路径仍被分析 → 原因:set_clock_groups 语法错误或未生效 → 检查点:报告中的时钟组信息 → 修复:检查约束文件语法,使用 report_clock_interaction。
- 现象:异步 FIFO 读写指针不同步 → 原因:格雷码转换逻辑错误 → 检查点:仿真波形中指针值 → 修复:使用 XPM 原语或验证自定义格雷码代码。
- 现象:多比特信号同步后出现错误值 → 原因:误用 2-FF 同步器同步多比特数据 → 检查点:数据位宽 > 1 时是否使用 FIFO → 修复:改用异步 FIFO 或握手协议。
扩展与下一步
- 参数化同步器:将同步器模块改为参数化(级数、数据位宽),便于复用。
- 带宽提升:对于高吞吐场景,使用多通道异步 FIFO 或 AXI4-Stream 接口。
- 跨平台移植:将 XPM 原语替换为通用 FIFO 代码,适配 Intel、Lattice 等平台。
- 加入断言与覆盖:在仿真中添加 SVA 断言,验证 CDC 数据完整性;使用覆盖率分析确保所有路径被测试。
- 形式验证:使用工具(如 OneSpin)对 CDC 设计进行形式化验证,确保无亚稳态风险。
- 动态时钟切换:研究时钟切换(glitch-free mux)与 CDC 的结合,用于动态频率调整。
参考与信息来源
- Xilinx UG906: “Vivado Design Suite User Guide: Design Analysis and Closure Techniques” (2026.1)
- Xilinx UG953: “Vivado Design Suite User Guide: Constraints” (2026.1)
- Clifford E. Cummings, “Clock Domain Crossing (CDC) Design & Verification Techniques Using SystemVerilog” (SNUG 2008)
- Altera (Intel) AN 433: “Clock Domain Crossing Techniques for Altera Devices”
- Lattice Semiconductor: “Clock Domain Crossing (CDC) Design Guide” (FPGA-UG-02042)
技术附录
术语表
- CDC:Clock Domain Crossing,时钟域交叉。
- 亚稳态:触发器在时钟沿附近采样到变化信号时,输出处于不确定状态。
- MTBF:Mean Time Between Failures,平均无故障时间,衡量同步器可靠性。
- XPM:Xilinx Parameterized Macros,Xilinx 参数化宏。
- 格雷码:相邻值只有一位变化的编码,用于多比特指针跨时钟域同步。
检查清单
- [ ] 所有跨时钟路径已设置 set_clock_groups -asynchronous。
- [ ] 单比特信号使用双级或三级同步器。
- [ ] 多比特信号使用异步 FIFO 或握手协议。
- [ ] 仿真验证无毛刺与数据错误。
- [ ] 上板测试使用正确时钟的 ILA 核。
- [ ] 综合报告中同步器未被优化。
关键约束速查
# 异步时钟组
set_clock_groups -asynchronous -group [get_clocks clk_a] -group [get_clocks clk_b]


