SpyGlass CDC 规则参考手册

全面覆盖 Synopsys VC SpyGlass CDC 验证规则 — 电路拓扑 · 波形动画 · 修复方法 · Waiver 指南

26
CDC 规则
6
同步方案
8
规则分类
45+
Waiver 标签
🔓

未同步跨越 (Unsynchronized Crossings)

3 条规则

Ac_unsync01 — 单bit信号未同步跨时钟域

ERROR cdc_verify_struct
Clock Domain A (clk_a) Clock Domain B (clk_b) F1 D Q clk_a F2 D Q clk_b ✗ 无同步器 ⚠ 亚稳态风险 (Metastability)
clk_a clk_b data_a data_b META ← 亚稳态:值不确定

问题描述

信号 data_a 直接从时钟域 A (clk_a) 传递到时钟域 B (clk_b),中间没有任何同步逻辑。当两个时钟是异步关系时,目的寄存器 F2 可能在数据跳变瞬间采样,导致 setup/hold time 违例,进而产生亚稳态 (Metastability)。

潜在影响

  • 目的寄存器输出值不确定(可能为 0、1 或中间电平振荡)
  • 亚稳态可能沿下游逻辑传播,导致功能错误
  • 问题具有随机性,仿真难以复现

检查阶段

Severity: Error   Goal: cdc_verify_struct

修复方法:添加二级同步器 (2-FF Synchronizer)

在目的时钟域中插入至少两级寄存器作为同步器,使亚稳态在到达下游逻辑前稳定下来。

Domain A Domain B F1clk_a S1clk_b S2clk_b F2clk_b ✓ 2-FF Synchronizer
Verilog// 二级同步器 always @(posedge clk_b or negedge rst_b_n) begin if (!rst_b_n) begin sync_r1 <= 1'b0; sync_r2 <= 1'b0; end else begin sync_r1 <= data_a; // 第一级同步 sync_r2 <= sync_r1; // 第二级同步, 输出稳定信号 end end assign data_b = sync_r2;

Waiver 条件

仅在以下情况下可以考虑 Waive:

  • Stable Signal (准静态信号): 信号在正常工作模式下几乎不变(如配置寄存器),可使用 quasi_static 约束
  • Clock Off: 信号跨越时,目的时钟域处于关闭状态
  • Receiver Ignore: 目的端不使用该信号的值
Waiver 标签适用场景SVA 支持
Stable Signal;<Enable Condition>信号为准静态,由使能条件控制✅ Yes
Stable Signal Clock Off;<Enable>目的时钟域关闭时信号跨越✅ Yes
Stable Signal Receiver Ignore目的端不使用该信号✅ Yes
SGDC# SGDC 约束示例 - 准静态信号 quasi_static -name "top.u_cfg.config_reg[7:0]" # TCL Waiver 示例 set_cdc_waiver -scheme unsynchronized \ -from {top.u_src.cfg_data} \ -to {top.u_dst.cfg_reg} \ -comment "Stable Signal;CSR config bit, stable during functional mode"

Ac_unsync02 — 多bit信号未同步跨时钟域

ERROR cdc_verify_struct
Domain A (clk_a) Domain B (clk_b) F1[0] F1[1] F1[n] F2[0] F2[1] F2[n] ✗ bus[n:0] 各bit独立采样 → 数据不一致
clk_b ↑ data[1:0] = 2'b00 → 2'b11 00 11 sampled 01 或 10 ?! 11 各bit到达时间不同 → 采到中间值 !

问题描述

多bit总线 data[n:0] 从时钟域 A 直接传递到时钟域 B,没有使用同步逻辑。由于各bit路径延时不同,目的时钟域可能采到中间状态值(如 00→11 过程中采到 01 或 10),导致数据不一致。

潜在影响

  • 多bit信号各bit不同时到达,采样到错误的组合值
  • 如果是计数器/地址信号,可能采到非法值导致严重功能错误
  • 使用二进制编码的多bit信号风险最高(多bit同时跳变)

修复方法

根据使用场景选择合适的同步方案:

  • 异步 FIFO: 适用于数据流传输,使用格雷码指针同步
  • 握手协议 + MUX: 适用于低速数据传输,先稳定数据再传使能
  • 格雷码编码: 适用于计数器等连续变化信号(相邻值只有1bit变化)
  • DMUX同步: 使能信号做2-FF同步,数据走MUX选通
Domain A Domain B DATA EN S1 S2 D_OUT MUX ✓ EN经2-FF同步 → 控制MUX选通数据
Verilog// DMUX 同步方案:使能信号同步 + 数据 MUX 选通 // 1. 在源端稳定数据,拉高使能 // 2. 使能信号通过 2-FF 同步到目的时钟域 // 3. 同步后的使能控制 MUX 选通稳定的数据 wire en_sync; // 同步后的使能 cdc_demet u_sync (.clk(clk_b), .d(en_a), .q(en_sync)); always @(posedge clk_b) if (en_sync) data_b <= data_a; // 使能有效时锁存数据

Waiver 条件

  • DMUX Synchronization: 如果设计中已有使能同步逻辑但工具未自动识别
  • quasi_static: 总线为准静态配置数据
  • Stable Signal: 功能上保证数据在采样窗口前已稳定
Waiver 标签适用场景SVA 支持
DMUX Synchronization;<Enable Signal>有使能同步逻辑但未被工具识别❌ No
Stable Signal;<Enable Condition>总线数据在采样时已稳定✅ Yes
SGDC# 准静态信号约束 quasi_static -name "top.u_cfg.bus_data[31:0]" # TCL Waiver set_cdc_waiver -scheme unsynchronized \ -from {top.u_src.data_bus[*]} \ -to {top.u_dst.data_reg[*]} \ -comment "DMUX Synchronization;en_sync controls data capture"

Ac_unsync03 — 多位信号通过单个同步器跨时钟域

