Verilog流水线加法器always块中应该采用阻塞赋值(=),还是非阻塞赋值(<=)?

2019-07-15 22:24发布

二级流水线加法器非阻塞赋值.png 图一
wave3.PNG
图二
二级流水线加法器阻塞赋值.png
图三
wave4.PNG
图四

最近写了一个16位二级流水线加法器,并进行了一下仿真。发现在always块中采用阻塞赋值(=)和非阻塞赋值(<=)的结果是不一样的,书上的例程以及网上很多例程的流水线加法器都采用的是阻塞赋值。
书上对流水线加法器的描述是这样的:“采用流水线,能将一个算术操作分解为一些小规模的基本操作,将进位和中间值存储在寄存器中,并在下一个时钟周期内继续运算”。
如上图所示,图一、图二是采用非阻塞赋值的代码及仿真波形图,图三、图四是采用阻塞赋值的代码及波形图。明显可以看出,采用阻塞赋值的仿真结果是在一个时钟周期内得到结果,并没有像描述的那样在每个时钟周期内分级运算,也没有体现出流水线的特点;而非阻塞赋值好像更符合“下一个时钟周期内继续运算”的描述,也体现出了流水线的执行特点。


求大神指点!




友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
17条回答
reallmy
1楼-- · 2019-07-17 08:49
小白报道 发表于 2016-9-9 11:09
我要是说这里用阻塞赋值是错误的,会不会有人喷死我

不会,强烈支持!!!!!这和什么流水不流水没有关系!!!
渊底一尾
2楼-- · 2019-07-17 14:31
hqbenson 发表于 2016-9-12 16:23
您好楼主。您再仔细分析一下您的代码就可以发现问题了。其实这和阻塞非阻塞没太大关系。(当然时序电路还是必须要用非阻塞的)
主要有
1.流水线的编写思路不太清晰。

您好!首先感谢您对我的问题作出如此详细的解答。
关于您所说的进位位以及每一级增加寄存器的问题,我后来也已经发现并改正了,但是使用阻塞赋值和非阻塞赋值的仿真结果仍然是不同的。阻塞赋值的仿真结果:输入和输出仍然是在一个时钟周期内完成,而非阻塞赋值的仿真结果:输入和输出却是阶梯状。
还望指点!谢谢!
hqbenson
3楼-- · 2019-07-17 16:24
 精彩回答 2  元偷偷看……
alasga
4楼-- · 2019-07-17 21:35
本帖最后由 alasga 于 2016-9-14 22:38 编辑
渊底一尾 发表于 2016-9-12 08:34
1、因为要采用流水线设计,所以没有直接用{cout,sum}。
2、采用图一代码,我发现仿真结果不对。上图中,我没有对高8位赋值。在我对高8位赋值后,发现:输出结果(cout)的高8位是当前输入高8位的和,而低8位则是上一个时钟输入低8位的和。请问应如何解决?不知您之前是否写过流水线加法器?求指教。 ...

简单,你把输入数据cina和cinb延迟1级,简称cina_d1和cinb_d1,在你的第二个always块中,高8bit的运算用cina_d1和cinb_d1代替就OK了,改完相信你就知道你的问题在哪了。另外刚才看了12楼的解说,他说的完全正解!!!,低8位相加时,应该不需要进行符号位扩展,毕竟这里的第8bit不是符号位。这一点倒是看了12楼的观点才发现。
渊底一尾
5楼-- · 2019-07-17 22:42
hqbenson 发表于 2016-09-14 12:36
指点不敢..我也在学习中,只能按我理解的观点谈一下问题点...
楼主您可以试一下,源代码中,在用阻塞赋值时,如果将两个always调换位置(将第二个always写在前面,第一个always写在后面),仿真出来的结果会和原来的不一样。(sum要从第二个时钟沿才有输出,并且与当前的输入值之和不一致)
在用非阻塞赋值时,就算将两个always调换位置,仿真出来的结果是一样的。

根本原因在于,当仿真器运行到阻塞赋值语句时,先计算等号右边的值并更新,这时候赋值语句不允许任何别的verilog语句干扰,直到把该值赋值完成为止。
如果是非阻塞赋值语句,计算等号右边的值时,其他的verilog语句,非阻塞赋值语句都可以同时计算等号右边的值。非阻塞语句允许其他的语句同时操作。

按此理解,如果
1.原本代码,用阻塞:仿真器执行语句,按代码所述,第一个上升沿事件开始→计算出sum1和count1并立即赋值→计算cout和sum并立即赋值→结束上升沿事件。

2.原代码,用阻塞,将两个always对调:仿真器执行语句,第一个上升沿事件开始→计算出count和sum并立即赋值→计算出sum1和count1并立即赋值→结束上升沿事件。

3.原代码,用非阻塞:仿真器执行语句,第一个上升沿事件开始→计算出sum1和count1的值,同时计算sum,count的值(目标还未更新赋值)→更新赋值目标的值→结束上升沿事件。

情况1中,计算sum1与count1的阻塞赋值语句在前面,在sum与count执行之前,sum1与count1已经得到更新,所以第一个上升沿就有值输出。

情况2里面,由于把sum和count的语句写在了前面,仿真器先计算并更新它们俩的值,但由于此时sum1和count1仍是未知值,所以第一个时钟沿输出仍是未知值(红线),更新完sum与count后,才计算写在后面的always里面的sum1与count1的值并立即更新。

由于有这样的歧异,所以才可综合代码里,规定在含有时序逻辑的always块里面必须使用非阻塞。
由于流水线是典型的,严格的时序逻辑电路,所以必须使用非阻塞。

如果楼主您还不太理解,建议多写一些测试的小代码,用两种赋值修改看看仿真有什么不同然后用自己的想法去理解。当理解的差不多了,再写一些测试代码预测一下仿真结果,或者多看书上的例子。

按照您所说的,我又试了多种情况,发现:代码写在一个always块和写在两个always块中的仿真结果是一样的,那么问题来了:如果触发条件相同,一个always块是否和多个always块的效果相同呢?多个always块的意义又何在呢?

一周热门 更多>