HDLBits刷题日记(三)
打算利用碎片化时间重温一遍Verilog语法,好记性不如烂笔头,在此记录一下HDLBits刷题的过程,记录一些知识点,方便日后再次复习。
1、Verilog Language - Vectors
Problem 10 : Vectors
向量是一组 wire 信号的集合,通过赋予这一组信号的集合一个名称,以便于访问其中的 wire 信号
wire [7:0] w ; // 声明了一个 8 bit 位宽的信号,向量名为 w,等价于 8 个 1bit 位宽的 wire 信号。
请注意声明向量时,位宽位于向量名之前。但在片选向量中某个 bit 时,使用的语法同 C 语言数组中取出某个数的语法相同。
wire [99:0] my_vector; // Declare a 100-element vector
assign out = my_vector[10]; // Part-select one bit out of the vector
在同时声明多个向量时,位宽对于声明的多个向量都是起作用的,比如:
wire [7:0] a, b, c; // Declares three 8-bit vectors
Build a circuit that has one 3-bit input, then outputs the same vector, and also splits it into three separate 1-bit outputs.
构建一个电路,有一个 3 位输入,然后输出相同的向量,并将其分成三个单独的 1 位输出。

module top_module(
input [2:0] vec,
output [2:0] outv,
output o2,
output o1,
output o0
);
assign outv = vec;
// This is ok too: assign {o2, o1, o0} = vec;
assign o0 = vec[0];
assign o1 = vec[1];
assign o2 = vec[2];
endmodule
如果想要片选多个 bit,那么可以通过如下操作实现:
assign w = vec[1:0];
Problem 11 : Vectors in more detail
向量的声明规则如下:
type [upper:lower] vector_name;
其中 type 指定了向量的类型,一般为 wire 或者 reg 型。关于 reg 型,会在后续介绍中引入。如果向量为模块的输入输出端口,那么可以在 type 中添加 input/output 定义。
wire [7:0] w; // 8-bit wire
reg [4:1] x; // 4-bit reg
output reg [0:0] y; // 1-bit reg output port (但仍然是一个向量)
input wire [3:-2] z; // 6-bit wire input (在位宽中使用负数作为 index 是可以的,代表倒数第二位)
output [3:0] a; // 4-bit output wire. wire 为默认定义,在没有显式声明的情况下
wire [0:7] b; // 8-bit wire b[0]是这个向量的 最高位 MSB(most-significant bit)
声明为 [3:0] w 的向量,LSB 是 w[0],如果声明为 [0:3] w,那么 w[3] 是 LSB 。LSB 指的是二进制数中权值最低的一位。
在 Verilog 语法中,可以将向量声明为 [3:0], 这种语法最为常见,但也可以将向量声明为 [0:3]。这都是可以的,但必须在声明和使用时保持一致。如果声明为 wire [3:0] w ,但使用 w[0:3] 赋值,这是不允许的,保持前后如一的比特顺序是很重要的一点。
信号变量有两种声明方式,一是使用 wire 或者 assign 语句进行显示声明和定义,二是综合器的隐式声明和定义。变量隐式声明的危害在于,当你将一个未定义声明的信号连接到模块的输入输出端口时,综合器会“热心”地帮助你声明这个信号,但它只会将其声明为 1 bit wire 型信号。
wire [2:0] a, c; // Two vectors
assign a = 3'b101; // a = 101
assign b = a; // b = 1 implicitly-created wire
assign c = b; // c = 001 <-- bug
my_module i1 (d,e); // 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.
通过添加 `default_nettype none 宏定义会关闭隐式声明功能,那么这样一来,使用未声明的变量就会变成一个 Error 而不再只是 Warning。
unpacked 和 packed 数组:在声明向量时,一般向量的位宽写在向量名之前。位宽定义了向量的 packed 维度,该向量中每位信号都被视作一个块进行操作(在仿真中,硬件中有所不同)。unpacked 维度定义在向量名之后,通常用来定义向量数组长度。
reg [7:0] mem [255:0]; // 256 unpacked elements, each of which is a 8-bit packed vector of reg.
reg mem2 [28:0]; // 29 unpacked elements, each of which is a 1-bit reg.
获取向量元素,也称片选:
通过向量名可以获得整个向量,在下方的 assign 语句中,向量名 a 代表了向量中的所有比特为信号。
wire [7:0] a;
assign w = a;
在 assign 赋值操作中,如果等号左右两侧信号的位宽不同,那么就会进行截断或者补零操作。左侧信号位宽大于右侧信号位宽,右值的低位赋予左值对应的低位,左值高位的部分赋零。左侧信号位宽小于右侧信号位宽,右值的低位赋予左值对应的低位,右值高位的部分直接被截断。即保留右值的低位。
w[3:0] // Only the lower 4 bits of w
x[1] // The lowest bit of x
x[1:1] // ...also the lowest bit of x
z[-1:-2] // Z 最低两位
b[3:0] // 如果 b 在声明时 声明为 wire [0:3] b;则不能使用 b [3:0]进行选择
b[0:3] // b的高四位.
assign w[3:0] = b[0:3]; // 将 b 的高位赋予 w 的低位 w[3]=b[0], w[2]=b[1], etc.
Build a combinational circuit that splits an input half-word (16 bits, [15:0] ) into lower [7:0] and upper [15:8] bytes.
构建一个组合电路,将输入的半字(16 位,[15:0])分为低位 [7:0] 和高位 [15:8] 字节。
`default_nettype none // Disable implicit nets. Reduces some types of bugs.
module top_module(
input wire [15:0] in,
output wire [7:0] out_hi,
output wire [7:0] out_lo );
assign out_hi = in[15:8];
assign out_lo = in[7:0];
endmodule
Problem 12 : Vector part select
A 32-bit vector can be viewed as containing 4 bytes (bits [31:24], [23:16], etc.). Build a circuit that will reverse the byte ordering of the 4-byte word.
一个 32 位向量可以看作包含 4 个字节(位 [31:24], [23:16], etc.)。构建一个电路,将 4 字节的字节顺序反转。
AaaaaaaaBbbbbbbbCcccccccDddddddd => DdddddddCcccccccBbbbbbbbAaaaaaaa
module top_module(
input wire [31:0] in,
output wire [31:0] out );
assign out[31:24] = in[7:0];
assign out[23:16] = in[15:8];
assign out[15:8] = in[23:16];
assign out[7:0] = in[31:24];
//或者使用{}拼接符
// assign out = {in[7:0], in[15:8], in[23:16], in[31:24]};
endmodule
Problem 13 : Bitwise 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_not 的上半部分(即,位 [5:3]),将 a 的逆放在下半部分。

module top_module(
input [2:0] a,
input [2:0] b,
output [5: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 = {~b, ~a};
endmodule
Problem 14 : Four-input gates
Build a combinational circuit with four inputs, in[3:0]. There are 3 outputs:
out_and: output of a 4-input AND gate. out_or: output of a 4-input OR gate.out_xor: output of a 4-input XOR gate
构建一个具有四个输入 in[3:0] 的组合电路。有 3 个输出:
out_and:4 输入 AND 门的输出。out_or:4 输入 OR 门的输出。out_xor:4 输入 XOR 门的输出。
module top_module(
input [3:0] in,
output out_and,
output out_or,
output out_xor
);
assign out_and = ∈
assign out_or = |in;
assign out_xor = ^in;
// 繁琐点的写法
// assign out_and = in[3] & in[2] & in[1] & in[0];
endmodule