第五章 时钟strobe检查
只所以要进行时钟strobe检查,是因为很多时候设计中有下图时序的要求,这种场景一般在两个频率不同的时钟域内进行数据交互的时候会用到,比如AHB到APB域的数据交互,都需要利用clk_strobe来指示数据的有效性。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 图1:两个时钟之间的关系?
?为了说明问题,我们举个简单的例子,实际上时钟设计可能会更复杂,利用进行扩展:
假设clk_2是clk_1分频得到的时钟,可以是同频,可以是二分频,设计要求当clk_2与clk_1同频时,clk_strobe需要一直为高电平,当clk_2为clk_1的二分频时,在任意两个沿对齐的时候需要采样到clk_strobe为高电平,且clk_strobe只能保持一个clk_1的时钟周期长度。
我们可以简单的理解为:当两个同源时钟时钟沿对齐的时候,不管时钟频率是否相同,为了保证数据交互正常,需要一个数据交互的握手信号来指示当前数据是否有效,而这个握手信号要求任意两个时钟沿对齐的时候都可以采样到其为有效。而且要求这个有效时间只能是两个时钟信号最高频的1个时钟周期。
property strobe_0;
@(posedge clk_2) disable iff(not_check) clk_strobe;
endproperty
a_check_strobe_0: assert property(strobe_0);
else begin
err_num ++;
end
c_check_strobe_0: cover property(strobe_0);
上图代码分析:由于clk_1是源时钟,clk_2为其子时钟,两个时钟沿会周期性的对齐,因此我们需要检查每个clk_2的上升沿都应该采样到clk_strobe,否则说明分频过程中,RTL设计漏掉了某个clk_strobe,这种漏掉的strobe是不符合设计要求的。当然,我们也可以在验证环境中通过控制not_check来关闭checker。
property strobe_1;
@(posedge clk_1) disable iff(not_check) clk_strobe |=> if(clk_div_num==0) clk_strobe
else !clk_strobe;
endproperty
a_check_strobe_1: assert property(strobe_1)
else begin
err_num++;
end
c_check_strobe_1: cover property(strobe_1);
?上图代码分析:因为clk_1与clk_2存在分频关系,因此,我们加入该条checker,当clk_1采样到clk_strobe时,如果clk_2与clk_1同频(clk_div_num=0表示不分频),那么下一个clk_2也必须采样到clk_strobe为高,否则下一个clk_2必须采样到低电平(因为设计要求clk_strobe在分频情况下只能保持一个clk_2的周期长度)。
sequence strobe_2;
@(posedge clk_1) clk_strobe;
endsequence
sequence strobe_3;
@(posedge clk_2) clk_strobe;
endsequence
property strobe_4;
disable iff(not_check) strobe_2 |-> strobe_3;
endproperty
a_check_strobe_4: assert property(strobe_4)
else begin
err_num ++;
end
c_check_strobe_4: cover proerty(strobe_4);
上图代码分析: 分别定义两个序列,序列stobe_2为每个clk_1采样clk_strobe,序列strobe_3为每个clk_2采样clk_strobe。clk_strobe4定义了当strobe_2成立时激活属性检查,同时当前时刻判断序列strobe_3也必须成立,否则断言失败。利用该checker来进一步说明当clk_1与clk_2沿对齐时,必须都能采样到clk_strobe,即应该满足图1所示要求。
通过systemverilog assertion来实现两个甚至多个时钟之间strobe的检查,后期可以进行覆盖率统计,通过分析覆盖率保证可以很清楚的查看这些checker有没有被执行过,且执行的结果可以反馈到上层的testbench中,方便验证人员快速定位到问题点。
利用三个checker来完成一组strobe的检查,可以实现全方位无死角的check任意时刻两个时钟时间是否完全满足图1中的时序要求。这种方式看似代码量有点大,但是通过实战我们发现,这种方式还是具有一定的高效性的,而且易于维护和继承。