下列提供的代码答案不唯一!
目录
6、Vector concatenation operator
1、Vectors
矢量用于使用一个名称对相关信号进行分组,以使操作更方便。例如导线[7:0]w,声明一个名为w的8位向量,它在功能上等价于拥有8条独立连线。注意,vector的声明将维数放在vector的名称之前,这与C语法相比是不一样的。
wire [99:0] my_vector; // Declare a 100-element
vector
assign out = my_vector[10]; // Part-select one bit out of the vector
构建一个有一个3位输入的电路,然后输出相同的矢量,并将其分成三个单独的1位输出。将输出o0连接到输入向量的位置0,o1连接到位置1,等等。
代码:
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
2、Vectors in more detail
Declaring Vectors
vector常见以下几种
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.
向量的字节顺序是指最不重要的位是否具有较低的索引(little-endian,例如[3:0])或较高的索引(big-endian,例如[0:3])。在Verilog中,一旦用特定的字节顺序声明vector,就必须始终以相同的方式使用它。例如当vec被声明为wire [3:0] vec时,写入vec[0:3];是非法的。
Implicit nets
Implicit nets常常是难以发现的bug的来源。在Verilog中,可以通过赋值语句或将未声明的内容附加到模块端口来隐式创建网络类型信号(即使用wire型变量前请先声明,不要直接未定义就作为中间变量,这样导致的错误会很难发现)。Implicit nets总是1位导线形式存在,如果使用向量,则可能会导致错误。禁用Implicit nets的创建可以使用' default_nettype none指令来完成。
wire [2:0] a, c; // Two vectors assign a = 3'b101; // a = 101
assign b = a; // b = 1 implicitly-created wire
//
添加' default_nettype none将使这行代码出现错误,从而使错误更加明显。
assign c = b; // c = 001 <-- bug
my_module i1 (d,e); //
如果没有声明, d和e默认为1位宽//
如果端口是一个向量,这可能出现错误
Unpacked vs. Packed Arrays
在声明中,向量索引写在向量名称之前。这声明了数组的“打包”维度。解压后的维度声明在名称之后,它们通常用于声明内存数组。详见Data Types Part-X。
向量名前为维度,向量名后为数目,不写默认为1。(可类比C语言中的数组,向量名前为数组元素的数据类型,向量名后为数组长度;或者形象化的表述为:维度即为每个房子的大小,数目为房子的总数目)
Reg [7:0] mem [255:0];// 256个解压缩的元素,每个元素都是一个8位压缩的reg向量。reg mem2 [28:0];// 29个解压的元素,每个都是1位的reg。
Accessing Vector Elements: Part-Select
访问整个vector是使用vector名称完成的。例如:assign w = a;
将整个4位向量a赋值给整个8位向量w(声明从上面获取)。如果左右两边的长度不匹配,则对其进行适当的零扩展或截断。
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] // Two lowest bits of z b[3:0] // Illegal. Vector part-select must match the direction of the declaration. b[0:3] // The *upper* 4 bits of b. assign w[3:0] = b[0:3]; // Assign upper 4 bits of b to lower 4 bits of w. w[3]=b[0], w[2]=b[1], etc.
练习题目:建立一个组合电路,将输入半字(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
3、Vector part select
32位向量可以被视为包含4个字节(位[31:24],[23:16]等)。构建一个电路将一个4byte的数中的字节顺序调转,当需要交换一段数据的字节顺序时,通常使用此操作,常用于数据的大小端转换,如下
AaaaaaaaBbbbbbbbCcccccccDddddddd = > DdddddddCcccccccBbbbbbbbAaaaaaaa
代码:
module top_module(
input [31:0] in,
output [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];
endmodule
4、Bitwise opertators
建立一个电路,有两个3位输入,计算两个向量的位或,两个向量的逻辑或,以及两个向量的逆(NOT)。把b的逆放在out_not的上半部分(也就是比特[5:3]),把a的逆放在下半部分。
按位操作符与逻辑操作符.在前面,我们提到了各种布尔操作符的按位和逻辑运算
(例如异或门NOR gates1、Verilog Language-Basics_Black-S的博客-CSDN博客)。在使用vector时,区分这两种操作符类型就变得很重要。两个n位向量之间的按位运算复制向量每一位的运算并产生n位输出,而逻辑运算将整个向量视为布尔值(true =非零,false =零)并产生1位输出。
代码:
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_logical = a || b;
assign out_or_bitwise = a | b;
assign out_not[5:3] = ~b;
assign out_not[2:0] = ~a;
endmodule
看一下模拟波形,看看按位或与逻辑或有何不同。
5、Four-input gates
建立一个具有四个输入的组合电路,in[3:0]。有3个输出:
out_and: 4输入与门的输出。out_or: 4输入OR门的输出。
out_xor: 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];
endmodule
6、Vector concatenation operator
部分选择用于选择向量的各个部分。向量拼接操作{a,b,c}通过将一个向量的较小部分连接在一起来创建较大的向量。
{3'b111, 3'b000} => 6'b111000
{1'b1, 1'b0, 3'b101} => 5'b10101
{4'ha, 4'd10} => 8'b10101010 // 4'ha和4'd10都是4'b1010的二进制
向量拼接操作需要知道每个组件的宽度,因此,{1,2,3}是非法的,并导致错误消息:未大小的常量不允许在向量拼接操作中使用。向量拼接操作可以同时用于赋值的左边和右边。
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.
题目练习:给定几个输入向量,将它们连接在一起,然后将它们分成几个输出向量。有6个5位输入向量:a、b、c、d、e和f,总共有30位输入。有4个8位输出向量:w、x、y和z,对应32位输出。输出应该是两个1位输入向量的串联。
代码:
module top_module (
input [4:0] a, b, c, d, e, f,
output [7:0] w, x, y, z );//
// assign { ... } = { ... };
//左边w x y z拼在一起和右边a b c d e f 2'b11拼在一起相等
assign {w, x, y ,z} = {a, b, c, d, e, f, 2'b11};
endmodule
7、Vector reversal 1
给定一个8位输入向量[7:0],反转它的位顺序。
代码:
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
8、Replication operator
向量拼接操作允许将向量串联起来形成一个更大的向量。但有时想要把相同的东西连接在一起很多次,就很繁琐,例如赋值a = {b,b,b,b,b};
向量复制操作允许重复一个向量并将它们连接在一起:{num{vector}}
。这将复制向量num次。num必须是一个常量。这两组括号都是必需的。
复制操作符的一个常见情况是将较小的数字扩展为较大的数字,同时保留其带符号的值。这是通过将较小的数字的符号位(最高有效位)复制到左边来完成的。例如,4'b0101(5)符号扩展到8位会得到8'b00000101(5),而4'b1101(-3)符号扩展到8位会得到8'b11111101(-3)。
例如
{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.可见夏宇闻《Verilog数字系统设计教程》第4版42页
题目练习:建立一个电路,将8位数字符号扩展到32位。这需要将符号位的24个副本(即将位[7]复制24次)与8位数字本身连接起来。
代码:
module top_module (
input [7:0] in,
output [31:0] out );
assign out = { {24{in[7]}} , in };
endmodule
9、More replication
给定5个1位信号(a、b、c、d和e),在25位输出向量中计算所有25个一对一的1位比较。如果被比较的两位相等,输出应该是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;
题目练习:如图所示,使用复制和连接操作符可以更容易地完成这一操作。最上面的向量是每个输入5次重复的串联底部的向量是5个输入序列的5次重复
代码:
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 = ~{ ... } ^ { ... };
assign out = {{5{a}}, {5{b}}, {5{c}}, {5{d}}, {5{e}}} ~^ {5{a, b, c, d, e}};
endmodule