Verilog HDL 基础知识

⚠ 转载请注明出处:作者:ZobinHuang,更新日期:Jan.30 2022


知识共享许可协议

    本作品ZobinHuang 采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可,在进行使用或分享前请查看权限要求。若发现侵权行为,会采取法律手段维护作者正当合法权益,谢谢配合。


目录

有特定需要的内容直接跳转到相关章节查看即可。

正在加载目录...

基础

模块与连续型赋值

1
2
3
module top_module( input in, output out );
assign out = in;
endmodule

    使用上面的方法来定义一个模块,把模块的输入输出端口声明在模块名称后的括号中,使用 inputoutput 关键字来完成声明。

    使用 assign left_side = right_side 定义 连续赋值。连续赋值可以理解为在物理上完成了连线,因此只要 right_side 的值发生改变,left_side 的值就会发生改变,这不是一个 one-time event。

门电路

NOT Gate

1
2
3
4
5
6
module top_module(
input in,
output out
);
assign out = ~in;
endmodule

    使用 ~ 符号来声明一个非门。

AND Gate

1
2
3
4
5
6
module top_module( 
input a,
input b,
output out );
assign out = a & b;
endmodule

    符号 & 用于实现 按位与 (Bitwise-AND),符号 && 用于实现 逻辑与 (Logical-AND)

NOR Gate

1
2
3
4
5
6
module top_module( 
input a,
input b,
output out );
assign out = ~(a|b);
endmodule

    符号 | 用于实现 按位或 (Bitwise-OR),符号 || 用于实现 逻辑或 (Logical-OR)

XNOR Gate

1
2
3
4
5
6
module top_module( 
input a,
input b,
output out );
assign out = ~(a^b);
endmodule

    符号 ^ 用于实现 按位异或 (Bitwise-XOR)。没有逻辑异或的说法。

Wire

    当电路稍微复杂时,输出端口和输入端口之间不再是简单的连接关系,此时就需要在数字模块中声明 wire。上图所示电路的示例代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
module top_module (
input in, // Declare an input wire named "in"
output out // Declare an output wire named "out"
);

wire not_in; // Declare a wire named "not_in"

assign out = ~not_in; // Assign a value to out (create a NOT gate).
assign not_in = ~in; // Assign a value to not_in (create another NOT gate).

endmodule // End of module "top_module"

Verilog 数据类型

Net-Type

    上面介绍的 wire 是 Verilog Net (线网) 类型信号中的一种。声明为 Net Type 的信号描述了数字模块中各部分的物理连接,这些信号本身并不存储数据。除了 wire 之外,Net Type 还包括其它类型,但是最常用的还是 wire

Variable-Type

    Verilog 的另一种信号类型是 Varilable (变量) 类型数据。与 Net Type 相反的是,声明为 Variable-Type 的信号在设计中常被用于暂存数据,我们在后面介绍时序逻辑电路的 Verilog 代码时将会大量看到这种类型的信号。常用的 Variable-Type 的信号是 reg

Vectors

Vectors

    Vectors 用于聚合相关联的信号线,可以理解为信号的 "数组"。上图所示电路的示例代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
module top_module ( 
input wire [2:0] vec,
output wire [2:0] outv,
output wire o2,
output wire o1,
output wire o0 ); // Module body starts after module declaration
assign outv = vec;
assign o2 = vec[2];
assign o1 = vec[1];
assign o0 = vec[0];
endmodule

    可见,Vectors 的命名规范是 type [upper:lower] vector_name,如下所示是各种 Vector 的例子:

1
2
3
4
5
6
wire [7:0] w;         // 8-bit wire
reg [4:1] x; // 4-bit reg
output reg [0:0] y; // 1-bit reg that is also an output port (this is still a vector)
input wire [3:-2] z; // 6-bit wire input (negative ranges are allowed)
output [3:0] a; // 4-bit output wire. Type is 'wire' unless specified otherwise.
wire [0:7] b; // 8-bit wire where b[0] is the most-significant bit.

    一个 Vector 的 Endianness (字节顺序) 在定义的时候就被确定了:小端 (i.e. 低信号线拥有更低的序号,比如 [3:0]) 或者 大端 (i.e. 低信号线拥有更高的序号,比如 [0:3])。

Implicit Nets

    Implicit Nets 是很多 bug 产生的地方。在如下的两种情况中,Verilog 可能会隐式地创建 Net-type 的信号线:

  1. 将一个 Vector 连续赋值给一个未声明过的信号线,则 Verilog 会将这条信号线隐式声明为 wire,如下的 b:
    1
    2
    3
    4
    wire [2:0] a, c;   // Two vectors
    assign a = 3'b101; // a = 101
    assign b = a; // b = 1 隐式创建的 wire
    assign c = b; // c = 001 c 被赋值为 001,而不是期待的 101
  2. 将未声明的信号线与某个模块的端口相连接,则 Verilog 会将这些信号线隐式声明为 wire,如下的 de:
    1
    2
    3
    // d and e are implicitly one-bit wide if not declared.
    // This could be a bug if the port was intended to be a vector.
    my_module i1 (d,e);

    使用 `default_nettype 指令可以取消 Verilog 自动隐式地创建 Net-type 的信号线,从而在综合的时候就能尽快地发现错误。

Packed 和 Unpacked 的 Arrays

    当我们把 Indices (i.e. 大小和字节顺序信息) 写在名称之前时,我们实际上定义的是 Vector,在 SystemVerilog 中也被称为 Packed Array。正如我们上面阐述的那样,Vector 描述的是相关联的一组信号,例子如下所示:

1
wire [2:0] a;

    相反地,当我们把 Indices 信息写在名称之后时,我们实际上定义的是 Unpacked Array。例子如下所示:

1
reg mem2 [28:0];  // 29 unpacked elements, each of which is a 1-bit reg

    Unpacked Array 的元素可以是 Packed Array,如下定义所示:

1
reg [7:0] mem [255:0];  // 256 unpacked elements, each of which is a 8-bit packed vector of reg.

Bitwise Operators

    

xxx