HDLBits中文版,标准参考答案 | 2 Verilog Language 2.2 Vectors

关注 望森FPGA  查看更多FPGA资讯

这是望森的第 4 期分享

作者 | 望森
来源 | 望森FPGA

目录

1 Vectors | 向量
2 Vectors in more detail | 向量的更多细节
3 Vector part select | 向量的部分选择
4 Bitwise operators | 按位运算符
5 Four-input gates | 四输入门
6 Vector concatenation operator
7 Vector reversal 1
8 Replication operator
9 More replication


本文中的代码都能够正常运行,请放心食用😋~

练习的官方网站是:HDLBits官方网站

注:作者将每个练习的知识点都放在了题目和答案之后


1 Vectors | 向量

题目:
构建一个具有一个 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 o0 = vec[0];
    assign o1 = vec[1];
    assign o2 = vec[2];
    
endmodule

知识点:
向量的目的是使用一个名称分组管理相关信号。
例如,wire [7:0] w; 即声明一个名为 w 的 8 bit位宽向量,其功能相当于拥有 8 条独立的线路。

向量的声明示例如下:
wire [99:0] my_vector; // 声明一个 100 元素向量
assign out = my_vector[10]; // 从向量中部分选择一位


2 Vectors in more detail | 向量的更多细节

题目:
构建一个组合电路,将输入两个字节(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

知识点:

1.声明向量

声明向量的格式:
type [upper:lower] vector_name;
type 指定向量的数据类型。
这通常是 wire 或 reg。 如果您声明的是输入或输出端口,则类型还可以包括端口类型(例如,input或output)。

一些示例:
wire [7:0] w; // 8 位 wire
reg [4:1] x; // 4 位reg
output reg [0:0] y; // 1 位 reg,也是输出端口(这仍然是一个向量)
input wire [3:-2] z; // 6 位 wire 输入(允许负范围)
output [3:0] a; // 4 位输出 wire。除非另有说明,否则类型为“wire”。
wire [0:7] b; // 8 位 wire,其中 b[0] 是最高有效位。

向量的字节序是指:
最低有效位是具有较低索引(小端序,例如 [3:0])还是较高索引(大端序,例如 [0:3])。
在 Verilog 中,一旦向量声明为具有特定字节序,就必须始终以相同的方式使用它。
例如,当 vec 声明为 wire [3:0] vec; 时,写入 vec[0:3] 是非法的。
果分配或一起使用不同字节序的向量,会出现奇怪的错误!

2.隐式网络

隐式网络通常是难以检测的错误的来源! 在 Verilog 中,可以通过赋值语句或将未声明的内容附加到模块端口来隐式创建网络类型信号。隐式网络始终是 1 位线,如果您打算使用向量,则会导致错误。 可以使用 `default_nettype none 指令禁用隐式网络的创建。

示例:
wire [2:0] a, c; // 两个向量
assign a = 3'b101; // a = 101
assign b = a; // b = 1 隐式创建的线
assign c = b; // c = 001 <-- bug
my_module i1 (d,e); // 如果未声明,则 d 和 e 隐式为 1 位宽。
        // 如果端口打算用作向量,则这可能是一个错误。

如果添加了 `default_nettype none ,第二行代码会出现错误,从而发现问题。

未打包数组与打包数组

您可能已经注意到,在声明中,向量索引写在向量名称之前。 未打包维度在名称之后声明,它们通常用于声明内存数组。

示例:
reg [7:0] mem [255:0]; // 256 个未打包元素,每个元素都是 reg 的 8 位打包向量。
reg mem2 [28:0]; // 29 个未打包元素,每个元素都是 1 位 reg。

访问向量元素:部分选择

使用向量名称可以访问整个向量。例如: assign w = a; 使用部分选择运算符可用于访问向量的一部分,示例:

w[3:0] // 仅 w 的低 4 位
x[1] // x 的最低位
x[1:1] // ...也是 x 的最低位
z[-1:-2] // z 的两个最低位
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],等等。


3 Vector part select | 向量的部分选择

题目:

32 位向量可视为包含 4 个字节(位 [31:24]、[23:16] 等)。 构建一个电路来反转 4 字节字的字节顺序。 AaaaaaaaBbbbbbbbCcccccccDddddddd => DdddddddCccccccccBbbbbbbbAaaaaaaa

注:此操作通常在需要交换数据片段的字节顺序时使用,例如在小端 x86 系统和许多 Internet 协议中使用的大端格式之间。

