在仿真的行为 中,为了尽量避免时序电路中时钟和驱动信号的时序竞争问题,我们需要尽量明确驱动时序和采样时序。
默认情况下,时钟对于组合电路的驱动会 添加一个无线小 的时间延迟(delta-cycle),驱动信号和被驱动信号之间的延迟。它比最小 时间单位精度还小。
在仿真的过程中,输入命令“run 0”,就是 让仿真其运行一个delta-cycle时间。
timescale 1ns/1ns
module racel;
bit clk1,clk2;
bit rstn;
logic [7:0] d1;
initial begin //产生时钟clk1
forever #5 clk1 <= !clk1;
end
//产生时钟clk2
always @(clk1) clk2 <= clk1;
initial begin
#10 rstn <= 0;
#20 rstn <= 1;
end
//计数器
always @(posedge clk1, negedge rstn) begin
if(!rstn) d1<= 0;
else d1<= d1 + 1;
end
//在clk1,clk2上升沿打印出d1的数值
always @(posedge clk1) $display("%0t ns d1 value is 0x%0x", $time,d1);
always @(posedge clk2) $display("%0t ns d1 value is 0x%0x", $time,d1);
endmodule
问:在45ns时,采样的d1值为1,那么clk2在45ns时,采样的d1值为多少呢?2
由于各种 可能性,clk与被采样数据之间如果只存在若干个delta-cycle延迟,那么 采样可能会 存在问题,上例子中clk1与clk2对d1采样,在同样的时刻得到的是不同的采样 结果。
如何避免该问题:
(1)在驱动时,添加人为的延迟,模拟真实的延迟行为,同时加大clk与 变量之间的 延迟驱动,提高DUT信号的准确和TB 采样信号的可靠性。
(2)另外,对于一些采样仍然存在delta-cycle问题,我们还可以在采样事件的 某段时刻中进行采样,来模拟建立时的采样要求,保证采样的可靠性。
时钟块问题:
clocking bus @(posedge clock1);
default input #10ns output #2ns;
input data ,ready , enable;
output negedge ack;
input #1step addr;
endclocking
添加时钟块注意还应该以下问题:
(1) clocking块不但可以定义在interface中,也可以定义在module和program中;
(2)clocking中列举的信号不是自己定义的,而是由interface或者其它声明clocking模块定义;
(3)clocking在声明之后,伴随着默认的采样事件,否则默认在前1step输入采样,后#0输出驱动;
(4)还可以用新的采样事件覆盖默认事件。
module clocking
bit vld;
bit grt;
bit clk;
clocking ck #(posedge clk);
default input #3ns output #3ns;
input vld;
output grt;
endclocking
initial forever #5ns clk <=!clk;
//驱动
initial begin: drv_vld
$display("$%0t vld is assigned %d", $time,vld);
#3ns vld =1; $display("$%0t vld is assigned %d", $time, vld);
#10ns vld =0; $display("$%0t vld is assigned %d", $time, vld);
#8ns vld =1; $display("$%0t vld is assigned %d", $time, vld);
end
//采样1,时钟上升沿采样
initial forever
@ck $display("$%0t vld is sampled as %d at sampling time $%0t", $time, vld ,$time);
//采样2,等到ck事件即时钟上升沿利用clocking块采样
initial forever
@ck $display("$%0t ck.vld is sampled as %d at sampling time $%0t", $time, ck.vld ,$time-3); //等到ck事件即时钟上升沿利用clocking块采样
endmodule
本题目考查直接采样时钟上升沿采样和利用clocking块进行采样的区别:
由图可知,直接利用时钟上升沿采样得到 采样值为101;而采样时钟块 采样得到的值为001。
module clocking
bit vld;
bit grt;
bit clk;
clocking ck #(posedge clk);
default input #3ns output #3ns;
input vld;
output grt;
endclocking
initial forever #5ns clk <=!clk;
//驱动
initial begin: drv_grt
$display("$%0t grt initial value is %d", $time,grt);
@ck ck.grt <=1; $display("$%0t grt is assigned 1", $time);
@ck ck.grt <=0; $display("$%0t grt is assigned 0", $time);
@ck ck.grt <=1; $display("$%0t grt is assigned 1", $time);
end
initial forever
@grt $display("$%0t grt is sampled as %d", $time,grt);
endmodule
分析输出就会 发现,实际的驱动输出和仿真 设置的输出之间有3ns的延迟。
总结:
(1)为了避免采样竞争的问题,应该在验证环境驱动环节添加固定延迟,使得仿真波形中更加容易体现出时钟和被驱动信号之间的时序,便于DUT准确处理和TB 准确采样。
(2)如果TB在采样从DUT送出的数据,在时钟和被驱动 信号之间存在delta-cycle时, 应该考虑在时钟采样沿更早的时间段去模拟建立和保持时间要求采样,这样避免由于delta-cycle带来的采样竞争问题。
(3)将clockiing运用到interface,用来声明各个接口和时钟采样的 驱动关系,可以大大提高数据驱动和采样的准确性,排除采样竞争的可能性。