刚开始接触Verilog HDL语言时,这种硬件描述语言有一点与软件的程序设计语言直观上的最大区别大概就是这个赋值语句了(这里只是强调直观上的最大区别,事实上的最大区别并非如此)。

Verilog HDL中的赋值方式有两种:阻塞赋值与非阻塞赋值。

之前也看过很多种解释,例如,阻塞赋值(=)适用于时序电路的设计,非阻塞赋值(<=)适用于组合电路的设计;还有阻塞赋值和非阻塞赋值只是语法上存在的现象等等,这类解释让人云里雾里,似乎没能接触到其精髓。

今日偶看夏宇闻老师的著作《从算法设计到硬件逻辑的实现》,看到这个部分,恍然大悟,瞬间如同醍醐灌顶。记录如下,供大家参考。


请认真看完整体!

1、非阻塞(Non_Blocking)赋值方式(如 b <= a;)

  • 块结束后才完成赋值操作;
  • b的值并不是立刻就改变;
  • 这是一种比较常用的赋值方法。(特别在编写可综合模块时)

2、阻塞(Blocking)赋值方式(如: b = a;)

  • 赋值语句执行完后,块才结束;
  • b的值在赋值语句执行完后立刻就改变;
  • 可能产生意想不到的结果。

非阻塞赋值方式和阻塞赋值方式的区别常给设计人员带来问题。问题主要是给“always”块内的reg型信号的赋值方式不易把握。


如果“always”模块中的reg型信号采用非阻塞赋值方式:

b <= a;

这种方式的赋值并不是马上执行的,也就是说“always” 块内的下一条语句执行后,b并不等于a,而是保持原来的值。“always”块结束后,才进行赋值。


如果采用阻塞赋值方式:

b = a;

这种赋值方式是马上执行的。也就是说,执行下一条语句时,b已经等于a了。尽管这种方式看起来直观,但是可能引起麻烦。


下面对两种赋值方式举例分析:

例1:

非阻塞赋值

always @(posedge clk)
begin

    b <= a;
    c <= b;

end

systemverilog 阻塞赋值和非阻塞赋值 verilog阻塞赋值语句_赋值

上例中的"always"块中用了非阻塞赋值方式,定义了两个reg型信号b和c,clk信号的上升沿到来时,b就等于a,c就等于b,这里应该用到了两个触发器。请注意:赋值是在"always"块结束后执行的,c应为原来b的值,b为原来的a值。这个"always"块实际描述的电路功能如下图所示:

 

systemverilog 阻塞赋值和非阻塞赋值 verilog阻塞赋值语句_赋值_02

systemverilog 阻塞赋值和非阻塞赋值 verilog阻塞赋值语句_非阻塞_03

例2:

阻塞赋值

always @(posedge clk)
begin

    b = a;
    c = b;

end

systemverilog 阻塞赋值和非阻塞赋值 verilog阻塞赋值语句_非阻塞_04

上例中的 "always"块用了阻塞赋值方式。clk信号的上升沿到来时,将发生如下的变化:b马上取a的值,c马上取b的值(即等于a),生成的电路图如下所示只用了一个触发器来寄存器a的值,又输出给b和c。这大概不是设计者的初衷,如果采用[例1]所示的非阻塞赋值方式就可以避免这种错误。

systemverilog 阻塞赋值和非阻塞赋值 verilog阻塞赋值语句_赋值_05

systemverilog 阻塞赋值和非阻塞赋值 verilog阻塞赋值语句_赋值_06