答案:

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 operators | 按位运算符

题目:

构建一个具有两个 3 位输入的电路, 用于计算两个向量的按位或、两个向量的逻辑或以及两个向量的逆(非)。 将 “b 的逆”放在 out_not 的上半部分(即位 [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 = ~{b,a};
    
endmodule

知识点:

按位运算符与逻辑运算符

之前,我们提到各种布尔运算符(例如,norgate)都有“按位”和“逻辑”版本。
使用向量时,这两种运算符类型之间的区别变得很重要。
两个 N 位向量之间的按位运算会为向量的每个位复制运算并产生 N 位输出,而逻辑运算会将整个向量视为布尔值(真 = 非零,假 = 零)并产生 1 位输出。

查看模拟波形,了解按位或和逻辑或有何不同。


5 Four-input gates | 四输入门

题目:

构建一个具有四个输入的组合电路,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;
    
endmodule

6 Vector concatenation operator

题目:

给定几个输入向量,将它们连接在一起,然后将它们拆分成几个输出向量。
有六个 5 位输入向量:a、b、c、d、e 和 f,总共 30 位输入。
有四个 8 位输出向量:w、x、y 和 z,总共 32 位输出。
输出应该是输入向量的连接,后面跟着两个 1 bit:

答案:

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};
 
endmodule

知识点:

部分选择用于选择向量的部分。
连接运算符
{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; // 交换两个字节。右侧和左侧都是 16 位向量。
assign out[15:0] = {in[7:0], in[15:8]}; // 这是同一件事。
assign out = {in[7:0], in[15:8]}; // 这是不同的。右侧的 16 位向量被扩展为
        // 匹配左侧的 24 位向量,因此 out[23:16] 为零。
        // 在前两个示例中,out[23:16] 未分配。


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

题目:

构建一个将 8 位数符号扩展为 32 位的电路。 需要将 24 个符号位副本(即复制 bit[7] 24 次)串联起来,然后是 8 位数本身。

答案:

module top_module (
    input [7:0] in,
    output [31:0] out );//
 
    assign out = { {24{in[7]}} , in };
 
endmodule

知识点:

错解分析:【复制后的数还要用“{}”括起来】
module top_module (
    input [7:0] in,
    output [31:0] out );//
 
    assign out = { 24{in[7]} , in };
 
endmodule

连接运算符允许将向量连接在一起以形成更大的向量。但有时您希望多次将同一事物连接在一起,并且执行诸如assign a = {b,b,b,b,b,b};之类的操作仍然很繁琐。
复制运算符允许重复一个向量并将它们连接在一起:
{num{vector}}
这将向量复制num次。num必须是常数。两组括号都是必需的。

示例:
{5{1'b1}} // 5'b11111(或5'd31或5'h1f)
{2{a,b,c}} //与{a,b,c,a,b,c}相同
{3'd5, {2{3'd6}}} // 9'b101_110_110。它是101与
        //第二个向量的连接,第二个向量是3'b110的两个副本。

复制运算符的一个常见场景是将较小的数字符号扩展为较大的数字,同时保留其有符号值。
这是通过将较小数字的符号位(最高有效位)复制到左侧来实现的。
例如,将 4'b0101 (5) 符号扩展为 8 位,结果为 8'b00000101 (5),
而将 4'b1101 (-3) 符号扩展为 8 位,结果为 8'b11111101 (-3)。


9 More replication

题目:

给定五个 1 位信号(a、b、c、d 和 e),计算 25 位输出向量中所有 25 个成对的 1 bit 比较。 如果比较的两个位相等,则输出应为 1。

out[24] = ~a ^ a; // a == a,因此 out[24] 始终为 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 );//
 
    assign out = ~{{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}} ^ { {5{a,b,c,d,e}} };
 
endmodule

知识点:

如图所示,使用复制和连接运算符可以更轻松地完成此操作。
顶部向量是每个输入 5 次重复的连接
底部向量是 5 个输入连接的 5 次重复


- END -

微信公众号/CSDN/EETOP搜索【望森FPGA】,查看更多FPGA资讯~

相关推荐文章,点击跳转:

FPGA新手必用,Verilog HDL编程学习网站推荐 —— HDLBits

Getting Started| HDLBits启航篇!

HDLBits中文版,标准参考答案 | 2 Verilog Language 2.1 Basics

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值