阻塞赋值和非阻塞赋值
时隔一年,再次学习阻塞赋值和非阻塞赋值,温故知新,醍醐灌顶。搜集多方资料,汇总于此,共同学习。希望对大家有所帮助。
《Verilog数字系统设计教程》第3版 夏宇闻
4.9 赋值语句和块语句
4.9.1 赋值语句
在Verilog HDL语言中,信号有两种赋值方式:
- 非阻塞(Non_Blocking)赋值方式(如b <= a;)
(1)在语句块中,上面语句所赋的变量值不能立即就为下面的语句所用;
(2)块结束后才能完成这次赋值操作,而所赋的变量值是上一次赋值得到的;
(3)在编写可综合的时序逻辑模块时,这是最常用的赋值方法。 - 阻塞(Blocking)赋值方式(如b = a;)
(1)赋值语句执行完后,块才结束;
(2)b的值在赋值语句执行完后立刻就改变的;
(3)在时序逻辑中使用时,可能会产生意想不到的结果。
非阻塞赋值方式和阻塞赋值方式的区别常给设计人员带来问题。问题主要是对“always”块内的reg型信号的赋值方式不易把握。到目前为止,前面所举的例子中的“always”模块内的reg型信号都是采用下面的这种赋值方式:
b <= a;
这种方式的赋值并不是马上执行的,也就是说,“always”块内的下一条语句执行后,b并不等于a,而是保持原来的值,“always”块结束后,才进行赋值。而阻塞赋值方式,如下所示:
b = a;
这种赋值方式是马上执行的,也就是说执行下一条语句时,b已等于a。尽管这种方式看起来很直观,但是可能引起麻烦。下面举例说明。
【例4.1】
always @(posedge clk)
begin
b <= a;
c <= b;
end
【例4.1】的“always”块中用了非阻塞赋值方式,定义了两个reg型信号b和c。clk信号的上升沿到来时,b就等于a,c就等于b,这里用到了两个触发器。
注意:赋值是在“always”块结束后执行的,c应为原来b的值。这个“always”块实际描述的电路功能如下图所示。
【例4.2】
always @(posedge clk)
begin
b = a;
c = b;
end
【例4.2】中的“always”块用了阻塞赋值方式。clk信号的上升沿到来时,将发生如下的变化:b马上取a的值,c马上取b的值(即等于a),生成的电路如图4.2所示,图中只用了一个触发器来寄存a的值,又输出给b和c。这大概不是设计者的初衷,如果采用【例4.1】所示的非阻塞赋值方式就可以避免这种错误。图4.2为阻塞赋值方式的“always”块图。
关于赋值语句更详细的说明请参阅第二部分第14章中“深入理解阻塞和非阻塞赋值”一节。
于是我又去看了第14章,下面截取一部分放上来。
第14章 深入理解阻塞和非阻塞赋值的不同
14.2 Verilog模块编程要点
下面将对阻塞和非阻塞赋值做进一步解释并将举更多的例子来说明这个问题。在此之前,掌握可综合风格的Verilog模块编程的以下8个原则对读者会有很大的帮助。在编写Verilog代码时必须牢记这8个要点,才能在综合布局布线后的仿真中避免出现冒险竞争现象。
(1)时序电路建模时,用非阻塞赋值。
(2)锁存器电路建模时,用非阻塞赋值。
(3)用always块建立组合逻辑模型时,用阻塞赋值。
(4)在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值。
(5)在同一个always块中不要既用非阻塞赋值又用阻塞赋值。
(6)不要在一个以上的always块中为同一个变量赋值。
(7)用$strobe系统任务来显示用非阻塞赋值的变量值。
(8)在赋值时不要使用 #0 延迟。
在后面的讲解中还要对为什么必须记住这些要点再做进一步的解释。Verilog的新用户在彻底搞明白这两种赋值功能差别之前,一定要牢记这几条要点。按照要点来编写Verilog模块程序,就可省去很多麻烦。
14.5 移位寄存器模型




《Verilog HDL高级数字设计(第二版)》Michael D. Ciletti
5.8行为建模方式的比较
5.8.2 数据流/寄存器传输级模型



硬禾学堂class.eetree.cn
阻塞赋值

逻辑上是会因为阻塞而按顺序执行的
物理上,硬件上实现的时候会被优化掉,因为它其实就是同一根线
那如果强行保留呢?——
那a, b, c谁更快呢?——

不一定!要看布局走线,实际的电路谁离得近(线路短),谁离得远(线路长)。【还有制造工艺、电压、温度等等因素】

阻塞赋值建议在组合逻辑中使用。
非阻塞赋值

din要经过3个clk传递给c。