Vectors
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 in more detail
Vectors must be declared:
type [ upper : lower ] vector_name;
There are some declaring vectors examples:
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.(0 是最高位)
3'b101
的含义
assign a = 3'b101; // a = 101
3'
:指定数值的位宽为 3 位。b
:表示后续数值为二进制(binary)格式。101
:二进制数值本身,对应十进制的 5。
Implicit nets
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
赋值过程:
assign a = 3'b101;
→a
的值为101
(十进制 5)。assign b = a;
→ 隐式创建了 1 位 wireb
,并将a
的最低位(a[0]
)赋给b
。
(Verilog 中,未声明的标识符会被隐式创建为 1 位 wire,且高位自动截断。)assign c = b;
→ 将 1 位的b
(值为1
)扩展为 3 位赋值给c
。
由于b
只有 1 位,高位补零后c
的值变为001
(十进制 1)。
`default_nettype none
指令
功能:
- 禁止隐式网络生成:在 Verilog 中,如果使用了未经声明的标识符,系统会默认将其创建为 1 位宽的 wire 类型。而
default_nettype none
指令会阻止这种隐式创建,一旦遇到未声明的标识符,编译器就会报错。 - 提高代码可靠性:通过这种方式,可以有效避免因拼写错误或者变量未声明而引发的难以察觉的问题。
使用方法:
`default_nettype none // 后续代码
module my_module(input a, input b, output c);
wire sum; // 必须显式声明
wire assign c = sum + b; // 如果sum未声明,编译器会报错
endmodule
Unpacked vs. Packed Arrays
Blob = Binary Large Object(二进制大对象):
这是计算机科学中的术语,指一组连续的二进制数据。在 Verilog 语境中,"blob" 强调:- 位的连续性:压缩数组的所有位在内存中是连续的,不可单独访问(例如不能只修改其中几位而不影响其他位)。
- 不可分割性:在模拟器中,整个数组被视为一个整体,而非独立的位集合。
- 与硬件的区别:
在硬件中,压缩数组可能映射到实际的寄存器或总线(例如 8 位寄存器),但 "blob" 的概念更侧重于模拟器中的表示方式,而非物理实现。
- 压缩数组(位宽声明在前)
wire [7:0] data; // 8位压缩数组(1个8位寄存器)
reg [3:0][7:0] matrix; // 压缩多维数组(4个8位寄存器)
解释:
[7:0]
在变量名data
前,声明一个 8 位向量,所有位连续存储。matrix
的维度为[3:0][7:0]
,表示 4 个 8 位寄存器,在模拟器中视为一个 32 位的整体(4×8=32
位)。
- 非压缩数组(维度声明在后)
reg [7:0] memory [0:255]; // 256个8位存储单元(非压缩)
wire [3:0] array [0:7]; // 8个4位元素
解释:
memory
是一个 256×8 位的存储器,[0:255]
在变量名后,表示有 256 个独立的 8 位存储单元。- 每个元素(如
memory[0]
、memory[1]
)在硬件中可能对应不同的物理地址。
Accessing Vector Elements: Part-Select
位宽不匹配时的处理规则
当赋值语句左右两侧的位宽不一致时,Verilog 会按以下规则处理:
1. 右侧位宽 < 左侧位宽 → 零扩展(Zero-Extend)
- 规则:在右侧向量的高位补零,使其位宽与左侧匹配。
示例:
wire [7:0] w; // 左侧:8位 wire [3:0] a; // 右侧:4位 assign w = a; // 自动零扩展为8位:a[3:0] → w[7:0] = {4'b0, a}
- 若
a = 4'b1010
,则w = 8'b0000_1010
。
2. 右侧位宽 > 左侧位宽 → 截断(Truncate)
- 规则:丢弃右侧向量的高位,只保留与左侧位宽相同的低位部分。
示例:
wire [3:0] w; // 左侧:4位 wire [7:0] a; // 右侧:8位 assign w = a; // 自动截断为4位:a[7:0] → w[3:0] = a[3:0]
- 若
a = 8'b1111_1010
,则w = 4'b1010
(丢弃高位1111
)。
3. 符号数的扩展(Signed Extension)
- 规则:若右侧是有符号数(用
reg signed
或wire signed
声明),扩展时补符号位(而非零)。 - 示例:
wire signed [3:0] a; // 4位有符号数
wire signed [7:0] w; // 8位有符号数
assign w = a; // 符号扩展:a[3]为符号位
- 若
a = 4'b1010
(十进制 - 6),则w = 8'b1111_1010
(仍为 - 6)。
Solution
`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[7:0] = in[15:8];
assign out_lo[7:0] = in[7:0];
endmodule
Vectors part select
Solution
module top_module(
input [31:0] in,
output [31:0] out );//
// assign out[31:24] = ...;
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];
endmodule
Bitwise operators
Solution
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
);
//实现 the bitwise-OR of the two vectors
assign out_or_bitwise[2] = a[2] | b[2];
assign out_or_bitwise[1] = a[1] | b[1];
assign out_or_bitwise[0] = a[0] | b[0];
//实现 the logical-OR of the two vectors
assign out_or_logical = (a[0] | b[0]) | (a[1] | b[1]) | (a[2] | b[2]);
//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.
assign out_not[5] = ~b[2];
assign out_not[4] = ~b[1];
assign out_not[3] = ~b[0];
assign out_not[2] = ~a[2];
assign out_not[1] = ~a[1];
assign out_not[0] = ~a[0];
endmodule
对于第三部分的6行,可以用更简洁的语法表示:
assign out_not = {~b, ~a};
其中({}
)为拼接运算符
- 功能:将多个向量按指定顺序连接成一个更长的向量。
- 语法:
{向量1, 向量2, ...}
规则:
- 从左到右:左侧向量放在结果的高位,右侧向量放在低位。
- 总位宽:结果的位宽等于所有拼接向量的位宽之和。
示例:
a = 3'b101; // 3位向量 b = 3'b011; // 3位向量 {a, b} = 6'b101011; // a在高位,b在低位 {b, a} = 6'b011101; // 顺序颠倒,结果不同
Four-input gates
用 Verilog 实现连续异或、同或:
若要处理的操作数位宽是固定的,直接使用按位取反异或运算符即可:
module xnor_reduction (
input [N-1:0] a, // 假设N是操作数的位宽
output y
);
assign y = ^a; // 先进行异或缩减操作
assign y = ~y; // 再对结果取反,得到同或结果
// 或者可以合并为:assign y = ~^a;
endmodule
Vector concatenation operator
易错点:正确的做法应该是直接取拼接后的高 8 位(即a
的全部 5 位 +b
的前 3 位b[4:2]
,而不是后 3 位b[2:0]
)。
Solution
module top_module (
input [4:0] a, b, c, d, e, f,
output [7:0] w, x, y, z
); // 将所有输入向量连接为30位,再补两个1,形成32位
wire [31:0] combined = {a, b, c, d, e, f, 2'b11}; // 分割为四个8位输出
assign w = combined[31:24];
assign x = combined[23:16];
assign y = combined[15:8];
assign z = combined[7:0];
endmodule
Vector reversal 1
Solution
module top_module(
input [7:0] in,
output [7:0] out
);
assign out = {in[0],in[1],in[2],in[3],in[4],in[5],in[6],in[7]};
endmodule
Replication operator
符号扩展:
- 在计算机中,有符号数(如负数)通常用二进制补码表示。当你需要将一个位数较少的有符号数(如 8 位)转换为位数更多的有符号数(如 32 位)时,必须保持其数值不变。
- 符号扩展的规则是:用原数的符号位(最高位)填充扩展后的高位。
为什么符号扩展有效?
- 对于正数,符号位为 0,高位补 0 不改变数值。
- 对于负数,符号位为 1,高位补 1 保持补码的数值不变(例如 - 1 的补码是全 1)。
通过这种方式,扩展后的 32 位数与原始 8 位数在数值上完全相等。
Solution
module top_module (
input [7:0] in,
output [31:0] out );//
// assign out = { replicate-sign-bit , the-input };
assign out = {{24{in[7]}},in};
endmodule
More replication
Solution
module top_module (
input a, b, c, d, e,
output [24:0] out );//
// The output is XNOR of two vectors created by
// concatenating and replicating the five inputs.
// assign out = ~{ ... } ^ { ... };
wire [24:0] top;
wire [24:0] bottom;
assign top = {{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}};
assign bottom = {5{{a,b,c,d,e}}};
//Error
/* integer p = 24;
for (integer i = 0; i < 5; i = i + 1) begin
for (integer j = 0; j < 5; j = j + 1) begin
assign out[p] = ~top[i] ^ bottom[j];
assign p = p - 1;
end
end*/
assign out = ~(top ^ bottom);
endmodule