跳转至

2 赋值语句

文本统计:约 2351 个字 • 66 行代码

2.1 连续赋值语句(Continuous Assignments)

连续赋值的主要特点:

(1)语法上,有关键词“assign”来标识,也可以在对wire型变量声明的时候同时对其进行赋值

wire      Cout, A, B ;
assign    Cout  = A & B ;     //实现计算A与B的功能
wire      A, B ;
wire      Cout = A & B ;

(2)续赋值语句不能出现在过程块中(initial/always);

(3)连续赋值语句主要用来对组合逻辑进行建模以及线网数据间进行描述;

(4)左侧被赋值的数据类型必须是线网型数据(wire)

连续赋值语句的左值可以是一下类型之一:

  • 标量线网
  • 向量线网
  • 矩阵中的一个元素(该矩阵可以是标量线网类型的,也可以是向量线网类型的)
  • 向量线网的某一位
  • 向量线网的部分位

以及上述各种类型的拼接体。但是,不能是向量或向量寄存器。

(5)连续赋值语句产生作用后,赋值表达式中信号的任何变化都将立即被反映到赋值线网型数据的取值上;连续赋值语句总是处于激活状态。只要任意一个操作数发生变化,表达式就会被立即重新计算,并且将结果赋给等号左边的线网

(6)操作数可以是标量或向量的线网或寄存器,也可以是函数的调用。

(7)赋值延迟用于控制对线网赋予新值的时间,根据仿真时间单位进行说明。赋值延迟类似于门延迟,对于描述实际电路中的时序是非常重要的。

2.2 过程赋值语句(Procedural Assignments)

过程赋值的主要特点:

(1)语法上,没有关键词assign;

(2)过程赋值语句的左值可以是以下类型之一:

①reg、整形数、实型数、时间寄存器变量或存储器单元

②上述各种类型的位选(例如:addr[3])

③上述各种类型的域选(例如:addr[31:16])

④上面三种类型的拼接

(3)过程赋值语句只能在initial或always语句内进行赋值,只能对变量数据类型赋值,同时initial和always中只能使用过程赋值语句

(4)在过程赋值语句的情况下,只有在过程赋值语句被执行时才执行赋值操作,语句执行完后被赋值变量的取值不再受到赋值表达式的影响, 这些类型的变量在被赋值后,其值将保持不变,直到被其他过程赋值语句赋予新值。过程赋值语句只有在执行到的时候才会起作用。(注意与连续赋值(5)的辨析)

(5)过程性赋值语句包括两种类型的赋值语句:阻塞赋值(=)和非阻塞赋值(<=)。

阻塞赋值与非阻塞赋值

