参考连接:HDLBits导学
Problem 10 : Vectors
概述:什么是 Verilog 中的向量(vector)?向量是一组 wire 信号的集合,通过赋予这一组信号的集合一个名称,以便于访问其中的 wire 信号。
向量类似于总线,一般将向量视为位宽超过 1 位的 wire 信号,不是特别在意向量这个概念本身。
问题:构造一个电路,拥有 1 个 3 bit 位宽的输入端口,4 个输出端口。其中一个输出端口直接输出输入的向量,剩下 3 个输出端口分别各自输出 3 bit 中的 1 bit
解决:
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
Problem 11 : Vector in more detail
问题:创建一个模块输出16位输入信号的高8位和低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
注意:向量的比特顺序(endianness)信息,比特顺序取决于向量的 LSB 是向量的高位还是地位。比如声明为 [3:0] w 的向量,LSB 是 w[0],如果声明为 [0:3] w,那么 w[3] 是 LSB 。LSB 指的是二进制数中权值最低的一位。
隐式声明的问题,隐式声明的例子
wire [2:0] a, c; // Two vectors
assign a = 3'b101; // a = 101
assign b = a; // b = 1 隐式声明并定于了 b
wire assign c = b; // c = 001 <-- bug 来了 b 被 coder 默认为和 a 相同的 3'b101,但其实 b 只有 1bit宽
my_module i1 (d,e); // d e 都被隐式声明为 1bit wire
//如果模块期望的是 vector 那么 BUG 就产生了
通过添加 `default_nettype none
宏定义会关闭隐式声明功能,那么这样一来,使用未声明的变量就会变成一个 Error 而不再只是 Warning。
声明向量数组
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 赋值操作中,如果等号左右两侧信号的位宽不同,那么就会进行截断或者补零操作。
左侧信号位宽大于右侧信号位宽,右值的低位赋予左值对应的低位,左值高位的部分赋零。
左侧信号位宽小于右侧信号位宽,右值的低位赋予左值对应的低位,右值高位的部分直接被截断。即保留右值的低位。
片选例子
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.
//经测试不能这样做
Problem 12 : Vector part select
问题:一个 32 位的向量可以看做由 4 个字节组成(bits[31:24],[23:16],等等)。构建一个电路,将输入向量的字节顺序颠倒,也就是字节序大小端转换。
AaaaaaaaBbbbbbbbCcccccccDddddddd => DdddddddCcccccccBbbbbbbbAaaaaaaa
解决:
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
注意:不能把方向搞反了 会报错的
b[3:0] // 如果 b 在声明时 声明为 wire [0:3] b;则不能使用 b [3:0]进行选择
Problem 13 : Bitwise operators
问题:模块有两个 3bit 宽的输入变量 a,b ,要求输出 a,b 逐位或的,a,b 逻辑或以及 a,b 按位取反的结果,其中 b 在高位
解决:
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;
assign out_not[5:3] = ~b;
endmodule
Problem 14 : Four-input gates
问题:构建一个4输入的与门、或门和异或门
解决:
module top_module(
input [3:0] in,
output out_and,
output out_or,
output out_xor
);
//第一种解决方法
assign out_and = in[0] & in[1] & in[2] & in[3];
assign out_or = in[0] | in[1] | in[2] | in[3];
assign out_xor = in[0] ^ in[1] ^ in[2] ^ in[3];
//第二种解决方法
assign out_and = & in;
assign out_or = | in;
assign out_xor = ^ in;
endmodule
Problem 15 : Vector concatenation operator
问题:给定几个输入向量,将它们连接在一起,然后将它们分成几个输出向量。
思路:可以看出a,b,c,d,e,f 都是5位的,然后使用拼接操作
解决:
module top_module (
input [4:0] a, b, c, d, e, f,
output [7:0] w, x, y, z );//
// assign { ... } = { ... };
assign z = {e[0],f,2'b11};
assign y = {d[3:0],e[4:1]};
assign x = {b[1:0],c,d[4]};
assign w = {a,b[4:2]};
endmodule
注意:拼接操作符
{3'b111, 3'b000} => 6'b111000
{1'b1, 1'b0, 3'b101} => 5'b10101
{4'ha, 4'd10} => 8'b10101010 // 4'ha and 4'd10 are both 4'b1010 in binary
连接操作符的基本语法使用 { } 将较小的向量括起来,每个 { } 内的向量使用逗号作为间隔。
连接运算符中的向量务必需要标注位宽,不然综合器怎么能知道你的结果需要多宽的位宽。因此 { 1,2,3 } 这样的操作是非法的,并会产生一个 Error:unsized constants are not allowed in concatenations.
拼接用在左侧和右侧都可以
input [15:0] in;
output [23:0] out;
assign {out[7:0], out[15:8]} = in; // Swap two bytes. Right side and left side are both 16-bit vectors.
assign out[15:0] = {in[7:0], in[15:8]}; // This is the same thing.
assign out = {in[7:0], in[15:8]}; // This is different. The 16-bit vector on the right is extended to
// match the 24-bit vector on the left, so out[23:16] are zero.
// In the first two examples, out[23:16] are not assigned.
Problem 16 : Vector reversal 1
问题:给定一个 8bit 输入向量,将其反向输出
思路:拼接的办法 把地位依次放在高位进行拼接
解决:
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]};
//第二种方式 for循环
integer i;
always @(*) begin
for (i=0; i<8; i++) //Use integer for pure Verilog.
out[i] = in[8-i-1];
end
endmodule
Problem 17 : Replication operator
概述:连接操作符允许我们将短小的向量连接在一起构成更宽的向量。很方便,但有的时候需要将多个重复的向量连接在一起,诸如 assign a = {b,b,b,b,b,b}; 这样的语句写多了是非常让人忧愁的。而重复操作符语法就可以在这种情况下帮到你,允许你将一个向量重复多次,并将它们连接在一起,语法是这样:{ 重复次数 { 向量 } }。
例子:
{5{1'b1}} // 5'b11111 (or 5'd31 or 5'h1f)
{2{a,b,c}} // The same as {a,b,c,a,b,c}
{3'd5, {2{3'd6}}} // 9'b101_110_110. It's a concatenation of 101 with
// the second vector, which is two copies of 3'b110.
问题:重复操作符的应用场景之一是在有符号数的扩展。有符号数的扩展是将符号位填充待扩展的比特。比如要将 4bit 的 4'b0101 有符号数扩展为 8bit ,0 是符号位,那么扩展之后为 8'b0000 0101.
现在要求你构建一个电路,将一个 8bit 有符号数扩展为 32bit 数。
思路:输入高位为1的时候则为负数,此时需要将输出高位置1,反之则需要将输出高位置0(虽然说不置也是0)。开始想用if else,还写错了。然后参考了大佬写的,真不错~~~
解决:
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
注意:重复次数必须是一个常量,而且请特别注意重复操作符有两对 { }.外层的 {} 不能少。
Problem 18 : More Replication
问题:将 5 个 1bit 信号分别组成下图中两个 25 bit 信号,输出向量为这两个 25bit 向量的逐位操作的结果。如果两个待比较信号某比特相同,则结果向量对应的该比特位 1 。
out[24] = ~a ^ a; // a == a, so out[24] is always 1.
out[23] = ~a ^ b;
out[22] = ~a ^ c;
...
out[ 1] = ~e ^ d;
out[ 0] = ~e ^ e
解决:
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] x1 = {{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}};
wire [24:0] x2 = {5{a,b,c,d,e}};
assign out = ~ (x1 ^ x2);
endmodule
注意:
//有多个的时候每一个都需要用两个{}括起来,数字不能漏在外面
wire [24:0] x1 = {{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}};