ERRORcdc_verify_struct
Domain A (clk_a) Domain B (clk_b) D[0] D[1] D[n] S1(D[0]) S2(D[0]) D[n:0] ✗ 多位bit共用同步器 各bit延时不同 → 采样到中间值
clk_b ↑ D[0] D[1] sampled D[0]=1, D[1]=0 ?! 各bit到达时间不同 → 采到中间值

问题描述

多位总线 data[n:0] 的所有bit共用一个同步器(只有一个 2-FF 同步器对某一bit同步,其余bit直接连接)。由于各bit的路径延时不同,目的时钟域可能采到不一致的中间状态,导致数据错误。

与 Ac_unsync02 的区别

  • Ac_unsync02: 多位信号完全没有同步器
  • Ac_unsync03: 多位信号有同步器,但只对部分bit同步,其余bit直接连接
  • 两者都会导致多位数据不一致问题

检查阶段

Severity: Error   Goal: cdc_verify_struct

修复方法

  • 异步 FIFO: 最推荐方案,使用格雷码指针同步,适合数据流
  • 握手协议: 使用 req/ack 确保数据稳定后再采样
  • 格雷码编码: 如果是计数器,转为格雷码后每次只有1bit变化
  • DMUX同步: 使能信号同步 + MUX 选通稳定数据
Verilog// 正确方式: 格雷码编码后对每个bit分别同步 assign gray_data = data_a ^ (data_a >> 1); genvar i; generate for (i=0; i<N; i=i+1) begin : sync_bits cdc_demet u_sync (.clk(clk_b), .rst_n(rst_b_n), .d(gray_data[i]), .q(gray_sync[i])); end endgenerate

Waiver 条件

  • quasi_static: 多位总线为准静态配置数据,在功能模式下不变化
  • Gray Code: 已使用格雷码编码,相邻值只有1bit变化
Waiver 标签适用场景SVA 支持
Stable Signal;<Enable Condition>多位总线为准静态信号✅ Yes
Gray Code Synchronization已使用格雷码编码❌ No
SGDC# 声明格雷码信号 gray_signals -name "top.u_src.gray_ptr[3:0]" # 准静态多位信号 quasi_static -name "top.u_cfg.mode_reg[7:0]"

数据丢失 / 信号宽度 (Data Loss)

5 条规则

Ac_cdc01 — 快时钟域到慢时钟域信号宽度不足

ERROR cdc_verify
Fast Clock Domain (clk_fast) Slow Clock Domain (clk_slow) F1fast S1 S2 F2 脉冲太窄! ⚠ 脉冲宽度 < clk_slow 周期 → 可能被漏采
clk_fast clk_slow pulse_a 1 fast clk synced_b ✗ 脉冲被漏采! 始终为低 ← pulse 在 clk_slow 两个采样沿之间

问题描述

从快时钟域到慢时钟域传递 脉冲信号 时,如果脉冲宽度小于慢时钟的采样周期,慢时钟域的同步器可能完全采不到这个脉冲。脉冲需要在目的时钟域的至少连续3个偏有效沿期间保持稳定(Three-Edge 要求)。

潜在影响

  • 事件信号(event pulse)被漏采,导致功能逻辑未触发
  • 问题在特定频率比下才出现,增加调试难度

修复方法

  • Toggle 脉冲同步器: 将源脉冲转为电平翻转,目的端再转回脉冲(推荐方案)
  • 脉冲展宽: 在源端将脉冲展宽到满足 three-edge 要求
  • 握手协议: 使用 req/ack 确保信号被采到
Verilog// Toggle-based Pulse Synchronizer (DW_pulse_sync 方案) // 源端:脉冲 → 电平翻转 (toggle) reg toggle_src; always @(posedge clk_fast or negedge rst_n) if (!rst_n) toggle_src <= 1'b0; else toggle_src <= toggle_src ^ pulse_in; // 目的端:电平同步 → 再转脉冲 wire toggle_sync; cdc_demet u_sync (.clk(clk_slow), .d(toggle_src), .q(toggle_sync)); reg toggle_d; always @(posedge clk_slow) toggle_d <= toggle_sync; assign pulse_out = toggle_sync ^ toggle_d; // XOR 检测边沿

Waiver 条件

此规则通常 不建议 waive,除非能从功能上证明:

  • 设计中已做了脉冲展宽但工具未识别(常见情况)
  • 频率比固定且已验证展宽后满足 three-edge
  • 使用 Hybrid CDC (Formal) 验证信号不会丢失
Config# 启用 Hybrid CDC 进行形式化验证 CDC_HYBRID_EN = true # 在 SGDC 中设置时钟周期便于工具分析 set_cdc_clock clk_fast -period 3.9 set_cdc_clock clk_slow -period 10.0

Ac_cdc01a — 信号宽度不足 (数据可能丢失)

ERROR cdc_verify
Ac_cdc01a — Ac_cdc01 的子规则,增加了周期级检查 源信号脉冲 width < T_slow 目的时钟域 可能漏采 → 数据丢失
(波形与 Ac_cdc01 相同,请参考上文) Ac_cdc01a 是 Ac_cdc01 增加了形式化周期检查的子规则

问题描述

Ac_cdc01aAc_cdc01 的子规则,在 Hybrid CDC 模式下通过形式化引擎对信号宽度进行更精确的周期级检查。当启用 CDC_HYBRID_EN=true 和时钟周期约束后,工具会计算源脉冲宽度是否满足目的时钟的采样要求。

与 Ac_cdc01 的区别

  • Ac_cdc01 为结构级检查(基于时钟比率判断)
  • Ac_cdc01a 利用 Formal 引擎验证,精度更高
  • 需要在约束中指定时钟周期 (-period)

修复方法

同 Ac_cdc01,使用脉冲同步器或展宽逻辑。

Waiver 条件

同 Ac_cdc01。如果已做展宽处理但工具仍报错,建议 waive 并确保有对应的 SVA assertion 在 DV 中验证。

