Verilog语法学习

428 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

声明向量(Declaring Vectors)

Vectors must be declared:向量必须被声明 type [upper:lower] vector_name;

type指定向量的类型。通常是wire或reg.如果要声明输入或输出端,类型也可以包括(e.g., input or output) 具体实例如下:

wire [7:0] w;         // 8-bit wire  8bit线网
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)              1bit reg类型,这也是一个向量
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.  4bit输出线网类型;除非另有说明,一般都是线网类型
wire [0:7] b;         // 8-bit wire where b[0] is the most-significant bit.   8bit线网;且b[0]是最高有效位

向量的字节序(或非正式的“方向”)是最低有效位是否具有较低的索引(小端序,例如 [3:0])或更高的索引(大端序,例如 [ 0:3])。在 Verilog 中,一旦以特定的字节顺序声明向量,它必须始终以相同的方式使用。例如,在声明vec[0:3]后此时当vec被声明为vec[3:0] 是非法的。与字节序保持一致是一种很好的做法,因为如果将不同字节序的向量分配或一起使用,则会出现奇怪的错误.

Implicit nets (隐性线网)

隐式网络通常是难以检测的错误的来源。在 Verilog 中,网络类型信号可以通过assign语句或通过将未声明的内容附加到模块端口来隐式创建。隐式网络始终是一位线,如果您打算使用向量,则会导致错误。可以使用该 default_nettype none 指令禁用隐式网络的创建。

wire [2:0] a, c; // Two vectors 声明了a和c的两个向量
assign a = 3'b101; // a = 101  a被赋值了是一个3位二进制数101
assign b = a; // b = 1 implicitly-created wire  /*注意这里的b被verilog语法所隐式声明出来的,其是默认位宽为1bit的wire信号,并且默认将a的最低位赋值给了b*/
assign c = b; // c = 001 <-- bug   这里默认把b的值赋值给c,因此c是3位向量,所以c是001
my_module i1 (d,e); // d and e are implicitly one-bit wide if not declared.
如果未声明的话,d和e隐含是一步位宽
// This could be a bug if the port was intended to be a vector.
如果端口是一个向量的话,这可能就是一个bug了

添加default_nettype none 会使第二行代码成为错误,从而使错误更加明显。

声明向量时,位宽写在向量名的前面,它定义 这个向量的维数,即向量所包含的信号位数。对于模拟器而言(与硬件不同),向量的bits被打包到了blob中。不被打包的向量声明在名字后面。这一块初学有点绕,[这里引用B站UP主的观点](HDLBits_Verilog学习笔记Ⅰ——Verilog Language_Vectors - 哔哩哔哩 (bilibili.com))

在声明reg类型时,可以在向量名后面加“维数”,以形成向量组,即存储器。整体看作一个包含若干个向量的向量组,即对应一个存储器。向量名后的可以看作是向量的个数,即有几个同维度的向量。向量就是存储器里面的存储单元。 向量组= 存储器;向量= 存储单元; 向量维数= 存储单元位宽; 向量个数=存储单元个数

reg [7:0] mem [255:0];   // 256 unpacked elements, each of which is a 8-bit packed vector of reg.  即定义了一个存储器,有256个存储单元,地址是0~255,每个存储单元是8bit,即一个字节的大小*/
reg mem2 [28:0];         // 29 unpacked elements, each of which is a 1-bit reg.  即定义了一个存储器,有29个存储单元,每个存储单元是1bit

获取向量元素:部分选择 Accessing Vector Elements: Part-Select

使用向量名称访问整个向量。例如: wire [7:0] w; assign a = 4'b1001; assign w =a 获取整个 4 位向量a并将其分配给整个 8 位向量w(声明取自上面)。如果右侧和左侧的长度不匹配,则将其零扩展或酌情截断。 部分选择运算符可用于访问向量的一部分:

wire [7:0] w;
w[3:0] // 只有 w 的低 4 位
wire[0:7] b;
b[3:0] // 非法。向量部分选择必须与声明的方向相匹配。
b[0:3] // b 的*高* 4 位。
assign w[3:0] = b[0:3]; // 将 b 的高 4 位分配给 w 的低 4 位;w[3]=b[0]、w[2]=b[1]

操作练习题:

Bitwise vs. Logical Operators ( 按位与逻辑运算符)

Build a circuit that has two 3-bit inputs that computes the bitwise-OR of the two vectors, the logical-OR of the two vectors, and the inverse (NOT) of both vectors. Place the inverse of b in the upper half of out_not (i.e., bits [5:3]), and the inverse of a in the lower half. 大白话就是: 构建一个具有两个 3 位输入的电路,用于计算两个向量的按位或、两个向量的逻辑或以及两个向量的非 (NOT)。将b取反后放在(即位 out[5:3])的上半部分,将 a 取反后放在下半部分

image.png

module top_module(
	input [2:0] a, 
	input [2:0] b, 
	output [2:0] out_or_bitwise,
	output out_or_logical,
	output [5:0] out_not
);
	
	assign out_or_bitwise = a | b;
	assign out_or_logical = a || b;

	assign out_not[2:0] = ~a;	// Part-select on left side is o.
	assign out_not[5:3] = ~b;	//Assigning to [5:3] does not conflict with [2:0]
	
endmodule

在这里,需要注意不要将按位取反与逻辑非符号混肴,这两者是不一样的 eg: a = 4'b1110 则a进行非运算是!a=1'b0 这里如何来理解呢! 应该是这样子的,即a现在它不是一个0,那么它的非运算就是一个0