Verilog的过程赋值

简介: 过程性赋值是在 initial 或 always 语句块里的赋值,赋值对象是寄存器、整数、实数等类型。这些变量在被赋值后,其值将保持不变,直到重新被赋予新值。连续性赋值总是处于激活状态,任何操作数的改变都会影响表达式的结果;过程赋值只有在语句执行的时候,才会起作用。这是连续性赋值与过程性赋值的区别。Verilog 过程赋值包括 2 种语句:阻塞赋值与非阻塞赋值。

1、关键词:阻塞赋值,非阻塞赋值,并行

过程性赋值是在 initial 或 always 语句块里的赋值,赋值对象是寄存器、整数、实数等类型。

这些变量在被赋值后,其值将保持不变,直到重新被赋予新值。

连续性赋值总是处于激活状态,任何操作数的改变都会影响表达式的结果;过程赋值只有在语句执行的时候,才会起作用。这是连续性赋值与过程性赋值的区别。

Verilog 过程赋值包括 2 种语句:阻塞赋值与非阻塞赋值。

2、阻塞赋值

阻塞赋值属于顺序执行,即下一条语句执行前,当前语句一定会执行完毕。

阻塞赋值语句使用等号 = 作为赋值符。

前面的仿真中,initial 里面的赋值语句都是用的阻塞赋值。

3、非阻塞赋值

非阻塞赋值属于并行执行语句,即下一条语句的执行和当前语句的执行是同时进行的,它不会阻塞位于同一个语句块中后面语句的执行。

非阻塞赋值语句使用小于等于号 <= 作为赋值符。

利用下面代码,对阻塞、非阻塞赋值进行仿真,来说明 2 种过程赋值的区别。

`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。

网络异常,图片无法展示
|

4、使用非阻塞赋值避免竞争冒险

上述仿真代码只是为了让读者更好的理解阻塞赋值与非阻塞赋值的区别。实际 Verilog 代码设计时,切记不要在一个过程结构中混合使用阻塞赋值与非阻塞赋值。两种赋值方式混用时,时序不容易控制,很容易得到意外的结果。

更多时候,在设计电路时,always 时序逻辑块中多用非阻塞赋值,always 组合逻辑块中多用阻塞赋值;在仿真电路时,initial 块中一般多用阻塞赋值。

如下所示,为实现在时钟上升沿交换 2 个寄存器值的功能,在 2 个 always 块中使用阻塞赋值。

因为 2 个 always 块中的语句是同时进行的,但是 a=b 与 b=a 是无法判定执行顺序的,这就造成了竞争的局面。

但不管哪个先执行(和编译器等有关系),不考虑 timing 问题时,他们执行顺序总有先后,最后 a 与 b 的值总是相等的。没有达到交换 2 个寄存器值的效果。

always @(posedge clk) begin
    a = b ;
end
always @(posedge clk) begin
    b = a;
end

但是,如果在 always 块中使用非阻塞赋值,则可以避免上述竞争冒险的情况。

如下所示,2 个 always 块中语句并行执行,赋值操作右端操作数使用的是上一个时钟周期的旧值,此时 a<=b 与 b<=a 就可以相互不干扰的执行,达到交换寄存器值的目的。

always @(posedge clk) begin
    a <= b ;
end
always @(posedge clk) begin
    b <= a;
end

当然,利用下面代码也可以实现交换寄存器值的功能,但是显然不如在 always 块中直接用非阻塞赋值简单直观。

always @(posedge clk) begin
    temp    = a ;
    a       = b ;
    b       = temp ;
end

5、源码下载

Download

相关文章
|
8月前
|
C语言
【C语言】简易计算器转移表(函数指针简化)
【C语言】简易计算器转移表(函数指针简化)
58 0
|
4月前
|
C语言
C语言判断逻辑的高阶用法
在C语言中,高级的判断逻辑技巧能显著提升代码的可读性、灵活性和效率。本文介绍了六种常见方法:1) 函数指针,如回调机制;2) 逻辑运算符组合,实现复杂条件判断;3) 宏定义简化逻辑;4) 结构体与联合体组织复杂数据;5) 递归与分治法处理树形结构;6) 状态机管理状态转换。通过这些方法,可以更高效地管理和实现复杂的逻辑判断,使代码更加清晰易懂。
253 88
|
7月前
|
C语言
【C语言基础篇】结构控制(中)循环结构
【C语言基础篇】结构控制(中)循环结构
|
C语言 异构计算
【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句
【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句
66 0
|
8月前
|
C语言
c语言循环设计程序结构
c语言循环设计程序结构
50 0
|
算法 C语言
C语言基本结构:顺序、选择和循环
C语言基本结构:顺序、选择和循环
194 0
|
C语言
C语言流程结构之循环语句(一)
C语言流程结构之循环语句(一)
C语言程序入门——if-else及switch分支结构与for、do-while循环1.1.2
当表达式值为”真“时,循环执行,直到表达式的值为”假“,循环终止并继续执行while的下一条语句。循环与while有所不同,while循环如果一开始条件不满足,则循环一次都不不执行,而do-while先执行循环体,后判断循环条件,无论赋值条件的值如何,执行流程,先求表达式1,若为真,则执行语句1,并结束整个if语句的执行,否则,求解表达式2······直到表达式n-1都为假时,最后执行语句n。可由一个if语句构成,用来进行分支选择,表达式条件成立,则进行if中的语句,反之,无任何操作行为。.........
Verilog语法入门(二)多bit逻辑门
Verilog HDL是一种硬件描述语言(HDL:Hardware Description Language),以文本形式来描述数字系统硬件的结构和行为的语言,用它可以表示逻辑电路图、逻辑表达式,还可以表示数字逻辑系统所完成的逻辑功能。 Verilog HDL和VHDL是世界上最流行的两种硬件描述语言,都是在20世纪80年代中期开发出来的。前者由Gateway Design Automation公司(该公司于1989年被Cadence公司收购)开发。两种HDL均为IEEE标准。
224 0