HDLBits习题讲解_Modules: Hierarchy
元件例化
- 当我们在调用别人已经写好的IP核,或者使用自己的IP核时,需要对IP核进行元件例化操作
- 例化的目的是在上一级模块中调用例化的模块完成代码功能,在 Verilog 里例化信号的格式如下:模块名必须和要例化的模块名一致,包括模块信号名也必须一致。连接信号为 TOP 程序跟模块之间传递的信号,模块与模块之间的连接信号不能相互冲突,否则会产生编译错误。
- 实际使用中,会有两种例化形式,具体格式如下:
//按信号位置例化(不推荐)
mudule_name new_module_name(new_signal_1,new_signal_2,new_signal_3);
//按信号名称例化(推荐)
mudule_name new_module_name
(
.signal_1 (new_signal_1),
.signal_2 (new_signal_2),
.signal_3 (new_signal_3)
);
Modules
- 题目要求使用原件例化,连接
mod_a
模块。mod_a的模块代码如下:
module mod_a ( input in1, input in2, output out );
// Module body
endmodule
- 代码如下:
//按信号位置例化(不推荐)
module top_module ( input a, input b, output out );
mod_a u_mod_a(a,b,out);
endmodule
//按信号名称例化(推荐)
module top_module ( input a, input b, output out );
mod_a u_mod_a(
.in1(a),
.in2(b),
.out(out)
);
endmodule
Connecting ports by position
- 题目要求使用原件例化,连接
mod_a
模块。mod_a的模块代码如下:
module mod_a ( output, output, input, input, input, input );
//module body
endmodule
- 要求按信号位置进行例化,连接顺序为
out1,out2,a,b,c,d
,代码如下:
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a u_mod_a(out1,out2,a,b,c,d);
endmodule
Three modules
- 已有一个模块my_dff,其中有两个输入和一个输出(D触发器)。实例化三个D触发器然后将它们连接在一起,实现一个长度为3的移位寄存器。clk端口需要连接到所有my_dff实例。my_dff的模块代码如下:
module my_dff ( input clk, input d, output q );
- 按如图所示的顺序例化并连接三个模块,代码如下:
module top_module ( input clk, input d, output q );
wire q0,q1;
my_dff u0_my_dff(
.clk(clk),
.d(d),
.q(q0)
);
my_dff u1_my_dff(
.clk(clk),
.d(q0),
.q(q1)
);
my_dff u3_my_dff(
.clk(clk),
.d(q1),
.q(q)
);
endmodule
__tips:__在命名
wire
和例化module
时,名称必须是独一无二的
Modules and vectors
- 有一个模块my_dff8,它具有两个输入和一个输出(实现一组8位的D触发器)。实例化其中的三个,然后将它们连接在一起,实现一个长度为3的8位宽移位寄存器。另外,构造一个4-1多路选择器,根据sel[1:0]选择输出值。本质上,sel选择的是延迟输入的周期。
- 已有模块代码如下:
module my_dff8 ( input clk, input [7:0] d, output [7:0] q );
- 按如图所示的顺序例化并连接,代码如下:
module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] q
);
wire [7:0] q0,q1,q2;
my_dff8 u0_my_dff8(
.clk(clk),
.d(d),
.q(q0)
);
my_dff8 u1_my_dff8(
.clk(clk),
.d(q0),
.q(q1)
);
my_dff8 u3_my_dff8(
.clk(clk),
.d(q1),
.q(q2)
);
assign q = sel[1]? (sel[0]?q2:q1):(sel[0]?q0:d);//多路选择器
endmodule
Adder 1
- 题目要求使用两个带进位的16bit加法器组成一个32bit加法器。一个加法器用于计算结果的低16位,而另一个加法器用于计算结果的高16位。所提供的模块声明如下:
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 cout_0;
add16 u0_add16(
.a(a[15:0]),
.b(b[15:0]),
.cin(1'b0),
.sum(sum[15:0]),
.cout(cout_0)
);
add16 u1_add16(
.a(a[31:16]),
.b(b[31:16]),
.cin(cout_0),
.sum(sum[31:16]),
.cout()
);
endmodule
Adder 2
- 如图中所示的模块结构,我们的top_module例化了2个16位的加法器予以实现,而每个16位的加法器又是例化了16个1位的全加器加以实现。题目要求,自定义一个1bit的全加器,构成一个16bit全加器,然后用两个16bit全加器完成32bit加法模块的搭建,忽略进位。具体任务如下
- 定义一个1bit全加器。
- 在顶层完成两个16bit全加器的调用。
- 题目提供一个16位加法器模块,具体代码如下:
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
- 需要用户自行编写并声明的1位加法器,输入输出接口定义如下:
module add1 ( input a, input b, input cin, output sum, output cout );
- 代码编写如下:
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);//
wire cout_0;
add16 u0_add16 (
.a(a[15:0]),
.b(b[15:0]),
.cin(0),
.sum(sum[15:0]),
.cout(cout_0)
);
add16 u1_add16(
.a(a[31:16]),
.b(b[31:16]),
.cin(cout_0),
.sum(sum[31:16]),
.cout()
);
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
// Full adder module here
assign {cout,sum} = a + b + cin;
endmodule
Carry-select adder
- 传统的级联加法器,随着加法器的数量不断增加,加法器的速度会变得越来越慢,这是因为每一个后级均在等待前一级的计算结果。故若我们更加追求执行速度而不在意资源使用的话,可使用超前进位加法器以获得更小的时延。
- 本题将两个带进位的16位数字相加,并生成一个输出进位和16位的和。并将输出进位用于控制一个16位2-1多路选择器,用于选择高位的计算结果。题目提供一个16位加法器模块,具体代码如下:
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] highout0;
wire [15:0] highout1;
wire cout;
add16 u_add16_low(
.a(a[15:0]),
.b(b[15:0]),
.cin(0),
.sum(sum[15:0]),
.cout(cout)
);
add16 u_add16_high0(
.a(a[31:16]),
.b(b[31:16]),
.cin(0),
.sum(highout0),
.cout()
);
add16 u_add16_high1(
.a(a[31:16]),
.b(b[31:16]),
.cin(1),
.sum(highout1),
.cout()
);
assign sum[31:16] = (cout)? highout1:highout0;
endmodule
Adder-subtractor
- 题目要求利用sub信号和两个16bit的全加器,实现32bit的加减法运算。对输入的sub信号进行判断,如果sub=0,则输出(a + b + 0);如果sub=1,则输出(a + ~b + 1)。题目提供一个16位加法器模块,具体代码如下:
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,
input sub,
output [31:0] sum
);
wire [31:0] b_processed;
wire cout_temp;
assign b_processed = b ^ {32{sub}};
add16 u_add16_lower(
.a(a[15:0]),
.b(b_processed[15:0]),
.cin(sub),
.sum(sum[15:0]),
.cout(cout_temp)
);
add16 u_add16_higher(
.a(a[31:16]),
.b(b_processed[31:16]),
.cin(cout_temp),
.sum(sum[31:16]),
.cout()
);
endmodule