Ac_cdc02 — 慢时钟域到快时钟域信号宽度检查

WARNINGcdc_verify
Slow Clock Domain (clk_slow) Fast Clock Domain (clk_fast) F1slow S1 S2 F2 ⚠ 慢→快 信号宽度 > T_fast,通常可被采到
clk_slow clk_fast sig_slow synced_fast ✓ 慢→快:信号宽度足够,可被多次采样

问题描述

从慢时钟域到快时钟域传递信号时,由于快时钟频率更高,信号宽度通常足够被采样。但 SpyGlass 仍会检查此路径,确认同步器结构正确,并在某些边界情况下发出警告。

潜在风险

  • 如果慢时钟信号宽度恰好为1个慢时钟周期,在快时钟域可能只被采到一次
  • 同步器延迟(2个快时钟周期)可能导致信号被延迟采样
  • 如果慢时钟信号是脉冲(非电平),仍需使用脉冲同步器

检查阶段

Severity: Warning   Goal: cdc_verify

修复方法

  • 电平信号: 使用标准 2-FF 同步器,慢→快通常安全
  • 脉冲信号: 即使慢→快,也建议使用 Toggle 脉冲同步器确保可靠性
  • 验证信号宽度: 确认源信号宽度 ≥ 3 × T_fast(满足 three-edge 要求)
Config# 设置时钟周期以便工具精确分析 set_cdc_clock clk_slow -period 20.0 set_cdc_clock clk_fast -period 5.0 # 如果是脉冲信号,使用 Toggle 同步器

Waiver 条件

  • 已确认信号为电平信号(非脉冲),且宽度满足要求
  • 已使用 Toggle 脉冲同步器处理脉冲信号
Waiver 标签适用场景SVA 支持
Stable Signal;<Enable Condition>信号为电平信号,宽度足够✅ Yes
Toggle Synchronization已使用 Toggle 脉冲同步器❌ No

Ac_cdc03 — 多bit信号跨时钟域同步不完整

ERRORcdc_verify_struct
Domain A (clk_a) Domain B (clk_b) D[0] D[1] D[n] S1 S2 S1only ✗ D[1..n] 同步级数不足
各bit同步级数不同 → 到达目的域的时序不一致 → 采到中间值

问题描述

多bit总线中,不同bit经过了不同级数的同步器(如 D[0] 经过2级同步,D[1..n] 只经过1级同步)。这导致各bit到达目的时钟域的时序不一致,目的端可能采到不一致的中间状态。

与 Ac_unsync03 的区别

  • Ac_unsync03: 多bit中只有部分bit有同步器,其余bit完全没有同步
  • Ac_cdc03: 多bit都有同步器,但同步级数不同(如1级 vs 2级)
  • 两者都会导致多bit数据不一致,但 Ac_cdc03 的风险相对较低

检查阶段

Severity: Error   Goal: cdc_verify_struct

修复方法

  • 统一同步级数: 确保所有bit都经过相同级数(至少2级)的同步器
  • 使用异步 FIFO: 对于数据总线,使用异步 FIFO 是最安全的方案
  • 格雷码编码: 对计数器类信号使用格雷码,确保相邻值只有1bit变化
Verilog// 确保所有bit使用相同的2级同步器 genvar i; generate for (i=0; i<WIDTH; i=i+1) begin : gen_sync // 每个bit都使用标准2-FF同步器 cdc_demet u_sync ( .clk(clk_b), .rst_n(rst_b_n), .d(data_a[i]), .q(data_b_sync[i]) ); end endgenerate

Waiver 条件

  • 已使用格雷码编码,相邻值只有1bit变化,1级同步器也可接受
  • 信号为准静态,不需要严格的多bit一致性
Waiver 标签适用场景SVA 支持
Gray Code Synchronization已使用格雷码编码❌ No
Stable Signal;<Enable Condition>准静态信号✅ Yes

Ac_cdc04 — 信号被多个目的时钟域使用但只同步到其中一个

ERRORcdc_verify_struct
Domain A Domain B (clk_b) Domain C (clk_c) Domain D (clk_d) SRC 2FF DST_B 2FF DST_C DST_D ✗ 无同步器 Domain D 未同步!
信号扇出到多个时钟域,部分域有同步器,部分域没有 → 未同步域存在亚稳态风险

问题描述

源时钟域 A 的信号扇出到多个目的时钟域(B、C、D),其中 Domain B 和 C 有正确的同步器,但 Domain D没有同步器。SpyGlass 会对每个未同步的目的域分别报告此规则。

常见场景

  • 设计中新增了一个时钟域,但忘记为该域添加同步器
  • 信号通过 assign 语句直接连接到多个模块,部分模块在不同时钟域
  • 顶层连线时误将信号直接连接到不同时钟域的端口

检查阶段

Severity: Error   Goal: cdc_verify_struct

修复方法

  • 为每个目的时钟域添加独立的同步器: 每个时钟域需要自己的 2-FF 同步器
  • 不要共用同步器输出: 不同时钟域的同步器不能共享,每个域需要独立实例
Verilog// 为每个目的时钟域添加独立同步器 // Domain B 的同步器 cdc_demet u_sync_b (.clk(clk_b), .rst_n(rst_b_n), .d(sig_a), .q(sig_b)); // Domain C 的同步器(独立实例) cdc_demet u_sync_c (.clk(clk_c), .rst_n(rst_c_n), .d(sig_a), .q(sig_c)); // Domain D 的同步器(不能省略!) cdc_demet u_sync_d (.clk(clk_d), .rst_n(rst_d_n), .d(sig_a), .q(sig_d));

Waiver 条件

  • 某个目的域在信号跨越时处于关闭状态(Clock Off)
  • 某个目的域不使用该信号的值(Receiver Ignore)
  • 信号为准静态信号(quasi_static)
