环境wait了一次为啥执行了两次?

电子说

1.2w人已加入

描述

前言

副标题 —— 验证环境中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信号置起一拍:

RTL

当时出现的错误是,发现只有一拍的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次,事故现场还原结束。

事故分析

明确下,这个现象是不符合代码本意的,本意应该是一拍有效取一个数据出来,那么接下来具体分析下为什么是这种现象,由本灵魂画手把波形画一下!

RTL

顺便在把time slot的图搬出来对着看,因为环境搭建并启动于于module中,只需要module regions的就够了:

RTL

那么在2010ns时间点,进程上在做哪些事呢?

1.2010ns ts之前的1ps(interface中设置的skew)采样rtl vld信号为1,在active-observed之间bus.mon.vld值跳变为1;
2.时钟bus.mon在observed域跳变为1;对应的时序结构如下图,那么也就不难发现为什么wait会判定成功2次了:

RTL

时间线也就理清楚了:

*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上升沿-->

  • 时间推进到2020ns,@bus.mon成功,再一次执行下面的语句。

责任划分

该波形是符合systemVerilog仿真规则的,但是不符合本人意图,最好就别这么搞。乖乖的@bus.mon (if bus,mon.vld) 是最安全的。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分