本文已参与「新人创作礼」活动,一起开启掘金创作之路。
声明向量(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 取反后放在下半部分
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