Waiver 标签适用场景SVA 支持
Stable Signal Clock Off;<Enable>目的时钟域关闭时信号跨越✅ Yes
Stable Signal Receiver Ignore目的端不使用该信号✅ Yes
SGDC# 声明某个目的域不使用该信号 set_cdc_waiver -scheme unsynchronized -from {top.u_src.sig_a} -to {top.u_dst_d.reg_d} -comment "Stable Signal Receiver Ignore;Domain D does not use this signal"
📌

数据保持 (Data Hold Issues)

2 条规则

Ac_datahold01a — 数据在使能有效期间发生变化

WARNING cdc_verify
Domain A (clk_a) Domain B (clk_b) DATA EN S1 S2 MUX D_OUT ⚠ 数据在EN有效时变化!
clk_b ↑ en_sync data_a DATA_A DATA_B (变化!) sampled DATA_A or DATA_B ? ⚠ EN有效期间data变化 → 采样值不确定

问题描述

在数据同步 (Data Synchronization) 结构中,当同步后的使能信号 en_sync 有效时,源端数据 data_a 发生了变化。此时目的端寄存器可能采到数据跳变的中间状态,导致数据不正确。

正确行为应为

  • 先稳定数据 → 再拉高使能
  • 使能有效期间,数据必须保持不变
  • 数据被采样后 → 才能改变数据或拉低使能

修复方法

  • 源端逻辑保证: 确保数据在使能拉高前已稳定,使能期间不改变数据
  • 握手协议: 使用 req/ack 握手确保数据稳定后再通知目的端采样
  • 异步 FIFO: 如果数据变化频繁,使用异步 FIFO 解耦
Verilog// 正确的时序: 先稳定数据,再拉高使能 always @(posedge clk_a) begin case (state) IDLE: begin data_out <= new_data; // 先锁存数据 state <= WAIT; end WAIT: begin en_out <= 1'b1; // 数据稳定后拉高使能 state <= HOLD; end HOLD: if (ack_sync) en_out <= 1'b0; // 收到确认后释放使能 endcase end

Waiver 条件

  • 功能上保证在使能有效时数据不会变化
  • 数据路径有其他保护机制(如 FIFO empty 信号保护)
  • 缺少复位信号导致的误报(检查 setup 约束)
可能原因解决方法
缺少 reset 约束补充 reset 定义到 SGDC
setup 流程不完整检查 cdc_setup 结果
功能上数据确实稳定添加 SVA assertion 验证

Ac_datahold01 — 数据保持基础规则(使能无效时数据变化)

WARNINGcdc_verify_struct
Domain A (clk_a) Domain B (clk_b) DATA EN S1 S2 MUX D_OUT ⚠ EN无效时DATA仍在变化 结构上存在数据保持风险(功能上可能正确)
clk_b ↑ en_sync data_a V1 V2(变!) V3 V4 (EN有效期间稳定) sampled V4 ✓ EN无效时DATA变化 → 结构级警告(功能上可能正确)

问题描述

Ac_datahold01Ac_datahold01a 的基础规则,在结构级检查中发现数据信号在使能信号无效期间发生了变化。与 Ac_datahold01a 不同,此规则检测的是使能无效时的数据变化,功能上可能是正确的。

与 Ac_datahold01a 的区别

  • Ac_datahold01a: 使能有效期间数据变化(更严重,ERROR 级别)
  • Ac_datahold01: 使能无效期间数据变化(结构级警告,WARNING 级别)
  • Ac_datahold01 通常是 WARNING 级别,功能上可能正确

检查阶段

Severity: Warning   Goal: cdc_verify_struct

修复方法

  • 确认功能正确性: 验证在使能有效时数据确实稳定
  • 添加 SVA 断言: 在 DV 中验证数据保持时序
  • 握手协议: 使用 req/ack 确保数据稳定后再传使能
SVA// SVA 断言: 验证 EN 有效时 DATA 稳定 property data_stable_when_en; @(posedge clk_b) en_sync |-> $stable(data_a); endproperty assert_data_hold: assert property(data_stable_when_en) else $error("Data changed while enable is active!");

Waiver 条件

  • 功能上已验证使能有效时数据稳定(EN无效时变化不影响采样)
  • 已添加 SVA 断言在 DV 中验证
Waiver 标签适用场景SVA 支持
Stable Signal;<Enable Condition>功能上保证EN有效时数据稳定✅ Yes
SGDC# TCL Waiver set_cdc_waiver -scheme data_hold \ -from {top.u_src.data_out[*]} \ -to {top.u_dst.data_reg[*]} \ -comment "Stable Signal;data stable when en_sync is high, verified by SVA"
🔀

收敛性问题 (Convergence Issues)

4 条规则

Ac_conv01 — 同步信号经不同级数寄存器后收敛

WARNING cdc_verify_struct
Domain A Domain B X sync sync R1 Y sync sync R1 R2 AND X: sync+1级 Y: sync+2级 ⚠ 延迟不一致!
X_synced Y_synced AND out skew! X 和 Y 之间存在1周期偏移 → 输出可能出现毛刺

问题描述

两个来自同一源时钟域 A 的信号 X 和 Y,分别通过各自的同步器进入时钟域 B 后,经过不同级数的寄存器(X 经过1级,Y 经过2级),最后在一个逻辑门处收敛。由于额外寄存器引入的延迟,两个信号可能出现时序偏移 (skew),导致输出短暂出现错误值。

示例

假设源端 X=0,Y=0 同时变为 X=1,Y=1。由于 Y 多经过一级寄存器,在某个周期可能出现 X=1,Y=0 的状态,AND 门输出短暂为 0(应该为 1)。

修复方法

  • 确保收敛信号经过相同级数的寄存器
  • 使用格雷码 (Gray Code) 编码,确保相邻值只有1bit变化
  • 使用单一同步机制(如异步 FIFO)传递相关多bit信号
  • 如果信号不相关,使用 cdc_filter_coherency 约束

