参考链接:HDLBits导学
Problem 19 : Modules
问题:在顶层模块中例化下面的模块
思路:例化有两种方式
按端口顺序,mod_a instance1 ( wa, wb, wc );根据原模块的端口顺序例化(端口列表发生变化后修改很麻烦)
按端口名称,mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) ); 直接对应端口名称进行例化
解决:
module top_module ( input a, input b, output out );
mod_a mod_a_inst(
.in1(a),
.in2(b),
.out(out)
);
endmodule
Problem 20: Connecting ports by position(Module pos)
问题:按端口顺序例化下图模块
解决:
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a mod_a_inst(out1,out2,a,b,c,d);
endmodule
Problem 21: Connecting ports by name(Module name)
问题:按照端口名称例化下图模块
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_inst(
.out1(out1),
.out2(out2),
.in1(a),
.in2(b),
.in3(c),
.in4(d)
);
endmodule
注意:例化端口名和顶层模块名别搞反了
Problem 22: Three modules(Module shift)
问题:实例化三个my_dff,然后将它们连接在一起,构成长度为3的移位寄存器。注意:clk端口需要连接到所有的寄存器实例上
思路:从图中可以看出第二个my_dff的输入端口是第一个my_dff的输入端口,顶层模块的输入输出没有连接它们,所以它们之间需要定义一根线来连接,第二个到第三个同理
解决:
module top_module ( input clk, input d, output q );
wire d2,d3;
my_dff my_dff_inst1(
.clk(clk),
.d(d),
.q(d2)
);
my_dff my_dff_inst2(
.clk(clk),
.d(d2),
.q(d3)
);
my_dff my_dff_inst3(
.clk(clk),
.d(d3),
.q(q)
);
endmodule
Problem 23: Modules and vectors(Module shift8)
问题:给出了一个名为my_dff8的模块,包含两个输入和一个输出(实现一个8bit的D触发器)。请实例化三个,并将它们连接在一起,形成一个长度为3的8bit移位寄存器。此外,再写出一个4选1多路复用器(未提供模块模型),根据输入的sel[1:0]选择要输出的内容:输入D的值,在第一个D触发器之后的值,第二个或第三个D触发器之后的值。(可以说sel选择的是输入延迟的的周期数,0~3个时钟周期不等。)
思路:相比于上一道题增加了一个四选一的选择器,使用always完成
解决:
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 my_dff_inst1(
.clk(clk),
.d(d),
.q(q1)
);
my_dff8 my_dff_inst2(
.clk(clk),
.d(q1),
.q(q2)
);
my_dff8 my_dff_inst3(
.clk(clk),
.d(q2),
.q(q3)
);
always @(*) begin
case(sel)
2'b00:q = d;
2'b01:q = q1;
2'b10:q = q2;
2'b11:q = q3;
endcase
end
endmodule
注意:此时wire的位宽为8位
Problem 24: Adder 1(Module add)
问题:给出了一个可以做16bit加法的模块add16,实例化两个add16以达到32bit加法的。一个add16模块计算结果的低16位,另一个add16模块在接收到第一个的进位后计算结果的高16位。此32bit加法器不需要处理输入进位(假设为0)和输出进位(无需进位),但为了内部模块为了结果的正确仍要处理进位信号。(换句话说,add16模块执行16bit的a+b+cin,而顶层模块执行32bit的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 cout1;
wire[15:0] sum1,sum2;
add16 add16_inst1(
.a(a[15:0]),
.b(b[15:0]),
.cin(0),
.sum(sum1),
.cout(cout1)
);
add16 add16_inst2(
.a(a[31:16]),
.b(b[31:16]),
.cin(cout1),
.sum(sum2),
);
assign sum = {sum2,sum1};
endmodule
Problem 25: Adder 2(Module fadd)
问题:在本题中,您将描述一个具有两级层次结构的电路。在top_module中,实例化两个add16模块(已为您提供),每个add16中实例化16个add1实例(此模块需要您编写)。所以,您需要描述两个模块:top_module和add1
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
module add1 ( input a, input b, input cin, output sum, output cout );
思路:这个题和上一个题是类似的,add_16模块已经定义好了,但是需要自己实现add_1的全加器,从来实现add_16
借用大佬的写法,我只会++++
assign sum = a^b^cin;
assign cout = (a&b)|(a&cin)|(b&cin);
解决:
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);//
wire cout1;
wire[15:0] sum1,sum2;
add16 add16_inst1(
.a(a[15:0]),
.b(b[15:0]),
.cin(0),
.sum(sum1),
.cout(cout1)
);
add16 add16_inst2(
.a(a[31:16]),
.b(b[31:16]),
.cin(cout1),
.sum(sum2),
);
assign sum = {sum2,sum1};
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
// Full adder module here
assign sum = a^b^cin;
assign cout = (a&b)|(a&cin)|(b&cin);
endmodule
Problem 26: Carry-select adder (Module cseladd)
概述:上一个练习中(Problem 25: Adder 2(Module fadd))实现的加法器应该叫做行波进位加法器(RCA: Ripple-Carry Adder)。这种加法器的缺点是计算进位输出的延迟是相当慢的(最坏的情况下,来自于进位输入)。并且如果前一级加法器计算完成之前,后一级加法器不能开始计算。这又使得加法器的计算延迟变大。
问题:这次来实现一个改进型的加法器,如下图所示。第一级加法器保持不变,第二级加法器实现两个,一个假设进位为0,另一个假设进位为1。然后使用第一级结果和2选一选择器来选择哪一个结果是正确的。
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
思路:高位加法器定义两个,一个的进位为1,另一个的进位为0,然后由低位加法器的进位来选择最后哪一个加法器输出
解决:
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);//
wire cout1;
wire[15:0] sum1,sum2_1,sum2_2;
add16 add16_inst1(
.a(a[15:0]),
.b(b[15:0]),
.cin(0),
.sum(sum1),
.cout(cout1)
);
add16 add16_inst2_1(
.a(a[31:16]),
.b(b[31:16]),
.cin(0),
.sum(sum2_1),
);
add16 add16_inst2_2(
.a(a[31:16]),
.b(b[31:16]),
.cin(1),
.sum(sum2_2),
);
assign sum = cout1?{sum2_2,sum1}:{sum2_1,sum1};
endmodule
Problem 27: Adder–subtractor (Module addsub)
概述:加减法器可以由加法器来构建,可以对其中一个数取相反数(对输入数据取反,然后加1。最终结果是一个可以执行以下两个操作的电路:(a + b + 0) 和 (a + ~b + 1)
问题:如下图所示构建加减法器,您需要实例化两次下面给出的16bit加法器模块:
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次相异或,请参阅复制运算符Problem 17: Replication operator(Vector4))。同时sub信号连接到加法器的进位。
思路:sub重复32次的写法,sum分开进行输出,不使用拼接
解决:
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire carry;
wire[31:0] b_nb = b^{32{sub}};
add16 add16_inst1(
.a(a[15:0]),
.b(b_nb[15:0]),
.cin(sub),
.sum(sum[15:0]),
.cout(carry)
);
add16 add16_inst2(
.a(a[31:16]),
.b(b_nb[31:16]),
.cin(carry),
.sum(sum[31:16]),
);
endmodule