HDLBits刷题合集—4 Modules:Hierarchy
HDLBits-17 Module
Problem Statement
下图显示了一个带有子模块的非常简单的电路。在本练习中,创建模块mod_a的一个实例,然后将模块的三个引脚(in1、in2和out)连接到顶层模块的三个端口(连接a、b和out)。mod_a模块已经为你提供,你使用时必须实例化它。
在连接模块时,只有模块上的端口是重要的。不需要知道模块内部的代码。模块mod_a的代码如下:
module mod_a ( input in1, input in2, output out );
// Module body
endmodule
模块的层次结构是通过在另一个模块中实例化一个模块来创建的,只要使用的所有模块都属于同一个工程(这样编译器就知道在哪里可以找到模块)。一个模块的代码不能写在另一个模块的内部(即不同模块的代码不嵌套)。
可以通过端口名或端口位置将信号连接到模块。可以额外的练习,尝试这两种方法。
将信号连接到模块端口
有两种常用的方法将线路连接到端口:按位置或按名称。
按位置
按照位置将连接线连接到端口的语法应该很熟悉,因为它使用类似C语言的语法。在实例化模块时,根据模块的声明从左到右连接端口。例如:
mod_a instance1 (wa, wb, wc);
它实例化一个mod_a类型的模块,并给它一个实例名“instance1”,然后将信号wa(新模块的外部)连接到新模块的第一个端口(in1),将wb连接到第二个端口(in2),将wc连接到第三个端口(out)。这种语法的一个缺点是,如果模块的端口列表发生更改,还需要找到并更改模块的所有实例以匹配新模块。
按名称
通过名称将信号连接到模块的端口,即使端口列表改变,连接也能保持正确。但是,这种语法更冗长。
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 );
//By name
mod_a instance1 (.out(out), .in1(a), .in2(b));
endmodule
HDLBits-18 Module positoin
Problem Statement
这个问题与前一个问题类似。给定一个名为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 name1( out1, out2, a, b, c, d);
endmodule
HDLBits-19 Module name
Problem Statement
这个问题还是与第17个问题类似。给定一个名为mod_a的模块,它有2个输出和4个输入,按某种顺序排列。你必须通过名称将6个端口连接到顶层模块的端口:
Port in mod_a | Port in top_module |
---|---|
output out1 | out1 |
output out1 | out2 |
input in1 | a |
input in2 | b |
input in3 | c |
input in4 | d |
给定的模块是:
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 name2 (.out1(out1), .out2(out2), .in1(a), .in2(b), .in3(c), .in4(d));
endmodule
HDLBits-20 Module shift
Problem Statement
给定一个模块my_dff,有两个输入和一个输出(实现一个D触发器)。实例化模块my_dff三次,然后将它们连接在一起,形成长度为3的移位寄存器。clk端口需要连接到所有实例。
给定的模块是:
module my_dff ( input clk, input d, output q );
注意要进行内部连接,需要声明一些wire。在对wire和模块实例进行命名时要小心:这些名称必须是惟一的。
module top_module ( input clk, input d, output q );
wire q1,q2;
my_dff dff1( clk, d, q1);
my_dff dff2( clk, q1, q2);
my_dff dff3( clk, q2, q);
endmodule
HDLBits-21 Module shift8
Problem Statement
这个练习是上一题module_shift的延申。模块端口不再是单一的引脚,而是以向量为端口,你可以将线向量而不是普通的导线连接到模块上。
给定一个模块my_dff8,它有两个输入和一个输出(实现一个8位的D触发器)。实例化my_dff8三次,然后将它们连接在一起,形成一个长度为3的8位宽移位寄存器。
此外,创建一个4选1多路复用选择器(没有提供),它根据sel[1:0]选择输出什么:在输入d处的值,在第一个D触发器之后、第二个D触发器之后或第三个D触发器之后。(本质上,sel选择多少周期来延迟输入,从0到3个时钟周期。)
给定的模块是:
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] q1,q2,q3;
my_dff8 dff1 (clk, d, q1);
my_dff8 dff2 (clk, q1, q2);
my_dff8 dff3 (clk, q2, q3);
always @(*)
begin
case(sel)
2'h0: q = d;
2'h1: q = q1;
2'h2: q = q2;
2'h3: q = q3;
endcase
end
endmodule
HDLBits-22 Module add
Problem Statement
给定一个执行16位加法的模块add16。实例化两次来创建一个32位加法器。一个add16模块计算加法结果的低16位,在接收到第一个加法器的执行之后,第二个add16模块计算结果的高16位。设计的32位加法器不需要处理低位的进位(假设为0)或向高位的进位(忽略),但是内部模块需要正确连接才能正确地工作。(换句话说,add16模块执行16位a + b + cin,而设计的模块执行32位a + b)。
给定的模块是:
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 cin,cout1,cout2;
wire [15:0] sum1,sum2;
assign cin=0;
add16 add1 (.a(a[15:0]), .b(b[15:0]), .cin(cin), .sum(sum1), .cout(cout1));
add16 add2 (a[31:16], b[31:16], cout1, sum2, cout2);
assign sum = {sum2,sum1};
endmodule
HDLBits-23 Module fadd
Problem Statement
在本练习中,你将创建一个具有两个层次结构的电路。top_module将实例化2次add16(提供的),每个add16实例化16次add1(必须自己编写)。因此,必须编写两个模块:top_module和add1。
与上一题module_add一样,你将获得一个执行16位加法的add16模块。你必须实例化2次来创建一个32位加法器。一个add16模块计算加法结果的低16位,而第二个add16模块计算结果的高16位。设计的32位加法器不需要处理低位进位(假设为0)或向高位进位(忽略)。
所提供的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 );
回想一下,全加法器进位CO与和SUM计算a+b+cin。
综上所述,本次设计共有三个模块:
top_module — 顶层模块包括两个add16模块
add16, provided — 一个16位加法器包括16个一位加法器
add1 — 一个一位全加器模块
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);//
wire cin1,cout1,cout2;
wire [15:0] sum1,sum2;
assign cin1=0;
add16 add1 (a[15:0], b[15:0], cin1, sum1[15:0], cout1);
add16 add2 (a[31:16], b[31:16], cout1, sum2[15:0], cout2);
assign sum = {sum2, sum1};
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;
// Full adder module here
endmodule
HDLBits-24 Module cseladd
Problem Statement
行波进位加法器的一个缺点(参见前面的练习)是加法器计算执行的相当慢。第二级加法器在第一级加法器完成之前不能开始执行计算,这使得加法器变慢。一种改进是进位选择加法器,如下所示。第一级加法器和前面一样,但是我们复制了第二级加法器,一个假设进位为0,另一个假设进位为1,然后使用一个快速的2选1多路复用器来选择执行哪一个。
在本练习中,向你提供了与前一个练习相同的模块add16,它将两个16位数字与低位进位相加,并生成一个16位的和。必须使用自己的16位2选1多路复用器实例化三个add16模块来构建c进位选择加法器。
给定的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 cin,cin1,cin2,cout;
wire [15:0] sum0, sum1, sum2,sum_h;
assign cin = 0;
assign cin1 = 0;
assign cin2 = 1;
add16 add0 (a[15:0], b[15:0], cin, sum0[15:0], cout);
add16 add1 (a[31:16], b[31:16], cin1, sum1[15:0],);
add16 add2 (a[31:16], b[31:16], cin2, sum2[15:0],);
always @(*)
begin
case(cout)
1'b0: sum_h = sum1;
1'b1: sum_h = sum2;
endcase
end
assign sum = {sum_h,sum0};
endmodule
HDLBits-25 Module addsub
Problem Statement
加法减法器可以利用加法器构建,方法是选择性地对其中一个输入求反,这等价于先对输入求反码,然后再加1。最终的结果是一个可以做两种操作(即加法和减法)的电路:(a + b + 0)和(a + ~b + 1)。
给定的add16模块是:
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] 与复制32次的sub异或),还要将sub连接到加法器的低位来的进位。
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire [31:0] b_n;
wire cout1,cout2;
assign b_n = b ^ {32{sub}};
add16 add0 (a[15:0], b_n[15:0], sub, sum[15:0], cout1);
add16 add1 (a[31:16], b_n[31:16], cout1, sum[31:16], cout2);
endmodule
Note
新手一枚,主要分享博客,记录学习过程,后期参考大佬代码或思想会一一列出。欢迎大家批评指正!