Waiver 条件

  • 两个信号功能上不相关(如独立的中断信号)
  • 两个信号不会同时跳变(如互斥信号)
SGDC# 声明信号不相关 cdc_filter_coherency -unrelated sig_x sig_y # 声明格雷码信号 gray_signals -name gray_ptr[3:0]

Ac_conv02 — 同步信号在寄存器前收敛

WARNING cdc_verify_struct
Dom A Domain B D[0] D[1] 2FF 2FF LOGIC REG ⚠ 同步后直接收敛,无对齐寄存器
波形类似 Ac_conv01,各bit同步后存在1周期偏移

问题描述

多bit信号各自通过独立的同步器到达目的时钟域后,在寄存器之前的组合逻辑处直接收敛。由于各bit通过同步器的延迟可能不同,收敛处可能出现短暂的错误组合值。

典型场景:二进制计数器值 011→100 跨时钟域,各bit独立同步后可能出现 111、110 等中间值。

解决思路

使用格雷码编码,确保相邻值只有1bit变化,即使有偏移也不会产生错误值。

修复方法

  • 将二进制编码转为格雷码后再同步
  • 使用异步 FIFO 传递多bit数据
Verilog// 二进制转格雷码 assign gray_ptr = bin_ptr ^ (bin_ptr >> 1); // 同步格雷码指针 always @(posedge clk_b) begin gray_sync1 <= gray_ptr; gray_sync2 <= gray_sync1; end

Waiver 条件

同 Ac_conv01。使用 cdc_filter_coherencygray_signals 约束。

Ac_conv03 — 不同域信号经同步器后收敛

WARNING cdc_verify_struct
Dom A Dom C Domain B X Y 2FF sync 2FF sync GATE ⚠ 不同源域信号收敛,相位关系不确定
不同源域信号同步后时序关系不保证

问题描述

来自不同源时钟域(Domain A 和 Domain C)的信号,分别通过各自的同步器同步到 Domain B 后,在下游逻辑处收敛。由于两个源域与目的域的相位关系完全独立,同步后信号之间的时序关系不可预测

修复方法

  • 避免不同域信号在收敛处产生数据依赖
  • 使用独立的控制逻辑分别处理

Waiver 条件

如果两个信号确实功能独立(如来自不同外设的中断),可使用 cdc_filter_coherency -unrelated 约束。

Ac_conv04 — 同步信号在目的域收敛后再次跨域

WARNINGcdc_verify_struct
Domain A Domain B Domain C X Y 2FF 2FF LOGIC REG_B 2FF 2FF REG_C 再次跨域! ⚠ 需要重新同步到 Domain C
Domain B 中收敛的信号再次跨域到 Domain C,需要重新同步

问题描述

来自 Domain A 的信号 X 和 Y,分别同步到 Domain B 后在 Domain B 中收敛,然后再次跨越到 Domain C。此时 Domain B 中的收敛结果对于 Domain C 来说是一个新的 CDC 路径,需要重新同步。

潜在影响

  • Domain B 中的收敛信号可能存在时序偏移(来自 Ac_conv01/02 问题)
  • 如果 Domain B 中的收敛问题未解决,再次跨域会将问题传播到 Domain C
  • 多级跨域增加了调试难度

检查阶段

Severity: Warning   Goal: cdc_verify_struct

修复方法

  • 先解决 Domain B 中的收敛问题: 确保 Ac_conv01/02 已修复
  • 在 Domain B 中寄存收敛结果: 确保跨域到 Domain C 的信号来自寄存器
  • 在 Domain C 中添加同步器: 对从 Domain B 到 Domain C 的信号添加 2-FF 同步器
Verilog// 在 Domain B 中寄存收敛结果 reg conv_result_b; always @(posedge clk_b) conv_result_b <= x_synced & y_synced; // 寄存收敛结果 // 然后对 conv_result_b 做 2-FF 同步到 Domain C cdc_demet u_sync_c ( .clk(clk_c), .rst_n(rst_c_n), .d(conv_result_b), .q(conv_result_c) );

Waiver 条件

  • Domain B 中的收敛问题已通过 cdc_filter_coherency 约束处理
  • 信号在 Domain B 中已经过寄存,跨域到 Domain C 的是干净的寄存器输出
SGDC# 声明 Domain B 中的收敛信号已处理 cdc_filter_coherency -unrelated sig_x sig_y
💥

毛刺问题 (Glitch Issues)

3 条规则

Ac_glitch01 — CDC路径上存在组合逻辑(可能产生毛刺)

ERROR cdc_verify_struct
Domain A Domain B F1 F2 组合 逻辑 sync sync ⚠ 组合逻辑输出有毛刺风险
combo_out glitch! clk_b ↑ synced_b clk_b 采样沿恰好采到毛刺 → 错误传播

问题描述

CDC 路径的源端在寄存器输出之后、同步器输入之前存在组合逻辑。组合逻辑由于路径延时差异可能产生毛刺 (Glitch),毛刺可能被目的时钟域的同步器采样到,导致错误的数据传播。

修复方法

在跨时钟域之前用寄存器打一拍,消除组合逻辑输出的毛刺。确保送入同步器的信号直接来自寄存器的 Q 端。

Verilog// 修复: 组合逻辑输出先寄存再跨时钟域 reg combo_reg; always @(posedge clk_a) combo_reg <= (f1_q & f2_q); // 寄存器消除毛刺 // 然后用寄存器输出作为同步器输入 cdc_demet u_sync (.clk(clk_b), .d(combo_reg), .q(synced_b));

Waiver 条件

Waiver 标签适用场景SVA
Stable Combo Active Path所有输入在采样窗口内不同时变化
Stable Combo Muxed PathMUX选择线稳定,只有一个活跃路径
Combo Logic Interrupts组合逻辑在不活跃路径上

Ac_glitch02 — 同步器输出驱动组合逻辑后再跨时钟域