`timescale 1ns/1ns


module test ;
    reg [3:0]   ai, bi ;
    reg [3:0]   ai2, bi2 ;
    reg [3:0]   value_blk ;
    reg [3:0]   value_non ;
    reg [3:0]   value_non2 ;

    initial begin
        ai            = 4'd1 ;   //(1)
        bi            = 4'd2 ;   //(2)
        ai2           = 4'd7 ;   //(3)
        bi2           = 4'd8 ;   //(4)
        #20 ;                    //(5)

        //non-block-assigment with block-assignment
        ai            = 4'd3 ;     //(6)
        bi            = 4'd4 ;     //(7)
        value_blk     = ai + bi ;  //(8)
        value_non     <= ai + bi ; //(9)

        //non-block-assigment itself
        ai2           <= 4'd5 ;           //(10)
        bi2           <= 4'd6 ;           //(11)
        value_non2    <= ai2 + bi2 ;      //(12)
    end

   //stop the simulation
    always begin
        #10 ;
        if ($time >= 1000) $finish ;
    end

endmodule
仿真结果如下:

语句(1)-(8)都是阻塞赋值,按照顺序执行。

20ns 之前,信号 ai,bi 值改变。由于过程赋值的特点,value_blk = ai + bi 并没有执行到,所以 20ns 之前,value_blk 值为 X(不确定状态)。

20ns 之后,信号 ai,bi 值再次改变。执行到 value_blk = ai + bi,信号 value_blk 利用信号 ai,bi 的新值得到计算结果 7。

语句(9)-(12)都是非阻塞赋值,并行执行。

首先,(9)-(12)虽然都是并发执行,但是执行顺序也是在(8)之后,所以信号 value_non = ai + bi 计算是也会使用信号 ai,bi 的新值,结果为 7。

其次,(10)-(12)是并发执行,所以 value_non2 = ai2 + bi2 计算时,并不关心信号 ai2,bi2 的最新非阻塞赋值结果。即 value_non2 计算时使用的是信号 ai2,bi2 的旧值,结果为 4'hF。

2.3 过程连续赋值语句(Procedural Continuous Assignments)

过程连续性赋值语句的主要特点:

(1)过程连续赋值是在过程块内对变量或线网型数据进行连续赋值,是一种过程性赋值,换言之,过程性连续赋值语句是一种能够在always或initial语句块中出现的语句。

(2)这种赋值可以改写所有其他语句对线网或者变量的赋值。这种赋值允许赋值表达式被连续的驱动进入到变量或线网中去;过程性连续赋值语句比普通的过程赋值语句有更高的优先级

(3)过程连续赋值语句有两种类型:

force语句的优先级高于assign 。

①assign和deassign过程性语句:只能用于对寄存器型变量的连续赋值操作,而不能用来对线网型数据进行连续赋值操作;deassign 撤销对某一个寄存器型变量的连续赋值后,该寄存器变量仍然保持deassign操作之前的取值。

assign和deassign语句

assign和deassign语句构成了一类过程性连续赋值语句,只能用于对寄存器类型变量的连续赋值操作,不能用来对线网类型数据进行连续赋值操作。

①assign语句

语法:assign <寄存器类型变量> = <赋值表达式>

assign在执行时,寄存器类型变量将由赋值表达式进行连续驱动,即进入连续赋值状态。如果此时有普通的过程赋值语句对该寄存器变量进行过程赋值操作,由于过程连续赋值语句assign的优先级高于普通过程赋值语句,所以出于连续赋值状态的寄存器变量将忽略普通过程赋值语句对它的过程赋值操作,其逻辑状态仍然由过程连续赋值语句内的赋值表达式所决定

如果先后有两条assign语句对同一寄存器变量进行了过程连续赋值操作,那么第二条assign的执行将覆盖第一条assign的执行效果。

②deassign语句

语法:deassign <寄存器类型变量>

deassign语句是一条撤销连续赋值语句,用来结束对变量的连续赋值操作。当deassign语句执行后,原来由assign语句对该变量进行的连续赋值操作将失效,寄存器变量被连续赋值的状态将得到解除,该变量又可以由普通过程赋值语句进行赋值操作了。这里需要注意一点,当执行该语句撤销对某寄存器变量的连续赋值后,该寄存器变量仍将保持使用该语句之前的原有值。

reg [3:0] out;
initial begin
    out = 4'b0000;          //s0:过程赋值语句
    #10;
    assign out = a & b;     //s1:第一条过程连续赋值语句
    #10;
    assign out = c & d;     //s2:第二条过程连续赋值语句
    assign out = e & f;     //s3:第三条过程连续赋值语句
    deassign out;           //s4:撤销连续赋值语句
end

上述语句执行过程如下:

s0:在0时刻,out被赋值为0,并且保持这个取值;

s1:在10时刻,s1开始执行,实现了对变量out的连续赋值操作,因此从10时刻开始,out将处于连续赋值状态;

s2:在20时刻,s2开始执行,将覆盖s1产生的作用,所以从20时刻开始,out将由c & d连续驱动;

s3:s3操作覆盖掉s2操作;

s4:当deassign语句得到执行,变量out连续赋值状态被解除,其取值将保持最后一次assign语句赋予的值,即“e & f”;

②force和release过程性语句:它不仅能对寄存器型变量产生作用,也对线网型数据产生作用。

force和release语句

force和release语句与assign和deassign语句类似,也是一种过程连续赋值语句。这组赋值语句不仅能对寄存器类型变量产生作用,还能对线网类型数据进行连续赋值操作。

①force语句

语法:force <寄存器变量或者线网数据> = <赋值表达式>;

force语句应用于寄存器类型变量时,则在force语句执行后,该寄存器变量将强制由<赋值表达式>进行连续驱动,进入被连续赋值的状态,此时将忽略其他较低优先级的赋值语句对该寄存器变量的赋值操作,直到执行一条release语句来释放对该寄存器变量的连续赋值为止。

force语句应用于线网数据时,则force语句执行后,对应的线网数据将得到<赋值表达式>的连续驱动,此时将忽略该线网数据上较低优先级的驱动,直到有一条release语句执行为止。

②release语句

语法:release <寄存器变量或者线网数据>

release语句执行后,原先由force语句对变量或者线网施加的过程连续赋值将失效,变量将解除被被连续赋值的状态,较低优先级的赋值语句的赋值操作将有效。

`timescale 1ns/1ps
module test();
    reg [2:0] reg1;
    reg [2:0] reg2;
    initial begin
        reg1 = 3'b000;          //s0:过程赋值语句
        assign reg2 = 3'b001;   //s1过程连续赋值语句
        #10;
        force reg1 = 3'b100;    //s2:过程连续赋值语句
        force reg2 = 3'b100;    //s3:过程连续赋值语句
        #10;
        release reg1;           //s4:撤销连续赋值语句
        release reg2;           //s5:撤销连续赋值语句
    end
