verilog阻塞赋值和非阻塞赋值的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了verilog阻塞赋值和非阻塞赋值的区别相关的知识,希望对你有一定的参考价值。

参考技术A 阻塞赋值操作符用等号(即 = )表示。“阻塞”是指在进程语句(initial和always)中,当前的赋值语句阻断了其后的语句,也就是说后面的语句必须等到当前的赋值语句执行完毕才能执行。
非阻塞赋值操作符用小于等于号 (即 <= )表示。“非阻塞”是指在进程语句(initial和always)中,当前的赋值语句不会阻断其后的语句。非阻塞语句可以认为是分为两个步骤进行的:
①计算等号右边的表达式的值,(我的理解是:在进入进程后,所有的非阻塞语句的右端表达式同时计算,赋值动作只发生在顺序执行到当前非阻塞语句那一刻)。
②在本条赋值语句结束时,将等号右边的值赋给等号左边的变量。

关于veriolg中阻塞与非阻塞赋值问题

在一开始学到阻塞和非阻塞的时候,所被告知的两者的区别就在于阻塞是串行的,非阻塞是并行的。但是虽然知道这个不同点,有些时候还是很难真正区分用两者电路的区别,在这就通过几个例子来解释一下。

以一个简单的串行流水线寄存器为例:d-q1-q2-q3.

1,采用阻塞赋值

代码:always @ (posedge clk) begin q1=d; q2=q1; q3=q2; end

这样的代码将会导致每一个寄存器输出都是d,即d将无延时的传送给q3(即q3=d)。因为采用的是阻塞赋值,当时钟上升沿到来时,先执行q1=d,再执行q2=q1。以此类推,最后所以寄存器的值都变成了d.反映到电路中的结果就是一个单独的直接从d到q3的寄存器,不符合流水线要求。

2,依然采用阻塞赋值,但是赋值顺序有变化

代码:always @ (posedge clk) begin q3=q2; q2=q1; q1=d; end

当我们改变赋值顺序后,综合的电路是符合要求的。当上升沿到来,先执行q3=q2,则q3的值是上一个时钟沿时q2的值。类似的,当上升沿到来后,每个寄存器的值都往后移动了一位,也就实现了预期的流水线结构。但是这样的缺点就在于我们要仔细的安排赋值的顺序,容易出错,且增加工作量。

3,采用非阻塞赋值

代码:always @ (posedge clk) begin q1<=d; q2<=q1; q3<=q2; end

由于非阻塞赋值是并发执行的,当时钟沿到来时,每个寄存器更新的值都是赋值寄存器在上一个时钟沿所被赋予的值,也就真正实现了流水线的结构。而且采用非阻塞赋值的好处在于,不用想阻塞赋值一样需要考虑赋值顺序问题。

另外一个问题是,为什么在组合逻辑中需要使用阻塞赋值?

在大多数情况下,都应该使用非阻塞赋值,这也比较符合电路并发执行的特点。但是在组合逻辑中并不一定。

例如:

always @ (a or b or c or d) begin

temp1<=a & b;

temp2<=c & d;

y<=temp1 | temp2;

end

在这个组合逻辑中,我们希望实现的是先将ab相与,cd相与,再将产生的temp1,temp2相或。但由于采用的是非阻塞赋值,是并发执行的。当执行y<=temp1 | temp2时,temp1,temp2的值并未更新,也就是说y输出的是上一个触发时temp1 | temp2的值,即延后了一次触发。

而如果此时采用阻塞赋值的话,则能正确实现电路。

不过对于这个问题,我还是觉得并不是说组合逻辑导致要使用阻塞赋值,而是说电路功能决定到底使用哪种。即便上面的例子是时序电路,如果要实现相同的逻辑,则依然要用阻塞赋值。而如果你是使用类似之前提到的移位的功能,则即便用的是组合逻辑,也需要用非阻塞赋值。

至于为什么会有组合电路用阻塞的说法,应该是大部分时候组合逻辑功能需要阻塞赋值,且这是一个规范吧,毕竟规范有时候不是很好解释,但是却在工作中大有裨益。当然,这只是我个人观点,有不同意见者希望不吝指教。

以上是关于verilog阻塞赋值和非阻塞赋值的区别的主要内容,如果未能解决你的问题,请参考以下文章

verilog阻塞赋值和非阻塞赋值的区别

verilog中为啥非阻塞赋值要用绝对时延

阻塞赋值和非阻塞赋值有何区别

在 verilog中的非阻塞赋值在啥时候赋值时刻结束?

verilog中时序逻辑和非阻塞赋值的内在联系是啥? 都说时序逻辑用非阻塞赋值,这是啥决定的?

在verilog HDL语言中的阻塞赋值和非阻塞赋值究竟有啥不同?同一变量在不同的过程块中(同时触发)又是如