HDLBits——Modules:Hierarchy
目录
- HDLBits——Modules:Hierarchy
- 问题19 Module
- 将信息连接到端口
- By position
- By name
- 问题20 Connecting ports by position(Module pos)
- 问题21 Connecting ports by name(Module name)
- 问题22 Three modules(Module shift)
- 问题23 Modules and vectors(Module shift8)
- 问题24 Adder 1(Module add)
- 问题25 Adder 2(Module fadd)
- 问题26 Carry-select adder (Module cseladd)
- 问题27 Adder–subtractor (Module addsub)
- 结语
问题19 Module
下图显示了一个带有子模块的简单的电路。在本练习中,创建模块 mod_a 的一个实例,然后将模块的三个引脚(in1、in2 和 out)连接到顶层模块的三个端口(线 a、b 和 out)。模块 mod_a 是为您提供的——您必须实例化它。
将信息连接到端口
将物理电线连接到端口有两种常用的方法: by position or by name. 按位置或按名称。
By position
按位置将电线连接到端口的语法应该很熟悉,因为它使用类似 C 的语法。实例化模块时,端口根据模块的声明从左到右连接。例如:
mod_a instance1 (wa,wb,wc);
这会实例化一个 mod_a
类型的模块,并给它一个实例名称“instance1
”,然后将信号 wa
(在新模块外部)连接到新模块的第一个端口(in1
),将 wb
连接到第二个端口(in2
),然后wc
到第三个端口(out
)。
By name
按名称将信号连接到模块的端口可以使电线保持正确连接,即使端口列表发生更改。然而,这种语法更加冗长。
mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) );
上面的行实例化了一个名为“instance2
”的 mod_a
类型的模块,然后将信号 wa
(模块外部)连接到名为 in1
的端口,将 wb
连接到名为 in2
的端口,将 wc
连接到名为 out
的端口。请注意,端口的顺序在这里是不相关的,因为无论其在子模块的端口列表中的位置如何,都将连接到正确的名称。还要注意此语法中端口名称前面的句点。
module top_module ( input a, input b, output out );
mod_a instance2 (.out(out),
.in1(a),
.in2(b)
);
endmodule
问题20 Connecting ports by position(Module pos)
这个问题和上一个问题19类似。您将获得一个名为 mod_a
的模块,该模块按顺序具有 2
个输出和 4
个输入。您必须按位置将 6
个端口按顺序连接到顶层模块的端口 out1
、out2
、a
、b
、c
和 d
。
您将获得以下模块:
module mod_a ( output, output, input, input, input, input );
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a mod_a (
out1,
out2,
a,
b,
c,
d
);
endmodule
问题21 Connecting ports by name(Module name)
您将获得一个名为 mod_a
的模块,该模块按某种顺序具有 2
个输出和 4
个输入。您必须按名称将 6
个端口连接到顶层模块的端口:
您将获得以下模块:
module mod_a ( output out1, output out2, input in1, input in2, input in3, input in4);
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a mod_a(
.in1(a),
.in2(b),
.in3(c),
.in4(d),
.out1(out1),
.out2(out2)
);
endmodule
问题22 Three modules(Module shift)
您将获得一个带有两个输入和一个输出的模块 my_dff
(实现 D
触发器)。将其中三个实例化,然后将它们链接在一起以制成长度为 3 的移位寄存器。 clk
端口需要连接到所有实例。
提供给你的模块是:
module my_dff(input clk, input d, output q);
请注意,要建立内部连接,您需要声明一些连线。命名你的连线和模块实例时要小心:名称必须是唯一的。
module top_module ( input clk, input d, output q );
wire w1_2;
wire w2_3;
my_dff dff1(
.clk(clk),
.d(d),
.q(w1_2)
);
my_dff dff2(
.clk(clk),
.d(w1_2),
.q(w2_3)
);
my_dff dff3(
.clk(clk),
.d(w2_3),
.q(q)
);
endmodule
问题23 Modules and vectors(Module shift8)
本练习是 module_shift 的扩展。模块端口不再只是单个引脚,我们现在有带有向量作为端口的模块,您将连接线向量而不是普通线。与 Verilog 中的其他任何地方一样,端口的向量长度不必与连接到它的导线相匹配,但这会导致向量的零填充或截断。本练习不使用向量长度不匹配的连接。
您将获得一个带有两个输入和一个输出的模块 my_dff8(实现一组 8
个 D
触发器)。实例化其中三个,然后将它们链接在一起,形成一个长度为3
的8
位宽移位寄存器。此外,创建一个4
对1
多路复用器(未提供),该多路复用器根据sel[1:0]
:输入d
处、第一个d
触发器之后、第二个d
触发器之后或第三个d
触发器之后的值来选择要输出的内容。(本质上,sel选择延迟输入的周期数,从零到三个时钟周期。)
提供给你的模块是:
module my_dff8(input clk, input [7:0] d, output [7:0] q);
未提供多路复用器。一种可能的编写方法是在一个带有 case
语句的 always 块中。 (另见:mux9to1v)
module top_module (
input clk, //clock signal
input [7:0] d, //Enter 8 groups of data
input [1:0] sel, //2-bit selector
output [7:0] q //8-bit output
);
wire [7:0] w1_1,w1_2,w1_3; //8-bit output
my_dff8 my_dff81(
.clk(clk),
.d(d),
.q(w1_1)
);
my_dff8 my_dff82(
.clk(clk),
.d(w1_1),
.q(w1_2)
);
my_dff8 my_dff83(
.clk(clk),
.d(w1_2),
.q(w1_3)
);
always @(*) begin
case(sel)
0: begin q <= d; end
1: begin q <= w1_1; end
2: begin q <= w1_2; end
3: begin q <= w1_3; end
endcase
end
endmodule
问题24 Adder 1(Module add)
您将获得一个执行16
位加法的模块add16
。实例化其中两个以创建32位加法器。一个add16
模块计算加法结果的低16位,而第二个add16
模块在从第一个加法器接收进位后计算结果的高16
位。您的32
位加法器不需要处理进位(假设为0)或进位(忽略),但内部模块需要处理才能正常工作。(换句话说,add16
模块执行16
位a+b+cin
,而您的模块执行32
位a+b
)。
如下图所示将模块连接在一起。提供的模块 add16 具有以下声明:
module add16(input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout);
![在这里插入图片描述](/i/ll/?i=a3998a0a74924f95b124ef6d2e63c827.png
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
parameter z = 0;
wire w;
add16 add161(
.a(a[15:0]),
.b(b[15:0]),
.cin(z),
.cout(w),
.sum(sum[15:0])
);
add16 add162(
.a(a[31:16]),
.b(b[31:16]),
.cin(w),
.sum(sum[31:16])
);
endmodule
问题25 Adder 2(Module fadd)
在本练习中,您将创建具有两个层次结构的电路。您的 top_module
将实例化 add16
的两个副本(已提供),每个副本将实例化 add1
的 16 个副本(您必须编写)。
与module\u add一样,您也会得到一个执行16
位加法的module add16
。必须实例化其中的两个才能创建32
位加法器。一个add16
模块计算加法结果的低16
位,而第二个add16
模块计算结果的高16
位。您的32
位加法器不需要处理进位(假定为0)或进位(忽略)。
如下图所示将 add16
模块连接在一起。提供的模块 add16
具有以下声明:
module add16(input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout);
在每个 add16
中,实例化了 16
个全加器(模块 add1
,未提供)以实际执行加法。您必须编写具有以下声明的完整加法器模块:
module add1( input a, input b, input cin, output sum, output cout );
总之,本题中一共有三个模块:
-
top_module
:包含两个16
位加法器的顶层模块; -
add16
(已给出):一个16bit
的加法器,由16
个全加器构成; -
add
(未给出):1bit
全加器。
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);//
wire w;
add16 add161(
.a(a[15:0]),
.b(b[15:0]),
.cin(1'b0),
.cout(w),
.sum(sum[15:0])
);
add16 add162(
.a(a[31:16]),
.b(b[31:16]),
.cin(w),
.sum(sum[31:16])
);
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
assign sum = a ^ b ^ cin;
assign cout = (a & b) | (a&cin) | (b & cin);
endmodule
问题26 Carry-select adder (Module cseladd)
问题25 实现的加法器叫做行波进位加法器(RCA: Ripple-Carry Adder
),缺点是计算进位输出的延迟是相当慢的(最坏的情况下,来自于进位输入),前一级加法器计算完成之前,后一级加法器不能开始计算,使得加法器的计算延迟变大。
在本练习中,为您提供与前一练习相同的模块 add16
,它将两个 16
位数字与进位相加,并产生一个进位和 16
位和。您必须使用您自己的 16
位 2
对 1 多路复用器来实例化其中的三个以构建进位选择加法器。
如下图所示将模块连接在一起。提供的模块 add16
具有以下声明:
module add16(input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout);
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire [15:0] sum1;
wire [15:0] sum2;
wire [15:0] sum3;
wire cout;
assign sum = cout ? {sum3, sum1} : {sum2, sum1};
add16 add161(
.a (a[15:0] ),
.b (b[15:0] ),
.sum (sum1 ),
.cin (1'b0 ),
.cout (cout )
);
add16 add162(
.a (a[31:16] ),
.b (b[31:16] ),
.sum (sum2 ),
.cin (1'b0 ),
.cout ( )
);
add16 add163(
.a (a[31:16] ),
.b (b[31:16] ),
.sum (sum3 ),
.cin (1'b1 ),
.cout ( )
);
endmodule
问题27 Adder–subtractor (Module addsub)
减法器可以由加法器来构建,对其中一个数取相反数(逐位取反加1)即可。最终结果是一个可以执行两种操作的电路:(a + b + 0)
和 (a + ~b + 1)
。如果您想更详细地了解该电路的工作原理,请参阅 Wikipedia。
为您提供了一个 16 位加法器模块,您需要对其进行两次实例化:
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
当 sub
为 1 时,使用 32
位的异或门对 b
进行取反(这也可以被视为 b[31:0]
与 sub
复制 32
次相异或),同时 sub
信号连接到加法器的进位。
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire cout;
wire [31:0] b_com;
assign b_com = {32{sub}}^ b;
add16 add161(
.a (a[15:0] ),
.b (b_com[15:0] ),
.cin (sub ),
.cout (cout ),
.sum (sum[15:0] )
);
add16 add162(
.a (a[31:16] ),
.b (b_com[31:16] ),
.cin (cout ),
.cout ( ),
.sum (sum[31:16] )
);
endmodule
结语
注意巩固练习