采样时发生竞争(delta cycle的存在),会导致采样数据错误。为了避免在RTL仿真中发生信号竞争的问题,建议通过非阻塞赋值或者特定的信号延迟来解决同步问题。这里我们介绍使用时钟块来决定信号的驱动和采样的方式。
什么是delta cycle?
在RTL仿真时,由于无法确定具体电路的延迟时间,默认情况下时钟驱动电路时会添加一个无限最小的时间(delta cycle)的延迟,这个延迟要比最小时间单位精度还要小(可以理解成远小于1ps)。
在一个时间片(time - slot)中可以发生很多的事,例如在仿真时输入run0,即让仿真器运行一个delta-cycle的时间。
由于各种可能性,clk与被采样数据之间如果只存在若干个delta-cycle的延迟,那么采样就会出问题。
例如下代码:
`timescle 1ns/1ns
module tb;
input clk1,clk2;
outout d1;
reg d1;
//产生clk1的时钟周期
initail begin
forever #5 clk1 <= !clk1;
end
always@(clk1) clk2 <= clk1; // 非阻塞赋值另一个时钟
always@(postedge clk1 ) d1 <= d1 + 1;
endmodule
如果在45ns处,clk1在上升沿处采样的得到d1的值为1,那么clk2在45ns处,采样得到d1的值应该是多少?
表面上看clk1和clk2是同周期变化的时钟信号,我们可能认为在clk1和clk2上升沿采样的结果都是相同的。
但**实际clk1与clk2之间相差一个delta cycle时间片,**也就是clk2要滞后于clk1一个delta cycle的时间, 这就产生了两种不同的采样结果
- 当仿真器在45ns + 0(delta cycle)处采样,clk1 = 1, clk2 = 0, d1 = 1; 【仿真器采样会取到的d1 = 1】
- 当仿真器在45ns + 1(delta cycle)处采样,clk1 = 1, clk2 = 1, d1 = 2;
也就是说,要想采样真实,需要仿真器在45ns后一点点区域去采样,而不能在45ns处采样
注:如何在EDA工具中看到delta cycle?
将时间轴选在clk1在45ns处的上升沿变化处,打开工具栏expanded time deltas mode --> expanded time at active cursor,就可以看到仿真器的delta cycle
采用clocking时钟块
clocking块基于时钟周期对信号进行驱动或者采样的方式,可以使testbench准确及时地对信号驱动或采样,消除信号竞争的问题。
clocking bus@(posedge clk); //在clk上升沿来驱动和采样
//在clk上升沿的前2ns对其进行输入采样,在事件的后2ns进行输出驱动
default input #2ns output #2ns
endclocking
注意:
- 如果不使用 default 指定的 input 和 output 的 skew,sv默认指定的 input skew为 1step,output skew 为0。 input skew 和 output skew 如下图所示,
- 如果input 的skew 是 1step,所采样的值是时钟事件发生前最后末尾(Postponed区域)。
- 如果直接指定default input #0 ,这会在相应地时钟事件发生的 time slot 的Observed区域采样。
- 如果直接指定default output #0 ,会作为非阻塞事件,在NBA区域进行采样。
一般在接口中定义clocking块,如下:
interface chnl_intf(input clk, input rstn);
logic [31:0] ch_data;
logic ch_valid;
logic ch_ready;
logic [ 5:0] ch_margin;
// 定义时钟块
clocking drv_ck @(posedge clk);
//采样时间
default input #1ns output #1ns;
//声明变量方向
output ch_data, ch_valid;
input ch_ready, ch_margin;
endclocking
endinterface