【转】Verilog阻塞与非阻塞赋值使用要点

Verilog阻塞与非阻塞赋值使用要点

原文链接:http://hi.baidu.com/52017/item/ff5aa1d0434069312b35c79f

越是看似简单、经常接触的。我们越是不知其所以然。这就是我写本文的原因。
        阻塞和非阻塞赋值一般使用在进程中,包括always和initial进程、assign赋值等操作中。
        在Verilog HDL中,描述进程的基本语句是always和initial。always过程反复执行其中的块语句,而initial过程语句只执行一次。此外,一个assign赋值语句,一个实例元件的调用也都是一个独立的进程。
        进程只有两种状态,即执行状态和等待状态,一旦满足特定的条件,如敏感变量发送变化,进程即进入执行状态,执行完毕或遇到停止语句后,即停止执行,自动返回到起始语句,进入等待状态。

在进行数字系统设计的时候,应该注意以下几点:
        将硬件电路的行为以合理的方式映射为一些进程,对每个进程,以最合理的方式描述并实现。
        将组合逻辑实现的电路和用时序逻辑实现的电路尽量分配到不同的进程中。
        进程中输出的信号在各种可能的情况下都应该被赋值,且赋值号右端不再出现该信号。
        多个进程之间通过信号线进行通信,在设计中,为了达到多个进程协调运行,可以设置一些握手信号,在进程中检测这些握手信号的状态,以决定是否进行必要的操作。在有的设计中,这种握手信号的协调是必不可少的。
        一个进程中一般只描述对应于一个时钟信号的同步时序逻辑。
        进程必须由敏感信号的变化来启动,因此必须精心选择进程敏感表达式中的敏感变量。
——

阻塞赋值与非阻塞赋值

    always @(event-expression)

        begin     <LHS1=RHS1>

                      <LHS2=RHS2>

          ......   

        end

同样可将采用非阻塞赋值方式的always进程块写成下面的形式:

    always @(event-expression)

        begin     <LHS1<=RHS1>

                      <LHS2<=RHS2>

       ......

        end

        阻塞赋值“=”与非阻塞赋值“<=”的本质区别在于:非阻塞赋值语句右端表达式计算完后并不立即赋值给左端,而是同时启动下一条语句继续执行,我们 可以将其理解为所有的右端表达式RHS1、RHS2等在进程开始时同时计算,计算完后 ,等进程结束时同时分别赋给左端变量LHS1、LHS2等。
        而阻塞赋值语句在每个右端表达式计算完后立即赋给左端变量,即赋值语句LHS1=RHS1执行完后LHS1是立即更新的,同时只有LHS1=RHS1执行 完后才可执行语句LHS1=RHS2,依次类推。前一条语句的执行结果直接影响到后面语句的执行结果。
        非阻塞赋值不能用于“assign”持续赋值中。阻塞赋值则既能用于“assign”持续赋值,也能用于“initial”和“always”等过程块 中,阻塞赋值则技能用于“assign”持续赋值,也嗯那个用于“initial”和“always”等过程赋值中。
对于时许逻辑描述和建模,应尽量使用非阻塞赋值方式。

——
用阻塞赋值方式描述了一个移位寄存器:

EX1:

module weise1(Q0,Q1,Q2,Q3,din,clk);
output Q0,Q1,Q2,Q3;
input clk,din;
reg Q0,Q1,Q2,Q3;
always @(posedge clk)
    begin
    Q3=Q2;
    Q2=Q1;
    Q1=Q0;
    Q0=din;
    end
endmodule

其RTL综合结果:

——


——

将上面例子中的阻塞赋值语句保持不变,仅仅将其两条语句的排列顺序改一下的话,则综合器综合的结果就会大不同。

EX2:

module weise1(Q0,Q1,Q2,Q3,din,clk);
output Q0,Q1,Q2,Q3;
input clk,din;
reg Q0,Q1,Q2,Q3;
always @(posedge clk)
    begin
    Q3=Q2;
    Q1=Q0;
    Q2=Q1;
    Q0=din;
    end
endmodule

其RTL综合结果:


——

将四条阻塞赋值语句的顺序完全颠倒的话,则综合器实际上等效成一个触发器。

EX3:

module weise1(Q0,Q1,Q2,Q3,din,clk);
output Q0,Q1,Q2,Q3;
input clk,din;
reg Q0,Q1,Q2,Q3;
always @(posedge clk)
    begin
    Q0=din;
    Q1=Q0;
    Q2=Q1;
    Q3=Q2;
    end
endmodule

其RTL综合结果:


——

        而用非阻塞赋值方式描述的移位寄存器,无论将其“always”过程块中四条赋值语句的顺序怎么变动,均不会影响其综合几个,其结果与第一个例子的结果相 同。对于时许逻辑描述和建模,应尽量使用非阻塞赋值方式。此外,若在同一个“always”过程块中描述时许和组合逻辑混合电路时,也最好使用非阻塞赋值 方式。

——

        非阻塞赋值不能用于“assign”持续赋值中,一般只出现在“initial”和“always”等过程块中,对reg型变量进行赋值。像assign out<=a+b;这样的语句是错误的。
        当用“always”块来描述组合逻辑时,既可以用阻塞赋值,也可以采用非阻塞赋值。但在同一个过程块中,最好不要同时用阻塞赋值和非阻塞赋值,虽然同时使用这两种赋值方式在综合时并不一定会出错。
在向函数(function)的返回值赋值时,应使用阻塞赋值“=”。
        不能在一个以上的“always”过程块中对同一个变量赋值,这样会引起冲突,在综合时会报错。
        在一个模块中,严禁对同一个变量既进行阻塞赋值,又进行非阻塞赋值,这样在综合时会报错。
        对时序逻辑描述和建模,应尽量使用非阻塞赋值方式,此外,若在同一个“always”过程块中描述时序和组合逻辑混合电路时,也最好使用非阻塞赋值方式。

——

原文地址:https://www.cnblogs.com/ymir/p/3076187.html