ERRORcdc_verify_struct
Domain A Domain B (已同步) Domain C SRC S1 S2 组合 逻辑 S1_C S2_C 毛刺! ⚠ 同步器输出经组合逻辑后再跨域 → 毛刺传播
S2_out combo_out glitch! clk_c ↑ synced_c clk_c 采到毛刺 → 错误传播到 Domain C

问题描述

信号从 Domain A 同步到 Domain B 后,Domain B 中的同步器输出经过组合逻辑处理,然后该组合逻辑的输出再次跨越到 Domain C。组合逻辑可能产生毛刺,这些毛刺会被 Domain C 的同步器采样到,导致错误传播。

与 Ac_glitch01 的区别

  • Ac_glitch01: 组合逻辑在 CDC 路径的源端(Domain A 内)
  • Ac_glitch02: 组合逻辑在已同步的信号之后,且该组合逻辑输出再次跨域
  • Ac_glitch02 涉及多个时钟域,问题更复杂

检查阶段

Severity: Error   Goal: cdc_verify_struct

修复方法

  • 在 Domain B 中寄存组合逻辑输出: 在跨域到 Domain C 之前,用 Domain B 的时钟打一拍
  • 消除不必要的组合逻辑: 如果可能,将组合逻辑移到 Domain C 内部
  • 使用 Domain B 的寄存器输出作为 CDC 源: 确保跨域信号来自寄存器 Q 端
Verilog// 修复: 在 Domain B 中寄存组合逻辑输出 reg combo_reg_b; always @(posedge clk_b) combo_reg_b <= s2_out & local_sig_b; // 寄存器消除毛刺 // 然后用寄存器输出跨域到 Domain C cdc_demet u_sync_c ( .clk(clk_c), .rst_n(rst_c_n), .d(combo_reg_b), .q(synced_c) );

Waiver 条件

Waiver 标签适用场景SVA
Stable Combo Active Path所有输入在采样窗口内不同时变化
Stable Combo Muxed PathMUX选择线稳定,只有一个活跃路径

Ac_glitch03 — 再聚合组合逻辑产生毛刺

ERROR cdc_verify_struct
Domain B (跨时钟域信号进入后) CDC Combo A Combo B GATE ⚠ 信号分叉后再聚合 → 竞争冒险
信号经不同延迟路径再聚合 → 产生毛刺 (Hazard)

问题描述

跨时钟域信号进入目的时钟域后,信号分叉经过不同的组合逻辑路径,然后再次聚合到同一个逻辑门。由于不同路径的延时差异,会产生竞争冒险 (Race Hazard),输出出现毛刺。

修复方法

  • 在源端将组合逻辑输出用寄存器打拍后再跨时钟域
  • 消除再聚合路径上的组合逻辑

Waiver 条件

同 Ac_glitch01,使用 Stable Combo Active PathStable Combo Muxed Path 标签。Waive 时需要选中所有源路径。

🔄

复位同步 (Reset Synchronization)

4 条规则

Ar_unsync01 — 复位信号跨时钟域未同步

ERROR cdc_verify_struct
Reset Source Domain B RST_SRC FF (rst) ✗ 复位直连 异步复位释放可能引起亚稳态
异步复位释放时,若接近 clk_b 有效沿 → recovery/removal 违例

问题描述

异步复位信号从一个时钟域直接连接到另一个时钟域的寄存器异步复位端口。虽然复位断言 (assert) 通常是安全的(立即复位),但复位释放 (deassert) 如果发生在目的时钟边沿附近,会引起 recovery/removal time 违例,导致亚稳态。

修复方法: 异步断言、同步释放 (Async Assert, Sync Deassert)

使用复位同步器,确保复位可以立即断言(异步),但释放时同步到目的时钟域。

Verilog// 复位同步器: 异步断言, 同步释放 reg [1:0] rst_sync; always @(posedge clk_b or negedge rst_async_n) begin if (!rst_async_n) rst_sync <= 2'b00; // 异步断言 (立即复位) else rst_sync <= {rst_sync[0], 1'b1}; // 同步释放 end assign rst_b_n = rst_sync[1]; // 同步后的复位信号

Waiver 条件

标签场景SVA
Clock Off Reset复位时目的时钟关闭

Ar_asyncdeassert01 — 异步复位未同步释放

ERROR clock_reset_integrity
Domain B FF rst_n (async) ✗ rst_n 直接连接 FF 异步复位端 释放时机不可控 → recovery time 违例
复位释放若靠近时钟上升沿 → 部分FF退出复位,部分未退出

问题描述

异步复位信号可以异步地断言(使设计进入复位),但必须同步地释放。如果异步释放发生在时钟有效沿附近,不同寄存器可能在不同周期退出复位,导致逻辑状态不一致。

修复方法

同 Ar_unsync01,使用异步断言同步释放的复位同步器。

Waiver 条件

仅当复位释放时时钟确实关闭,可使用 Clock Off Reset 标签。

Reset_sync01 — 复位路径上存在组合逻辑

WARNING clock_reset_integrity
Reset Path RST COMBO FF(rst) ⚠ 复位路径上的组合逻辑可能产生毛刺
复位路径上的毛刺可能导致意外复位/释放

问题描述

复位信号路径上存在组合逻辑,组合逻辑的竞争冒险可能在复位线上产生毛刺,导致设计意外进入或退出复位状态。

修复方法

  • 确保复位树是干净的,避免在复位路径上放置组合逻辑
  • 如果必须用门控复位,使用无毛刺的 glitch-free 结构

Waiver 条件

如果组合逻辑的所有输入在复位期间都是稳定的,可以 waive。需要提供功能验证证据。

Ar_sync01 — 复位同步器结构不符合要求

WARNINGclock_reset_integrity
Domain B (clk_b) rst_n S1 only clk_b FF clk_b ⚠ 复位同步器只有1级 → MTBF 不足,复位释放可能引起亚稳态
单级复位同步器无法充分消除复位释放时的亚稳态

