本文主要是介绍HDLBits——Vectors,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
HDLBits —— Vectors
Vectors(向量;总线)
要求:
构造一个电路,拥有 1 个 3 bit 位宽的输入端口,4 个输出端口。其中一个输出端口直接输出输入的向量,剩下 3 个输出端口分别各自输出 3 bit 中的 1 bit。上图中,箭头上的小斜杠旁边的数字代表该向量(总线)的位宽,用于将向量同 wire 信号区别开来。
Solution:
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 declarationassign outv = vec;assign o2 = vec[2];assign o1 = vec[1];assign o0 = vec[0];endmodule
改进:assign {o2, o1, o0} = vec;
PS:如果想要片选多个 bit,那么可以通过如下操作实现。
assign w = vec[1:0];
Timing Diagram:
Vector in more detail
要求:
分别输出 16 位输入信号的高 8 位 和低 8 位。
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 = in[15:8];assign out_lo = in[7:0];endmodule
Timing Diagram:
Vector part select(向量片选)
要求:
一个 32 位的向量可以看做由 4 个字节组成(bits[31:24],[23:16],[15:8],[7:0])。构建一个电路,将输入向量的字节顺序颠倒,也就是字节序大小端转换。
aaaaaaaabbbbbbbbccccccccdddddddd => ddddddddccccccccbbbbbbbbaaaaaaaa
这项操作常见于不同的大小端体系之间的数据交换,比如 x86 体系使用小端模式存储数据,而因特网协议中均使用大端模式,数据在本地和网络进行数据交换之前,均要进行大小端转换。
Solution:
module top_module( input [31:0] in,output [31:0] out );assign out[31:24] = in[7:0];assign out[7:0] = in[31:24];assign out[23:16] = in[15:8];assign out[15:8] = in[23:16];endmodule
改进:用一句 assign 语句代替,使用 {} 位拼接符。
assign out = {in[7-:8],in[15-:8],in[23-:8],in[31-:8]};
Timing Diagram:
Bitwise operators(按位运算符)
要求:
模块有两个 3bit 宽的输入变量 a,b ,要求输出 a,b 逐位或、逻辑或、按位取反的结果,其中 b 在高位。
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
);assign out_or_bitwise = {a[2] | b[2],a[1] | b[1],a[0] | b[0]};assign out_or_logical = a || b;assign out_not = ~{b,a};endmodule
PS:逐位逻辑运算符 VS 逻辑运算符
逐位逻辑运算符:对于 N 比特输入向量之间的逻辑比较,会在 N 比特上逐位进行,并产生一个 N 比特长的运算结果。
逻辑运算符:任何类型的输入都会被视作布尔值,零->假,非零->真,将布尔值进行逻辑比较后,输出一个 1 比特的结果。
Timing Diagram:
Four-input gates
要求:
分别构建一个 4 输入与门,或门以及异或门。
Solution:
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
也可:使用缩减运算符的语法。
assign out_and = & in;assign out_or = | in;assign out_xor = ^ in;
Timing Diagram:
Vector concatenation operator(连接操作符)
要求:
方格表示模块 32 位输入向量,按照上下对应关系,输出为下方的 4 个 8 比特向量。
Solution:
module top_module (input [4:0] a, b, c, d, e, f,output [7:0] w, x, y, z );//assign {w[7:0],x[7:0],y[7:0],z[7:0]} = {a[4:0],b[4:0],c[4:0],d[4:0],e[4:0],f[4:0],2'b11};endmodule
也可: assign {w,x,y,z} = {a,b,c,d,e,f,2’b11}; 变量默认用了所有位,但数字必须说明是多少位。
PS:连接操作符的基本语法使用 { } 将较小的向量括起来,每个 { } 内的向量使用逗号作为间隔。连接运算符中的向量务必需要标注位宽,不然综合器不知道结果需要多宽。
习惯上把位连接符用在赋值语句的右侧,表示将较小的向量连接成较大的向量,赋予左值。但实际上位连接符同样可以用在赋值语句左侧,比如:
assign {cout,sum} = a + b + cin;
在表示全加器时,可以使用一句 assign 语句实现结果和进位的赋值。
Timing Diagram:
Vector reversal 1
要求:
给定一个 8bit 输入向量,将其反向输出。
Solution:
module top_module( input [7:0] in,output [7:0] out
);assign out[7:0] = {in[0],in[1],in[2],in[3],in[4],in[5],in[6],in[7]};endmodule
改进:循环实现(如果位数很高,比如2014位,手动调整就太麻烦了)
循环一:使用 for 循环
module top_module( input [7:0] in,output reg [7:0] out
);integer i;always @(*) beginfor(i=0; i<8; i=i+1)beginout[i] = in[7-i];endendendmodule
PS:for 循环描述了电路的行为,而不是电路的结构,因此,for 循环必须置于比如 always 块这样的过程块(在块中的组合逻辑将会按照一定的顺序运行)中。而实际上电路是不存在循环,for 循环表示的代码将被综合器解析为硬件电路。
注意:
- Verilog 的语法需要提前定义 integer 变量,即整形,不能在循环里面定义。
- always 语句中所有信号必须是 reg 变量。
- 循环只能用 +1,不能用 ++。
循环二:使用 generate 生成块
module top_module( input [7:0] in,output [7:0] out
);generategenvar i;for(i=0; i<8; i=i+1) begin:my_block_nameassign out[i] = in[7-i];endendgenerateendmodule
PS:for 循环和 Verilog 中其他的几种循环语句 while ,forever,repeat 本质上都用于控制语句的执行次数。但生成块主要用于动态生成语句,生成块可以例化 assign 语句,模块,信号和变量的声明以及 always initial 这样的过程块。循环生成块是生成块中的一种类型,在综合过程中同样被综合器进行编译,这个过程可以看做综合过程中动态生成更多 Verilog 代码的预处理过程。
总的来说,for 循环强调了对电路的行为描述,在综合的过程中循环展开,而生成块则用于综合过程中,动态生成代码,两者有本质上的不同。
注意:
- 在生成块中的 for 循环中不能使用 integer 作为循环变量,而必须使用 genvar 变量。
- begin 后面还有冒号,name。
Timing Diagram:
Replication operator(重复操作符)
要求:
重复操作符的应用场景之一是在有符号数的扩展,即将符号位填充待扩展的比特。比如要将 4bit 的 4’b0101 有符号数扩展为 8bit ,0 是符号位,那么扩展之后为 8’b0000 0101。
构建一个电路,将一个 8bit 有符号数扩展为 32bit 数。
Solution:
module top_module (input [7:0] in,output [31:0] out );assign out = {{24{in[7]}},in};endmodule
PS:语法为 { 重复次数 { 向量 } },重复次数必须是一个常量,而且重复操作符有两对 { },别漏了外层。
More Replication
要求:
将 5 个 1bit 信号分别组成下图中两个 25 bit 信号,输出向量为这两个 25bit 向量的逐位操作的结果。如果两个待比较信号某比特相同,则结果向量对应的该比特位 1 。
Solution:
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
部分题目改进思路来源于 LogicJitterGibbs,感谢大神。
果然站在巨人的的肩膀上做起来更快更有效率。
这篇关于HDLBits——Vectors的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!