在非時鐘沿去做cb賦值的時候,cb只會等到里程沿才會將值給到真正的signal。
在這種植情況下,如出現下面這種情況:
cb.a<=1;
@(cb);
cb.a<=2;
如果cb.a<=1 在沿1與沿2的中間,那么在沿2的時候,a的值將直接變為2
SOLUTION:
cb.a<=1;
@(cb);
if(cb.a!=1)
@(cb);
cb.a<=2
example1:
clocking cb @(negedge clk);
input v;
endclocking
always @(cb) $display(cb.v);
always @(negedge clk) $display(cb.v);
example2:
clocking cb @(posedge clk);
input v;
endclocking
task tclk();
$display($time," pre-clk");
@(posedge clk);
$display($time," post-clk");
endtask
task tcb();
$display($time," pre-cb");
@(cb);
$display($time," post-cb");
endtask
initial begin
fork
begin:clk
@(posedge clk);//active
tclk();//next active
end
begin:cb
@(posedge clk);//current active
tcb();//current observed
end
join
end
result :
30 pre-clk
30 pre-cb
30 post-cb
40 post-clk
假设当前时刻是30,clock 周期是10,则其中clk 进程的两条语句执行的时间分别在30,40 ;
cb 进程的两条语句执行的时间都为30
clocking block 写法实例:
clocking bus @(posedge clock1);
default input #10ns output #2ns;
input data, ready, enable = top.mem1.enable;
output negedge ack;
input #1step addr;
endclocking
对于同一信号,经过cb比没经过cb的晚1T(与input,output无关)。比如说vif.cb.a会比vif.a delay 1T。
在验证环境中,我们通常的做法:
driver中利用cb来drive signals; 比如: vif.cb.a <= 1’b1
连接DUT时却用的是不加cb的信号;比如: .frame_in(vif.a)
monitor中用加cb的信号sample; 比如: txn.a = vif.cb.a
waveform:
___
vif.a _______| |_________(DUT的输入信号)
___
vif.cb.a _____________| |_________(monitor sample的信号)
1 2 3
在时钟沿采到的是沿前的值,所以monitor采到的值比DUT的值delay 1T。
上述情况是针对drive DUT input和sample DUT output;当在环境描述signal level behavior时,cb使用状况有差别。
fork
forever begin//进程1
@(posedge line_ck or negedge rst_b);
cur_vld = (rate_cnt == 0);
end
forever begin//进程2
@(posedge line_ck or negedge rst_b);
if(cur_vld == 1'b1)
......
end
join
上面描述了两个并行进程,进程1 drive cur_vld ,进程2 sample cur_vld.
上面这种写法会产生竞争冒险,因为在同一时间既drive又sample.
此时我们想到了clocking block,它可以规避这件事。
interface vif;
parameter setup_time = 0.05;
parameter hold_time = 0.05;
logic cur_vld;
clocking line_cb @(posedge line_ck );
default input #setup_time output #hold_time;
inout cur_vld;
endclocking
endinterface
fork
forever begin//进程1
@(line_cb or negedge rst_b);
vif.line_cb.cur_vld <= (rate_cnt == 0);//驱动时加cb
end
forever begin//进程2
@(line_cb or negedge rst_b);
if(vif.line_cb.cur_vld === 1'b1) //采样时加cb
......
end
join
上面的写法可看出: 当自己驱动自己采样时 drive signals 时用cb, sample时也用cb.
__
vif.cur_vld _______| |_________(DUT的输入信号)
__
vif.cb.cur_vld _____________| |_________(monitor sample的信号)
1 2 3
采样时加不加cb都会在位置2处采到,debug看waveform时看不加cb的信号即可。前提是格式要统一,不要混用 ,即
forever begin//进程2
@(line_cb or negedge rst_b);//等cb
if(vif.line_cb.cur_vld === 1'b1) //采样时加cb
......
end
forever begin//进程2
@(posedge line_ck or negedge rst_b);//等posedge clk
if(vif.cur_vld === 1'b1) //采样时不加cb
......
end