问题描述

SpyGlass 检测到复位同步器的结构不符合要求,例如:

  • 只有1级寄存器(单级复位同步器),无法充分消除复位释放时的亚稳态
  • 复位同步器的寄存器之间存在组合逻辑
  • 复位同步器的寄存器没有使用异步复位端口

标准复位同步器要求

  • 至少2级寄存器(推荐3级用于高频设计)
  • 每级寄存器的异步复位端口连接到原始复位信号
  • 每级寄存器的 D 端:第一级接 VCC(1'b1),后续级接前一级 Q 端

检查阶段

Severity: Warning   Goal: clock_reset_integrity

修复方法:使用标准复位同步器

使用异步断言、同步释放的标准复位同步器,确保至少2级寄存器。

Verilog// 标准复位同步器: 异步断言, 同步释放, 2级 module rst_sync_2ff ( input clk, rst_async_n, output rst_sync_n ); reg [1:0] sync_ff; // 防止综合工具优化 (* dont_touch = "true" *) always @(posedge clk or negedge rst_async_n) if (!rst_async_n) sync_ff <= 2'b00; // 异步断言 else sync_ff <= {sync_ff[0], 1'b1}; // 同步释放 assign rst_sync_n = sync_ff[1]; endmodule

Waiver 条件

  • 已使用标准复位同步器单元但工具未识别(需要在 SGDC 中声明)
  • 复位信号为全局同步复位,不需要异步复位同步器
SGDC# 声明复位同步器 reset_sync -name "top.u_rst_sync.sync_ff[1]" -clock clk_b -stages 2
🕐

时钟问题 (Clock Issues)

3 条规则

Clock_glitch01 — 时钟使能路径上存在组合逻辑(时钟使能毛刺)

WARNINGclock_reset_integrity
Clock Enable Path CLK EN_A EN_B 组合 逻辑 ICG latch+AND GCLK ⚠ 使能信号经组合逻辑后进入 ICG → 使能毛刺可能导致时钟毛刺
EN_A EN_B EN_combo glitch! EN_A 和 EN_B 同时变化 → 组合逻辑产生毛刺 → 进入 ICG 可能产生时钟毛刺

问题描述

时钟使能信号(Clock Enable)在进入 ICG(集成时钟门控单元)之前经过了组合逻辑。组合逻辑的竞争冒险可能在使能信号上产生毛刺,这个毛刺进入 ICG 后可能导致时钟使能毛刺,进而产生时钟毛刺。

与 Clock_glitch02 的区别

  • Clock_glitch02: 组合逻辑直接在时钟路径上(时钟信号本身有毛刺)
  • Clock_glitch01: 组合逻辑在时钟使能路径上(使能信号有毛刺,可能传入 ICG)
  • Clock_glitch01 的风险相对较低,但仍需关注

检查阶段

Severity: Warning   Goal: clock_reset_integrity

修复方法

  • 寄存使能信号: 在组合逻辑输出后用寄存器打一拍,消除毛刺后再送入 ICG
  • 确保使能信号在时钟低电平期间稳定: ICG 要求使能信号在时钟低电平期间满足 setup/hold
  • 简化使能逻辑: 避免在使能路径上使用复杂的组合逻辑
Verilog// 修复: 寄存使能信号后再送入 ICG reg en_reg; always @(posedge clk) en_reg <= en_a & en_b; // 寄存器消除组合逻辑毛刺 // 使用寄存后的使能信号驱动 ICG CKLNQD1 u_icg (.TE(scan_en), .E(en_reg), .CP(clk), .Q(gated_clk));

Waiver 条件

  • 使能信号的所有输入在时钟低电平期间不同时变化(功能上保证无毛刺)
  • 已通过形式化验证确认使能信号稳定
SGDC# 声明使能信号稳定 set_cdc_waiver -scheme clock_enable_glitch -from {top.u_clk_ctrl.en_combo} -comment "Stable Combo Active Path;EN_A and EN_B do not change simultaneously"

Clock_glitch02 — 时钟路径上存在组合逻辑(时钟毛刺)

ERROR clock_reset_integrity
Clock Path CLK AND/OR FF (clk) ⚠ 时钟路径上的门控逻辑 → 可能产生时钟毛刺
CLK_in Gated CLK ↑ glitch 时钟毛刺导致意外时钟边沿 → 寄存器误触发

问题描述

时钟路径上存在组合逻辑(如 AND、OR 门),这些逻辑的延时差异可能在时钟信号上产生毛刺 (Glitch)。时钟毛刺会被下游寄存器当作有效时钟边沿,导致数据被错误锁存。

修复方法

  • 使用标准库提供的 ICG (Integrated Clock Gating) 单元,而不是手工门控
  • ICG 内部使用 latch + AND 结构,确保无毛刺时钟门控
  • 对于时钟 MUX,使用 glitch-free clock MUX 结构
Verilog// ✗ 错误: 直接用 AND 门控时钟 assign gated_clk = clk & enable; // 有毛刺风险! // ✓ 正确: 使用 ICG 单元 CKLNQD1 u_icg (.TE(scan_en), .E(enable), .CP(clk), .Q(gated_clk));

Waiver 条件

时钟路径上的毛刺问题通常不建议 waive。必须使用正确的 ICG 单元或 glitch-free MUX。

Clock_converge01 — 时钟信号再聚合

WARNING clock_reset_integrity
CLK_A CLK_B MUX FF ⚠ 时钟选择 MUX 需要 glitch-free 设计
时钟切换时可能产生短脉冲或毛刺

问题描述

多个时钟源在 MUX 或其他逻辑处聚合,形成一条时钟路径。时钟切换过程中如果不使用 glitch-free 结构,可能产生短脉冲或毛刺。

修复方法

使用 Glitch-Free Clock MUX:先停止两个时钟,切换选择,再启动新时钟。或使用标准库提供的时钟切换单元。

Waiver 条件

如果使用了 set_case_analysis 固定选择信号(表示只有一种时钟活跃),可以 waive。

同步方案参考 (Synchronization Schemes)

6 种方案

🔹 二级同步器 (2-FF Synchronizer)

适用于 单bit电平信号 (Level Signal) 的跨时钟域同步。信号需在源端保持稳定至少 2~3 个目的时钟周期。

电路拓扑

Dom A Domain B SRC S1 S2 DST 2-FF Synchronizer

Verilog 代码

Verilog// cdc_demet: 2-FF 同步器 module cdc_demet ( input clk, rst_n, d, output q ); reg [1:0] sync; always @(posedge clk or negedge rst_n) if (!rst_n) sync <= 2'b0; else sync <= {sync[0], d}; assign q = sync[1]; endmodule

解决规则: Ac_unsync01, Ac_sync01

🔹 脉冲同步器 (Toggle-based Pulse Synchronizer)

适用于 单bit脉冲/事件信号 (Event Signal)。源端将脉冲转为电平翻转 (toggle),目的端通过 XOR 检测边沿还原脉冲。

电路拓扑

Domain A (Source) Domain B (Destination) Toggle pulse_in S1 S2 DLY pulse_out Toggle → 2FF Sync → XOR 还原脉冲

Verilog 代码

Verilog// DW_pulse_sync 方案 reg toggle_src, toggle_d; wire toggle_sync; // 源端: pulse → toggle always @(posedge clk_a) toggle_src <= toggle_src ^ pulse_in; // 2-FF 同步 toggle 信号 cdc_demet u_sync ( .clk(clk_b), .d(toggle_src), .q(toggle_sync)); // 目的端: toggle → pulse always @(posedge clk_b) toggle_d <= toggle_sync; assign pulse_out = toggle_sync ^ toggle_d;

解决规则: Ac_cdc01, Ac_cdc01a

🔹 MUX 同步方案 (DMUX Synchronization)

适用于 多bit数据信号。使能信号通过 2-FF 同步,数据通过 MUX 选通。使能有效时数据必须稳定。

电路拓扑

Dom A Domain B EN DATA S1 S2 M OUT

关键要求

  • 数据必须在 EN 拉高前稳定
  • EN 有效期间数据不能变化
  • EN 通过 2-FF 同步到目的域
  • 同步后的 EN 控制 MUX/寄存器使能

解决规则: Ac_unsync02, Ac_datahold01a

🔹 握手同步 (Handshake Synchronization)

适用于 需要双向确认的数据传输。源端发送 REQ,目的端确认后回 ACK,确保数据被安全采样。延迟较大但最安全。

协议流程

Source (clk_a) Destination (clk_b) ① 稳定 DATA ② 拉高 REQ ③ 同步 REQ → 采 DATA ④ 拉高 ACK ⑤ 同步 ACK → 拉低 REQ ⑥ 检测 REQ↓ → 拉低 ACK

特点

  • 需要 2 次 2-FF 同步(REQ + ACK)
  • 延迟约 4~6 个时钟周期
  • 吞吐量低但可靠性最高
  • 保证数据不会丢失

解决规则: Ac_unsync01/02, Ac_cdc01, Ac_datahold01a

🔹 异步 FIFO (Async FIFO with Gray Code Pointers)

适用于 高吞吐量多bit数据流 传输。使用格雷码编码的读写指针进行跨时钟域同步。

架构示意

Write (clk_w) Dual-Port RAM Read (clk_r) wr_ptr (gray) rd_ptr (gray) 2-FF sync 2-FF sync full判断 empty判断

关键设计点

  • 格雷码指针: 相邻值只有1bit变化,避免多bit同步问题
  • Dual-Port RAM: 写端口用 clk_w,读端口用 clk_r
  • Full/Empty 判断: 在各自时钟域内比较同步后的对方指针
  • 深度: 需要 2^N 深度以适配格雷码

解决规则: Ac_unsync02, Ac_conv02 (gray code)

🔹 复位同步器 (Async Assert, Sync Deassert)

适用于 异步复位信号 的跨时钟域同步。确保复位可以立即生效(异步断言),但释放时同步到目的时钟(同步释放)。

电路拓扑

Destination Domain (clk_b) rst_n (async) S1 rst_n↓ S2 rst_n↓ VCC rst_sync_n 异步断言 (立即) + 同步释放 (安全)

Verilog 代码

Verilog// 异步断言,同步释放 reg [1:0] rst_sync; always @(posedge clk_b or negedge rst_n) if (!rst_n) rst_sync <= 2'b00; else rst_sync <= {rst_sync[0], 1'b1}; assign rst_sync_n = rst_sync[1];

解决规则: Ar_unsync01, Ar_asyncdeassert01

📋

CDC 方法学流程 (Methodology)

SpyGlass CDC 检查流程

cdc_setup cdc_setup_check clock_reset_integrity cdc_verify cdc_verify_struct

推荐处理顺序

  • cdc_setup: 指定时钟、复位、黑盒约束,生成 autoclock/autoreset
  • cdc_setup_check: 验证约束完整性,必须修复所有 Fatal/Error
  • clock_reset_integrity: 检查时钟和复位树完整性,修复 glitch 和 race
  • cdc_verify: Block 级 CDC 验证(信号宽度、数据保持等功能性检查)
  • cdc_verify_struct: 结构级 CDC 验证(未同步、收敛、毛刺等)

Violation 处理优先级

  • 🔴 Ac_unsync01/02: 最高优先级,先解决未同步问题
  • 🔴 Ar_*/Reset_*: 复位同步问题
  • 🟠 Ac_conv*: 收敛性问题
  • 🟠 Ac_glitch*: 毛刺问题
  • 🟡 Ac_cdc01*: 信号宽度问题
  • 🟡 Ac_datahold*: 数据保持问题