阻塞与非阻塞赋值
概念:
RHS--赋值等号右边的表达式或者变量; LHS--赋值等号左边的表达式或变量.
阻塞赋值(=)--当赋值发生时,先计算RHS的值,这时赋值语句不允许任何别的Verilog语句的干扰,直到现行的赋值完成时刻,即RHS 赋值给LHS的时刻,才允许其他赋值语句执行.
非阻塞赋值(<=)--在赋值操作开始时刻计算非阻塞赋值符的RHS值,赋值操作结束时才更新LHS.期间,其他的Verilog语句,包括其他 非Verilog非阻塞赋值语句同时计算RHS以及更新LHS,此过程可看做两个步骤:
(1)在赋值开始时刻,计算非阻塞赋值RHS的值;
(2)在赋值结束时刻,更新给阻塞赋值LHS的值.
原则:
(1)在描述组合逻辑的always块中用阻塞赋值,则综合成组合逻辑的电路结构;
(2)在描述时序逻辑的always块中用非阻塞赋值,则综合成时序逻辑的电路结构;
(3)在同一个always块中不要既用非阻塞赋值又用阻塞赋值;
(4)不要在一个以上的always块中为同一个变量赋值;
思路:
把三个数的和赋给一个数,赋值中间再加一个中转便于比较.此过程在时序下进行,
阻塞赋值:
代码:(情形1)
仿真与综合(Analysis & Synthesis)之后生成RTL Viewer为:
将赋值语句顺序改变:(情形2)
RTL Viewer变为:(多了一个d寄存器)
非阻塞赋值:
非阻塞赋值1:(情形3)
RTL Viewer:(和上图阻塞赋值没区别)
变换赋值顺序后:(情形4)
RTL Viewer:(Surprise!)
竟然仍生成了寄存器d.(这就是非阻塞赋值的秘密嘛?! ~Just wait and see.
testbench如下:
由上RTL Viewer可见,总共只有两种电路结构,
直接当前代码(情形4)仿真得到:
直接看没什么问题,放大后看:
在延迟1ns之后的下个时钟上升沿,out并没有立即改变为实际a(0) + b(1) + c(0) = 01,而是又等了一个执行信号(时钟上升沿)才改变为应有的值01,这是为什么呢???
加入子模块block_nonblock的波形再观察:
通过观察发现,此时d已发生值改变为a(0) + b(1) = 01,而out值被更新了一次为(00),却并没有符合实际out的值.猜测这应该就是非阻塞赋值的问题.这里因为Quartus Prime 高版本已经不支持门级仿真了,所以这里将代码改为这样:
模拟了一下实际的电路延迟
观察发现,在d值发生变化的同时, out值也发生更新,但值明显不是更新后的d(01) + c(0)应该得到的值,所以非阻塞赋值因为没有赋值阻塞,当d被赋值的同时out也被赋值,但out = d + c(0)却是上一个时钟沿的d值(00),此刻的d值改变并没有影响到out,此时的d值(01)在下个时钟信号到来的同时才被给与到out.以上极为非阻塞赋值的特点,联想到阻塞赋值应该在d值发生变化之后立刻响应到out,因为d在被赋值时out在等待d赋值,待其结束赋值才开始操作,若如此,辣么第二种电路写法应该有问题,将模块代码更改:(情形1)
再进行仿真
结果完全符合猜想,阻塞赋值out响应d值变化,实际电路中会有电路延迟,但两值也会同时发生变化.
究其缘由,是因为阻塞逻辑(=)赋值时,其后的赋值语句在等待其赋值完毕,才开始赋值,所以当连续赋值时,顺序显得尤为重要,否则会发生冒险竞争;而非阻塞赋值因为有寄存器的电路生成,寄存器储存赋值结果,不用担心时序下的赋值顺序,保证了电路的时序稳定.
若非要用阻塞赋值,可改为:
即可有效达到目的,避免出错!(以上内容基本学自小梅哥学PGFA)