1. 引言:为什么CDC检查里,聚合和毛刺是“隐形杀手”?
大家好,我是老张,在芯片设计这行摸爬滚打了十几年,用Spyglass做CDC检查的次数,两只手都数不过来。今天想和大家深入聊聊CDC检查里两个最让人头疼,也最容易埋下“定时炸弹”的问题:信号聚合和组合逻辑毛刺。
很多刚接触CDC验证的朋友,可能更关注那些明显的“硬伤”,比如信号没做同步(AC_unsync01/02)。这些规则报出来,问题一目了然,改起来方向也明确。但真正考验功力的,往往是那些通过了基础同步检查,却在聚合(Convergence)和毛刺(Glitch)规则上报出的违例。这些问题非常隐蔽,仿真时可能跑几百万个向量都发现不了,但芯片一上电,在某个特定的温度和电压下,它就可能突然发作,导致数据错乱、功能异常,让你查问题查到怀疑人生。
为什么这么说呢?因为这两个问题直接关联到跨时钟域传输的终极目标:数据一致性。你辛辛苦苦做了同步,确保信号能稳定地被目标时钟域捕获,避免亚稳态传播。但如果多个同步后的信号在“汇合”时出了岔子,或者同步前的组合逻辑产生了毛刺并被采到,那么你最终得到的数据,很可能已经不是源端想发送的那个数据了。这就好比用可靠的快递(同步器)把几份文件(多bit信号)从A地送到B地,每份文件都完好无损地到了,但你在B地组装时发现页码对不上(聚合问题),或者文件在打包前就被咖啡渍污染了一角(毛刺问题),最终的信息还是错的。
接下来的内容,我会结合我实际项目中踩过的坑,带大家把Spyglass里关于聚合的AC_conv系列规则和关于毛刺的AC_glitch03规则掰开揉碎了讲。我们不光要明白工具为什么报违例,更要掌握一套从分析、判断到修复的实战方法。我会给出具体的RTL代码例子、约束脚本怎么写,以及最终的设计修改方案。目标就一个:让你下次再看到这些违例时,心里有底,手上有招。
2. 深入骨髓:理解AC_conv聚合违例的三种“面相”
Spyglass的CDC检查里,AC_conv01、02、03这三条规则都盯着“聚合”问题,但角度各有不同。很多人一看报告密密麻麻就头疼,其实只要抓住核心,它们很好区分。
2.1 AC_conv01:同步后路径延时不同导致的“错拍”聚合
这是最常见的一种聚合问题。我们来看一个我早期项目里真实犯过的错误简化后的代码:
// 时钟域 clk_a -> clk_b
module convergence_issue (
input wire clk_a,
input wire clk_b,
input wire rst_n,
input wire [1:0] data_a,
output reg result_b
);
// 在clk_b域对两个bit分别进行两级同步
reg [1:0] sync_stage1, sync_stage2;
reg data_b_bit0, data_b_bit1;
reg data_b_bit0_dly1; // 多打了一拍!
always @(posedge clk_b or negedge rst_n) begin
if (!rst_n) begin
sync_stage1 <= 2'b0;
sync_stage2 <= 2'b0;
data_b_bit0 <= 1'b0;
data_b_bit1 <= 1'b0;
data_b_bit0_dly1 <= 1'b0;
end else begin
// 第一级同步
sync_stage1 <= data_a;
// 第二级同步
sync_stage2 <= sync_stage1;
// 将同步后的bit0和bit1取出,但bit0额外经过一个寄存器
data_b_bit0 <= sync_stage2[0];
data_b_bit1 <= sync_stage2[1];
data_b_bit0_dly1 <= data_b_bit0; // 这里给bit0多加了一级寄存器
end
end
// 问题点:聚合时,两个bit经历的寄存器数量不同!
always @(posedge clk_b or negedge rst_n) begin
if (!rst_n)
result_b <= 1'b0;
else
// bit1用的是当前拍的值,bit0用的是一拍前的值!
result_b <= data_b_bit1 & data_b_bit0_dly1;
end
endmodule
上面这个例子,就是典型的AC_conv01违例场景。data_a[1:0]这两个bit从clk_a域同步到clk_b域,都经过了规范的两级同步器(sync_stage1和sync_stage2)。但是,在clk_b域进行后续处理时,设计者不小心(或者出于某种逻辑考虑)让bit0又多经过了一级寄存器(data_b_bit0_dly1),而bit1没有。
这样一来,当data_a从2‘b00跳变到2’b11时,理想情况下,我们希望data_b_bit1和data_b_b

171

被折叠的 条评论
为什么被折叠?