endmodule

s0:实现对变量reg1的过程赋值操作,即reg1被赋值为3’b000;

s1:执行assign过程连续赋值语句,用来实现对变量reg2的连续赋值,从而reg2将被连续赋值为3’b001;

s2:在执行本条语句时,reg1未被assign语句进行过连续赋值操作,因此reg1被force连续赋值为3’b100;

s3:执行本条语句后,var_reg2被force连续赋值为3’b100;

s4:执行本条语句时,因为变量reg1将退出连续赋值的状态,因为reg1未曾被assign语句进行过连续赋值操作,故reg1取值保持不变,即保持force状态时的值3’b100;

s5:执行本语句时,因为reg2在执行s3之前已经由s1实现了连续赋值,所以在本条语句s5执行后,变量reg2将恢复到由assign语句s1确定的连续赋值状态,即3’b001;

2.4 赋值语句的区别

(1)连续赋值语句和过程赋值语句之间的区别

语法不同:连续赋值语句由assign来标示,而过程赋值语句不能包含这个关键词;

赋值对象不同:连续赋值语句中左侧的数据类型必须是线网数据类型,而过程赋值语句中的被赋值数据类型则必须是寄存器类型的变量;

出现位置不同:连续赋值语句不能出现在过程块(initial或always)中,而过程赋值语句可以;

连续赋值语句主要用来对组合逻辑电路进行建模以及对线网数据间的连接进行描述,而过程赋值语句主要用来对时序逻辑电路进行行为描述;

赋值时间不同:连续赋值语句对被赋值线网型数据的赋值是“连续”的(即赋值表达式的任何变化都会在立刻反应在线网数据的取值上),而过程性赋值语句,只有在过程赋值语句被执行时才执行赋值操作,语句执行完后被赋值变量的取值不再受到赋值表达式的影响(注意这里的一次是指:在initial块中,过程性赋值只顺序执行一次,而在always块中,每一次满足always的条件时,都要顺序执行一次该always块中的语句。)。

(2)过程连续赋值语句和连续赋值语句之间的区别

出现位置不同:过程连续赋值语句只能用在过程块(initial过程快或always过程块)内,而连续赋值语句不能出现在过程块中。

赋值对象不同:过程连续赋值语句可以对寄存器类型变量进行连续赋值(其中force-release语句还可以对线网进行连续赋值),但是其赋值目标不能是变量或线网的某一位或某几位,而连续赋值语句只能对线网数据进行赋值,赋值目标可以是线网型数据的某一位或某几位。

原文链接:https://blog.csdn.net/michael177/article/details/120810650

评论区

对你有帮助的话请给我个赞和 star => GitHub stars
欢迎跟我探讨!!!