Module
1 Module
截止目前,我们已经对 Verilog 中模块这一概念建立了初步的印象:模块是一个电路,通过输入输出端口和外部的电路联系。无论多大,多复杂的数字电路都是由一个个模块以及其他组成部分(比如 assign 赋值语句以及 always 过程块)互相连接所构成的。在一个模块中可以例化下一级的模块,这就形成了层级的概念(hierarchy)。
下图展示了一个简单的,拥有下级模块的模块。在本题的练习中,创建一个下级模块 mod_a,将其的三个端口 in1 ,in2 ,out 按照图中的连接方式,分别连接到顶层模块的 a ,b,out 端口上。mod_a 已经在测试代码中提供给你,你不需要自己写一个模块,只需要在你的顶层模块中,例化 mod_a 模块即可。
当你从顶层模块的角度看去,下层模块 mod_a 对你来说就是一个黑盒子,盒子里的内容并不重要。重要的是模块的输入输出端口。
并不在乎 module body 中有什么
模块的层级是通过在模块中例化下一级模块产生的。虽然不同的模块写在不同的 .v 文件中,(一般推荐一个 .v 文件中只写一个模块),但只要这些模块在 ISE/Vivado/Quartus 这些开发软件中处于一个 Project。综合器就能在你例化模块时,找到对应的模块和 .v 文件。
模块中可以例化其他模块,但在模块中不允许再定义其他模块。这项语法规则类似于在 C 语言函数中可以调用其他函数,但不能定义其他函数。
模块信号连接的两种方式
在实例化模块时,有两种常用的方式来进行模块端口的信号连接:按端口顺序以及按端口名称连接端口。
按端口名称,mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) );
在这种方式中根据端口名称指定外部信号的连接。这样一来就和端口声明的顺序完全没有关系。一旦模块出现改动,只要修改相应的部分即可。实际上,一般都使用这种方式来进行模块实例化。
module top_module ( input a, input b, output out );
mod_a instance1(.out(out)
,.in1(a)
,.in2(b));
//,在实例化模块时,一般一个端口用一行表示,这样更直观一些。至于逗号放在前面还是放在后面,那倒无所谓。
//括号里的是top module
endmodule
2 Module pos
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a name(out1,out2,a,b,c,d);
endmodule
但是在本题中对于给出的模块来说,我们并不知道mod_a这个模块的端口名是什么,所以对于本题来说,只能按照位置的顺序来连接。对于题中给出的模块来说,如果在写文档的时候这样只表注输入输出端口而没有名字是不规范的。自己写文档的时候要避免。
3 Module name
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a instance1(.out1(out1),
.out2(out2),
.in1(a),
.in2(b),
.in3(c),
.in4(d));
endmodule
4 Module shift
module top_module ( input clk, input d, output q );
wire q1;
wire q2;
my_dff instance1(.clk(clk),
.d(d),
.q(q1));
my_dff instance2(.clk(clk),
.d(q1),
.q(q2));
my_dff instance3(.clk(clk),
.d(q2),
.q(q));
endmodule
5 Module shift8
四选一多路选择器不会
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 instance1(.clk(clk),
.d(d),
.q(q1));
my_dff8 instance2(.clk(clk),
.d(q1),
.q(q2));
my_dff8 instance3(.clk(clk),
.d(q2),
.q(q3));
always @(*)
case(sel)
2'h0: q =d;
2'h1: q =q1;
2'h2: q =q2;
2'h3: q =q3;
endcase
endmodule
6 Module add
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cin1,cin2;
wire [15:0] score1,score2;
add16 instance1(.cin(1'b0),
.a(a[15:0]),
.b(b[15:0]),
.cout(cin1),
.sum(score1));
add16 instance2(.cin(cin1),
.a(a[31:16]),
.b(b[31:16]),
.cout(cin2),
.sum(score2));
assign sum={score2,score1};
endmodule
7 Module fadd
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);//
wire [15:0] score0,score1;
wire cout1;
add16 instance1(.a(a[15:0]),.b(b[15:0]),.cin(1'b0),.cout(cout1),.sum(score0));
add16 instance2(.a(a[31:16]),.b(b[31:16]),.cin(cout1),.sum(score1));
assign sum={score1,score0};
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
assign sum=a^b^cin;
assign cout=(a&b)|(cin&b)|(a&cin);
// Full adder module here
endmodule
8 Module cseladd
上一个练习中(Problem 25: Adder 2(Module fadd))实现的加法器应该叫做行波进位加法器(RCA: Ripple-Carry Adder)。这种加法器的缺点是计算进位输出的延迟是相当慢的(最坏的情况下,来自于进位输入)。并且如果前一级加法器计算完成之前,后一级加法器不能开始计算。这又使得加法器的计算延迟变大。
牛刀小试
这次来实现一个改进型的加法器,如下图所示。第一级加法器保持不变,第二级加法器实现两个,一个假设进位为0,另一个假设进位为1。然后使用第一级结果和2选一选择器来选择哪一个结果是正确的。
在本题中,您将获得与上一练习相同的模块add16,它将两个16bit数和进位输入相加,并产生16bit的结果和进位输出。您必须实例化其中的三add16来构建进位选择加法器,同时实现16bit的2选1选择器来选择结果。
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cout1;
wire [15:0] score0;
wire [31:16] score1,score2;
add16 instance1(.a(a[15:0]),.b(b[15:0]),.cin(1'b0),.cout(cout1),.sum(score0));
add16 instance2(.a(a[31:16]),.b(b[31:16]),.cin(1'b0),.sum(score1));
add16 instance3(.a(a[31:16]),.b(b[31:16]),.cin(1'b1),.sum(score2));
assign sum=cout1?{score2,score0}:{score1,score0};
endmodule
9 Module addsub
当sub为1时,使用32位的异或门对B进行取反。(这也可以被视为b[31:0]与sub复制32次相异或,请参阅复制运算符Problem 17: Replication operator(Vector4))。同时sub信号连接到加法器的进位。
小提示:异或门也可以看作是可编程的非门,其中一个输入控制是否应该反转另一个。 以下两个电路都是异或门:
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire cout1;
wire [31:0] subb=b^{32{sub}};
add16 instance1(.a(a[15:0]),.b(subb[15:0]),.cin(sub),.cout(cout1),.sum(sum[15:0]));
add16 instance2(.a(a[31:16]),.b(subb[31:16]),.cin(cout1),.sum(sum[31:16]));
endmodule