[资料分享] FPGA Verilog语言中阻塞赋值与非阻塞赋值个人看法

Aguilera   2018-11-10 20:19 楼主
对于Verilog 初学者来说,阻塞赋值与非阻塞赋值应该要区别一下子,我估计对于这两种赋值方式的应用解说,什么时候该用阻塞赋值,什么时候该用非阻塞赋值,通常见到的一句话是,时序逻辑里面通常用非阻塞赋值,组合逻辑里面通常使用阻塞赋值。但是这必然是含糊不清的,也并不意味着时序逻辑里面就不可以阻塞赋值了,组合逻辑里面就不可以用非阻塞赋值了。所以我觉得有必要弄清楚一下阻塞赋值和非阻塞赋值的细微区别。
       首先还是回归下定义,所谓阻塞赋值,例如 a=b; 当这个赋值语句执行的时候是不允许有其它语句执行的,这就是阻塞的原因。而非阻塞赋值,例如a<=b;当这个赋值语句执行的时候是不阻碍其它语句执行的。对于FPGA来讲,跟单片机相比(即使是高速单片机),它本身的优点是语句执行的并行性,而单片机语句执行是顺序执行的。所以如果说我们要充分利用好FPGA这个优点,那么我们应该尽量使用非阻塞赋值。
       下面我想从一个简单的例子来浅析一下两者的区别。


360截图20181110202325689.jpg
这是一个简单的分频程序,目的是将clk时钟四分频。Count初始值是0,(个人经验认为的,因为verilog里面似乎没法对变量进行初始化),然后第一个时钟的上升沿到来时,count自加1后变成了1,if语句执行为假,然后第二个时钟上升沿到来时,count又自加1变成了2,if语句执行条件为真,则执行if语句内的内容,将data_a数据翻转,count重新赋值为0,所以该程序就是每两个时钟的上升沿,data_a数据翻转一次,得到四分频的效果。
下图为仿真波形,是完全对得住分析的。


360截图20181110202332116.jpg
上面的程序用的是阻塞赋值,也就是 count执行自加1的时候,其它任何语句都是不能执行的,因此这里就有点想单片机里面的C语言了,一个顺序执行的always块。
如果把上面的程序赋值全改成非阻塞赋值,效果会怎样呢?
360截图20181110202338346.jpg


首先我们先不作分析,先对比一下仿真波形。
360截图20181110202343527.jpg


从仿真波形来看,这个程序确变成了对clk时钟的六分频,显然不是我们之前的思路分析结果。实际上它是这样子执行的。
    首先可以这样理解,1、非阻塞赋值是always块结束才赋值的,个人理解是程序见到always块的结束标记end后才赋值,但是并不代表当程序最开始看到该语句时没有任何动作,而是先把后面的值给计算出来放在一个寄存器中暂存,到了块结束才赋值,比如上述中的先把count+1计算出来后,到了块结束才把那个结果赋值给count。2、非阻塞赋值是并行执行的,因此不管有多少个always块,不管每个always块里面有多少条非阻塞赋值,它都是瞬间一块并行执行的,互不干扰。
所以上面的程序就好分析了
      Count初始值是0,第一个时钟的上升沿到来时,count<=count+1 这条语句先不赋值(前面说了块结束才赋值),但是count+1已经计算出来放在寄存器中存储着,先执行的是if语句,if语句此时条件仍然是(count=0),条件为假,不执行if内部语句,接着遇到always块结束标记end,这才执行count<=的赋值,count此时为1,然后第二个时钟上升沿到来,同样先执行if语句,条件仍然为假,然后再执行count自加1,count变为2,第三个时钟上升沿到来,先执行if语句,条件满足,至于此时 有三个非阻塞赋值的语句出现
count<=count+1;
data_a<=!data_a;
count<=0;
这三个语句按道理讲也是并行执行的,但是,有两个语句同时对count进行了赋值。。那么咋整呢,这点笔者尚未清楚,恳请达人解析,或者待日后笔者弄清楚在来看看了。。。
7月25日,经过龙哥点拨,上述问题终于有了一个合理的解释。
参阅许多资料可以得出的结论是:在begin 。。end 中非阻塞赋值实际上是并行中的顺序执行。此话的理解是,begin 。。end 语句块中得非阻塞赋值语句与其它块中的非阻塞赋值语句是并行的,但是对于单个begin 。。end 块中的语句却是顺序执行的。所以在verilog语言中是不允许在两个块中对同一变量进行赋值的,而在单一块中,如果有两个或两个以上的非阻塞语句对同一个变量进行了赋值,那么该变量的值由最后一个语句所决定。

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复