always语句块总是循环的执行。如果一个module里有好几个always语句块,这些always块都是并发执行的,如下例所示。
例17.1:多always语句块。
这个例子里,这几个always语句块都是同等级别的,并发执行。
那么每一个always语句块内部语句是如何执行的呢?这还是回到了阻塞和非阻塞的区别。always语句块内部语句虽名为顺序语句,但也得根据阻塞和非阻塞来决定如何执行。若always语句块内语句为阻塞赋值,则always语句块内部语句顺序执行。若always语句块内语句为非阻塞赋值,则always语句块内部语句并发执行。
always语句块通常都会有事件控制,当然,某些情况也可以没有。比如之前介绍过的生成循环时钟的例子:“always#5 clk=~clk;”,遇到这种情况,就会产生无限的时钟信号,所以可以在后面加上停止语句:“#1000$finish;”。
这个例子,我们同时使用了两个alwasy块的阻塞赋值和非阻塞赋值,第一个always块是电平触发,第二个always块是边沿触发。对于有一些复杂的程序来说,往往会有很多个always块都使用某个信号的相同边沿作为触发(比如clk的上升沿)。当我们遇到第二个always语句块里的非阻塞赋值语句时,不管“<=”符号右边有多少个信号的与或非的计算,你只需要记住,非阻塞赋值意味着是拿该触发边沿之前的值来做的计算。比如语句1,是拿clk的上升沿之前的in和temp0的值做的计算,然后赋值给temp1;语句2,是拿clk的上升沿之前的in和temp1的值做的计算,然后赋值给temp0。
例17.2:设计1——阻塞赋值的5级32位移位寄存器。
图17.6是综合的电路。
图17.6 阻塞赋值的5级32位移位寄存器综合的电路
可以看到,语句1至语句5都是阻塞赋值。语句1把d赋值给s1,s1得到了新的值。语句1执行完了才执行语句2。然后语句2把s1的新的值赋值给s2,s2得到了新的值。由此,d=s1=s2=s3=s4=s5。所以我们看到在上图中,几个触发器都融缩了,只留下了一个32位的D触发器S5。
例17.3:设计2—非阻塞赋值的5级32位移位寄存器。
图17.7是综合的电路。
图17.7 非阻塞赋值的5级32位移位寄存器综合的电路
可以看到,这是典型的移位寄存器结构。clk同步控制着每一个32位的D触发器。这个图和上一个程序的图的区别在于,本例中,语句1~语句5都换成了非阻塞赋值。也就是这5个语句里的每个语句都不阻塞下一行语句的执行。语句1~语句5同时执行。既然是同时执行,在每个clk的上升沿,就会把后4个D触发器的输入(该输入来自前一个D触发器上一时刻的输出)传递给输出。这就是非阻塞的意思。
我们已经从设计1和设计2看到了阻塞赋值和非阻塞赋值的区别。下面的设计3,我们看一看把设计2的非阻塞赋值的顺序调换一下,会出现什么情况。读者也可以先停在这个地方,思考一下:如果把设计2的语句1~语句5调换顺序,会是什么样的综合结果?
例17.4:设计3—非阻塞赋值的5级32位移位寄存器。
图17.8是综合的电路。(www.xing528.com)
图17.8 非阻塞赋值的5级32位移位寄存器综合的电路
可以看到,图17.8这个电路和设计2的综合结果是一模一样的。
例17.5:一个错误描述的组合逻辑电路。
假设有一个电路图如图17.9所示:
图17.9 错误描述的组合逻辑电路图
如果把上面这个电路以下面这段程序进行描述,对不对呢?
上面这段程序综合的结果确实和程序之前的电路图是对应的。上面这段程序描述的是一个组合逻辑电路,将alpha、beta的值异或,gamma、delta的值异或,两个异或值进行相与的结果赋值给out。综合是正确的。但是,如果是按照这段程序进行仿真,那么上面这段程序的仿真结果就和图中电路的意思有分歧(也可以说是错误)。
为什么会出现错误?
首先语句1的执行是拿之前的alpha和beta的值做异或再赋值给temp1。语句2的执行也类似。语句3拿的是之前的temp1和temp2的旧值(不是语句1和2产生的)来做与运算。
所以本例中的电路图和上面这段代码不是对应关系。
我们可以稍作修改,看下一个例子,尝试让电路图和下面的例子的源代码对应上。
例17.6:module ex2(alpha,beta,gamma,delta,out);
我们做的改动就是把语句4的电平敏感列表多加了两个信号。这样只要语句1和语句2计算的temp1和temp2有改动,就重新进入always块,进而重新计算语句3,这样源代码仿真就和电路对应上了。
但是,虽然对应上了,又出现了新的问题。那就是语句4电平敏感列表多了几项之后,运行的时候频繁进入always块,会对仿真的性能造成影响。因此我们可以考虑再次把程序做些修改,如下例所示。
例17.7:module ex3(alpha,beta,gamma,delta,out);
本例我们完全采用了阻塞赋值,本例的源代码的仿真和电路就对应上了。
结论就是:设计组合逻辑电路,尽量采用阻塞赋值语句。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。