电子说
副标题 —— 验证环境中bus.mon.sig与@bus.mon同时使用的反面案例哈哈哈。这个bug是在是过于经典了所以每过一段时间我就会拿出来跟人聊聊,要是没有这个的激励,我一定不会走上记录bug的道路的。
先来还原出错的场景。代码示意如下,验证环境构建于module中,这段代码的本意是希望对齐rtl的时钟沿,因此在wait到bus.mon.vld(bus是interface,mon是clocking block)后@时钟,之后从队列中取数进行处理,下面的代码我将取数调整成打印信息,本质都是执行一个操作:
initial begin
forever begin
wait (bus.mon.vld == 1'b1);
@bus.mon;
$display("%t, pop_front this cyc", $realtime);
end
end
此时RTL的波形如下,vld信号置起一拍:
当时出现的错误是,发现只有一拍的valid信号,但是却发生了两次取值行为,且发生在两拍,那么对应打印行为就是说发生了两次打印且在不同时刻:
2010.000ns, pop_front this cyc
2020.000ns, pop_front this cyc
为了进一步确定行为,在wait和@之后分别加入打印:
initial begin
forever begin
wait (bus.mon.vld == 1'b1);
$display("%t, wait dao le!", $realtime);
@bus.mon;
$display("%t, pop_front this cyc", $realtime);
end
end
打印结果为:
2010.000ns, wait dao le!
2010.000ns, pop_front this cyc
2010.000ns, wait dao le!
2020.000ns, pop_front this cyc
可以确定在2010ns时刻wait生效了2次,事故现场还原结束。
明确下,这个现象是不符合代码本意的,本意应该是一拍有效取一个数据出来,那么接下来具体分析下为什么是这种现象,由本灵魂画手把波形画一下!
顺便在把time slot的图搬出来对着看,因为环境搭建并启动于于module中,只需要module regions的就够了:
那么在2010ns时间点,进程上在做哪些事呢?
1.2010ns ts之前的1ps(interface中设置的skew)采样rtl vld信号为1,在active-observed之间bus.mon.vld值跳变为1;
2.时钟bus.mon在observed域跳变为1;对应的时序结构如下图,那么也就不难发现为什么wait会判定成功2次了:
时间线也就理清楚了:
*2010ns, bus.mon.vld跳变为1 -->
*wait(bus.mon.vld)在observed之前生效 -->
*@bus.mon成功(observed域)-->
*执行环境语句,不消耗时间,forever回wait语句 -->
*wait(bus.mon.vld)再次成功,此时仍为2010ns -->
*@bus.mon不成功(关于@和wait的区别请查询绿皮书吧),该进程等待在这里,等下一次bus.mon上升沿-->
该波形是符合systemVerilog仿真规则的,但是不符合本人意图,最好就别这么搞。乖乖的@bus.mon (if bus,mon.vld) 是最安全的。
全部0条评论
快来发表一下你的评论吧 !