跨时钟域处理的三种同步方案与工具实现对比
在FPGA/ASIC设计中,跨时钟域(CDC,Clock Domain Crossing) 是时序违例与功能Bug的高发区。单比特信号、多比特总线、脉冲需采用不同同步策略。本文给出三种经典CDC方案的RTL实现,并对比Synopsys SpyGlass CDC与Vivado Report CDC工具的检查能力差异。
一、方案①:双级触发器同步(单比特电平信号)
最基础也最常用的CDC结构,适用于状态标志、中断请求、模式选择等单比特电平信号(不可用于脉冲)。
// dest_clk域:两级同步
reg sync_ff1, sync_ff2;
always @(posedge dest_clk or negedge rst_n) begin
if (!rst_n) begin
sync_ff1 <= 1'b0;
sync_ff2 <= 1'b0;
end else begin
sync_ff1 <= src_signal; // 来自src_clk域的电平
sync_ff2 <= sync_ff1; // 已同步输出
end
end
assign synced_signal = sync_ff2;
要点:
• 必须设为 ASYNC_REG TRUE(告诉工具不做时序检查且放同一Slice):
set_property ASYNC_REG TRUE [get_cells {sync_ff1 sync_ff2}]
• 源信号需是电平保持至少2个dest_clk周期,脉冲需先展宽为电平再同步。
二、方案②:脉冲同步器(单比特脉冲跨时钟)
若src_clk域只产生一个周期宽度的脉冲,双FF会丢失(可能采样不到)。需用脉冲→电平→同步→边沿检测结构或专用脉冲同步器。
2.1 简易脉冲同步(要求src_clk慢于dest_clk足够多)
// src_clk域:脉冲转电平(Toggle)
reg toggle;
always @(posedge src_clk or negedge rst_n) begin
if (!rst_n) toggle <= 0;
else if (src_pulse) toggle <= ~toggle;
end
// dest_clk域:双FF同步 + 边沿检测
reg sync1, sync2, sync3;
always @(posedge dest_clk or negedge rst_n) begin
if (!rst_n) {sync1,sync2,sync3} <= 3'b000;
else begin
sync1 <= toggle;
sync2 <= sync1;
sync3 <= sync2;
end
end
assign dest_pulse = sync2 ^ sync3; // 检测Toggle变化 → 产生单周期脉冲
注意:src_clk频率不能远高于dest_clk,否则Toggle变化快于dest_clk采样可能漏检——此时建议用握手同步(方案③思想)或异步FIFO做事件计数。
三、方案③:异步FIFO / Gray码握手(多比特总线)
多比特并行数据(如 data[31:0])禁止直接双FF打拍,必须用异步FIFO(Gray指针跨时钟 + 双端口RAM)。
3.1 结构概要
[写侧 src_clk] → 写RAM + 生成Gray写指针 → 同步到读时钟域
[读侧 dest_clk] → 读RAM + 生成Gray读指针 → 同步到写时钟域
空/满判断基于同步后的Gray指针比较
3.2 调用示例(Xilinx FIFO Generator)
fifo_async_16x32 u_fifo (
.wr_clk(src_clk), .din(wdata_src), .wr_en(wr_en),
.rd_clk(dest_clk), .dout(wdata_dst), .rd_en(rd_en),
.full(full), .empty(empty)
);
CDC安全性完全由IP内部Gray码指针保证,用户只需确保写满不覆盖、读空不重复读。
四、CDC检查工具对比(SpyGlass CDC vs Vivado Report CDC)
维度 Synopsys SpyGlass CDC Vivado Report CDC
检测能力 深度:识别同步器类型、未约束跨时钟、伪路径遗漏、Reset同步缺失 基础:Unsafe CDC / Untested / Safe(基于结构匹配)
配置要求 需 SDC + CDC约束(-clock_domain、set_case_analysis) 自动从XDC推断时钟,简单项目够用
报告详细度 每个Unsafe CDC附源/目的代码行、建议加set_clock_groups或同步器 列出Path ID + Slack类型(Safe/Unsafe/Unknown)
适用阶段 大型SoC、签核前CDC Review FPGA原型快速检查
典型用法 sg_shell -f run_cdc.tcl → 查看 CDC_unsafe.rpt report_cdc -file cdc.rpt -max_paths 20
建议:FPGA项目至少跑 report_cdc 确认无 Red Unsafe;ASIC项目务必用 SpyGlass CDC 做专项审查并 Waive 已确认 Safe(加注释)。
五、常见设计错误速查
现象 原因 修正
跨时钟数据偶发错 多比特总线直接双FF打拍 改用异步FIFO或Gray码单比特握手
同步后仍采到X 源寄存器未初始化或跨时钟reset释放不同步 确保源FF有明确复位;必要时同步复位释放
SpyGlass报Unsafe但已加双FF 未标记 ASYNC_REG 或 clock_group 未设异步 加 set_property ASYNC_REG TRUE 或 set_clock_groups -asynchronous
脉冲跨时钟偶尔丢失 src_clk过快且Toggle同步器未做满判断 改用手动握手/计数或确保src周期≫dest周期
六、结语
跨时钟域处理遵循三条铁律:单比特电平→双FF同步(标记ASYNC_REG);单比特脉冲→Toggle同步或握手;多比特总线→异步FIFO(Gray指针)。配合SpyGlass CDC或Vivado report_cdc闭环验证,可把CDC隐患在流片/上板前消灭。





