第一章 :时钟不定态检查
? ? ? 为什么要进行时钟不定态检查,像一些时钟设计中,比如有些时钟来自PAD输入,像i2c,i2s,spi这些串行接口,当作为slave时,时钟都来自芯片外部的master,甚至经过一些pinmux复用逻辑,然后才接到clk_gen模块进行时钟管理,那么从顶层到clk_gen之间的链路,很可能会引入一些意想不到的连接错误,或者数据线与时钟线接反等等,这些在我们实际工作中是经常遇到的,为此,我们添加了这个不定态的检查,因为很多时候来自PAD的信号一旦呈现高阻态,那么接入到内部的信号呈现不定态,因此利用这个checker可以很容易的发现一些bug。就像前面几个章节提到的那样,有些RTL设计缺陷是我们始料未及的,有笔误,有考虑不到的等等,总之,在实际应用中我们仍需要不断更新添加新的自动化checker来应对各种各样的问题。
? ? 所谓时钟不定态,就是时钟信号呈现一个不确定的状态,如何从EDA仿真波形上看,显示的红色的,既不是逻辑0电平也不是逻辑1电平。类似的,信号不定态也是如此。
?为了提高此自动化checker的阅读性和继承性,我们将最底层的设计进行了模块化管理,如下:
module clk_x_state_chk(
input wire ref_clk ,
input wire chk_en ,
input logic clk ,
input wire[31:0] case_num ,
input wire report_err
);
property p_check;
@(posedge ref_clk) disable iff(!chk_en) not($isunknown)(clk));
endproperty
a_check: assert property(p_check);
else begin
if(report_err)begin
err_num++;
end
end
c_check: cover property(p_check);
endmodule
ref_clk为自动化checker的采样时钟,这个可以来自验证环境自定义的某个高频时钟。
chk_en为我们验证环境控制的自动化checker的使能,环境中可以控制这个信号来决定何时开启检查
case_num为上层传递的一个参数,为了方便debug,这里利用该参数来与不同的时钟进行对应
report_err这个是为了关闭某个检查,主要考虑到某些时钟可能是已知的问题,虽然有不定态但是经过designer确认,可以waive掉的,因此这部分我们不希望他向testbench上传err_num,否则就会影响我们case打pass。
而checker的核心即利用Verilog内嵌函数isunknown()来判断当前clk或者信号是否为不定态。
而我们在更上层可以直接实例化,代码如下(示例):
clk_x_state_chk u_clk_x_state_chk0(
.ref_clk (clk_model_ref_clk ),
.chk_en (clk_x_state_check_en),
.clk (clk_target0 ),
.case_num (32'h0 ),
.report_err(1'b1 )
);
clk_x_state_chk u_clk_x_state_chk1(
.ref_clk (clk_model_ref_clk ),
.chk_en (clk_x_state_check_en),
.clk (clk_target1 ),
.case_num (32'h0 ),
.report_err(1'b1 )
);
......
? ? ? ?该checker仅仅是借用了Verilog语法,用起来也非常的简单,但是有时候确能发挥出意想不到的效果,尤其是在后仿中,众所周知在后仿过程中,有时候有些信号一旦不满足timing问题,寄存器Q端输出将出现不定态,如果能利用该checker对此进行自动化检查,将大大提高我们debug问题的效率。当然,过多的自动化checker有可能会拖慢我们的仿真速度,这一点要根据实际工程的大小以及服务器的配置来balance,还是那句话,没有通杀的船票,有的只是我们在面对各种问题时的随机应变,各种大招小招,但凡能发现一个bug,就是好招!