Verilog中阻塞与非阻塞语句

这几天一直在纠结阻塞与非阻塞的问题,到现在基本弄清楚了。在纠结这个问题的时候,还顺便弄清楚了前仿真与后仿真,Verilog的分层事件队列,使用系统任务的一些原则等。这些问题以后再说,现在只谈一下我对阻塞与非阻塞的理解。

概念这东西,还是引用教材中的比较好。

    关于阻塞:计算RHS并更新LHS,此时不能允许有来自任何其他Verilog语句的干扰。 所谓阻塞的概念是指在同一个always块中,其后面的赋值语句从概念上(即使不设定延迟)是在前一句赋值语句结束后再开始赋值的。

这段代码实现的功能就是,在clk上升沿到来的时候,把a的值赋给b,再把b的值赋给c,并显示a、b的值。当条件符合时,执行上述操作。在把a的值赋给b的这个过程中,其他的语句都“被阻塞”,被迫停下来,结束之后,进入下一句,直到执行完begin---end中语句。所以相当于把a的值通过b传递给c。

这里所有的测试文件用的都是这一个testbench :

仿真结果:

综合之后只有一级寄存器。相当于把a的值直接传递给c。而b只是中间变量而已,并没有实际意义。

如果把上述代码中的两个赋值语句相互交换,如下所示,结果就不同了

在第一个clk上升沿到来时,由于b的值未知,赋给c之后,c也为未知值;紧接着,把a的值给b,由于a的值已经给出,所以,结束之后,a、b的值相同,c为x。

综合之后,生成两级移位寄存器。

    关于非阻塞:

1) 在赋值时刻开始时,计算非阻塞赋值RHS表达式。

2) 在赋值时刻结束时,更新非阻塞赋值LHS表达式。

    这段代码在posedge clk到来时,计算所有的RHS(Right Hand Side)的值,此时,a的值为3,b的值为x,这是同时进行的,没有先后顺序;然后更新LHS(left Hand Side)的值,结束之后,b的值变为3,c的值为前一时刻b的值,即x。如波形图所示:

综合之后生成两级移位寄存器:

如果把上述代码中的两个赋值语句相互交换,如下所示,结果和上面是一样的。所以在一个begin---end中的非阻塞语句并不会因为放置的位置不同,出现不同的结果。

关于非阻塞的例子,分析的貌似蛮有道理,但是从脚本上却看出了问题,第一个clk上升沿到来之后,a的值为3,而b、c的值却为x,就是说,并没有执行操作,但是从波形图看,确实在posedge clk的时候,把a的值传递给了b。到底怎么回事呢?直到看了一篇博文(http://blog.sina.com.cn/s/blog_58649eb30100biox.html),想起了Verilog的层次化事件队列的概念。再一翻书,明白了。原来是系统任务用的不对,$display命令的执行是安排在活动时间队列中,但排在非阻塞赋值数据更新事件之前。这就解释了为什么b的值是3,显示的却是x。换成$strobe之后,和预想的就相当一致了。

这下就对了。用$strobe系统任务来显示,应该用非阻塞赋值的变量值。

再了解一下Verilog的层次化事件队列有助于理解阻塞与非阻塞。阻塞赋值、计算非阻塞赋值语句右边的表达式、连续赋值、执行$display命令都放在动态事件队列中。而非阻塞赋值语LHS的更新却不放在这里,排在其他队列中的事件要被排入动态事件队列中后,才能等待执行。所以,排在动态事件队列中的事件优先级最高。

$strobe显示命令是排列在监控事件队列中,在仿真结束的时候,所有的值都赋完之后,$strobe才会显示出要求显示的变量的值。解释了应该用$srobe来显示非阻塞赋值的结果。

最后还剩下到现在都没想明白的两个问题:

单从代码中可以看出,当posedge clk到来时,发生了两次移位,至于哪次在前哪次在后并不能确定,顺序是随机的。唯一可以确定的就是:确实发生了两次移位。从仿真结果来看,当条件满足时,先执行的是b = a,接着是c = b,和阻塞赋值的第一种情况一样。

但是却综合出来了一个两级移位寄存器的RTL级视图:

把两条语句交换后如下:

仿真结果应该和上面是一样的才对,但很明显不一样,结果显示,第一次posedge clk结束时b的值为3,c的值为x,合理的解释是:clk上升沿到来,先执行的是c = b,然后才是b = a。而这种结果也应该是不确定的,但做了多次之后,每次结果都是这样。

综合后出现的RTL级视图和上面是一样的。

这两个例子综合后出现的两级移位寄存器说明,在每个clk上升沿,确确实实有两次移位,并且这两次移位是顺序进行的,所以出现了两个寄存器,而移位的先后顺序却不同,所以仿真的结果也就不同。但是既然仿真结果不一样,也不确定,怎么会出现相同的RTL级视图呢?怎么会综合出正确的结果呢?

好吧,只好用教材上的两段句来解释这个问题(虽然我还是看不太明白):

阻塞赋值分别被放在不同的always块里。仿真时,这些块的先后顺序是随机的,因此可能出现错误的结果。这是Verilog中的竞争冒险,按不同的顺序执行这些块将导致不同的结果。但是,这些代码的综合结果却是正确的流水线寄存器。也就是说,前仿真和后仿真的结果可能会不一致。

把always块的顺序稍作变动,也可以被综合成正确的移位寄存器逻辑,但仿真结果可能不正确。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值