提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
到目前为止,您已经熟悉了模块,它是一种通过输入和输出端口与外部进行交互的电路。更大、更复杂的电路是由更小的模块和连接在一起的其他模块(如赋值语句和总是块)组成更大的模块来构建的。这就形成了一个层次结构,因为模块可以包含其他模块的实例。
一、Module:Hierarchy
1.Module
Practice: create one instance of module mod_a, then connect the module’s three pins (in1, in2, and out) to your top-level module’s three ports (wires a, b, and out). The module mod_a is provided for you — you must instantiate it.
翻译:根据下图,实例化一个下层模块mod_a,将其三个端口in1,in2,out按照图中的连接方式,分别连接到顶层模块的a,b,out端口上。mod_a模块已默认提供给你,不需要自己写,只需在顶层模块中例化它即可。模块的例化有两种方式:按端口位置和按端口名称
module mod_a ( input in, output out ); //定义了一个名为mod_a的模块
... // Module body
endmodule
module top_module ( input a, output out ); //定义了名为top_module的模块
mod_a instance1 ( .in(a), .out(out)); //在top_module模块中例化mod_a模块
endmodule
//mod_a是被例化模块的模块名,instance1是实例名,()内是两个模块的端口信号的连接
Solution(不唯一,仅供参考):
module top_module ( input a, input b, output out );
mod_a instance1(.in1(a), .in2(b), .out(out));
endmodule
Timing Diagram
2.Connecting ports by position
Practice:You are given a module named mod_a that has 2 outputs and 4 inputs, in that order. You must connect the 6 ports by position to your top-level module’s ports out1, out2, a, b, c, and d, in that order.
翻译:得到一个名为mod_a的模块,它有2个输出和4个输入,按此顺序。按照下图的关系进行例化。
Solution(不唯一,仅供参考):
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a instance1(out1,out2,a,b,c,d);//注意输出和输入的顺序
endmodule
Timing Diagram
3.Connecting ports by name
Practice: You are given a module named mod_a that has 2 outputs and 4 inputs, in some order. You must connect the 6 ports by name to your top-level module’s ports:
翻译:你会得到一个名为mod_a的模块,它有2个输出和4个输入,按某种顺序。你必须按名称将这6个端口连接到你的顶级模块的端口.
提示:本题的例化方法与第一次例化方法相同,此方法在对应好每个端口后,可以不用考虑顺序问题,
Solution(不唯一,仅供参考):
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a instance1(
.in1(a),
.in2(b),
.in3(c),
.in4(d),
.out1(out1),
.out2(out2)
);
endmodule
Timing Diagram
4.Three modules
Practice:You are given a module my_dff with two inputs and one output (that implements a D flip-flop). Instantiate three of them, then chain them together to make a shift register of length 3. The clk port needs to be connected to all instances…
翻译:给你一个模块my_dff,它有两个输入和一个输出(它实现了一个D触发器)。实例化其中三个,然后将它们链接在一起,形成长度为3的移位寄存器。如下图所示。
Solution(不唯一,仅供参考):
module top_module ( input clk, input d, output q );
wire q1,q2;
my_dff my_dff1(clk,d,q1);
my_dff my_dff2(clk,q1,q2);
my_dff my_dff3(clk,q2,q);
endmodule
法二
module top_module ( input clk, input d, output q );
wire q1,q2;
my_dff my_dff1(.clk(clk), .d(d), .q(q1));
my_dff my_dff2(.clk(clk), .d(q1), .q(q2));
my_dff my_dff3(.clk(clk), .d(q2), .q(q));
endmodule
Timing Diagram
5.Modules and vectors
Practice:You are given a module my_dff8 with two inputs and one output (that implements a set of 8 D flip-flops). Instantiate three of them, then chain them together to make a 8-bit wide shift register of length 3. In addition, create a 4-to-1 multiplexer (not provided) that chooses what to output depending on sel[1:0]: The value at the input d, after the first, after the second, or after the third D flip-flop.
翻译:给您一个模块my_dff8,它有两个输入和一个输出(它实现了一组8个D触发器)。实例化其中三个,然后将它们链接在一起,形成一个长度为3的8位宽移位寄存器。另外,创建一个4选1的多路选择器器(未提供),它根据sel[1:0]选择输出内容:输入d处的值,在第一个、第二个或第三个d触发器之后。
Solution(不唯一,仅供参考):
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'b00: q=d;
2'b01: q=q1;
2'b10: q=q2;
2'b11: q=q3;
endcase
end
endmodule
Timing Diagram
6.Adder 1
Practice:You are given a module add16 that performs a 16-bit addition. Instantiate two of them to create a 32-bit adder. One add16 module computes the lower 16 bits of the addition result, while the second add16 module computes the upper 16 bits of the result, after receiving the carry-out from the first adder. Your 32-bit adder does not need to handle carry-in (assume 0) or carry-out (ignored), but the internal modules need to in order to function correctly. (In other words, the add16 module performs 16-bit a + b + cin, while your module performs 32-bit a + b).
翻译:给了一个实现16位加法器的模块add16,实例化两个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 );
Solution(不唯一,仅供参考):
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cout1;
add16 add1(.a(a[15:0]),
.b(b[15:0]),
.cin(1'b0),
.sum(sum[15:0]),
.cout(cout1));
add16 add2(.a(a[31:16]),
.b(b[31:16]),
.cin(cout1),
.sum(sum[31:16]),
.cout());
endmodule
Timing Diagram
7.Adder 2
Practice:you will create a circuit with two levels of hierarchy. Your top_module will instantiate two copies of add16 (provided), each of which will instantiate 16 copies of add1 (which you must write). Thus, you must write two modules: top_module and add1.
翻译:你将创建一个有两个层次的电路。top_module将实例化add16的两个副本(提供),每个副本将实例化add1的16个副本(自己编写)。因此,必须编写两个模块:top_module和add1。
提示:add1需要自己编写,全加器的逻辑表达式 为sum = a ^ b ^ cin; cout = a&b | a&cin | b&cin;
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
Solution(不唯一,仅供参考):
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cout1;
add16 add_16(
.a(a[15:0]),
.b(b[15:0]),
.cin(0),
.sum(sum[15:0]),
.cout(cout1)
);
add16 add_32(
.a(a[31:16]),
.b(b[31:16]),
.cin(cout1),
.sum(sum[31:16]),
.cout()
);
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
assign {cout,sum} = a+b+cin;
//或采用逻辑表达式
//assign sum = a^b^cin;
//assign cout = cout = a&b | a&cin | b&cin;
endmodule
Timing Diagram
8.Carry-aselect adder
Practice:In this exercise, you are provided with the same module add16 as the previous exercise, which adds two 16-bit numbers with carry-in and produces a carry-out and 16-bit sum. You must instantiate three of these to build the carry-select adder, using your own 16-bit 2-to-1 multiplexer.
翻译:在本练习中,为您提供与上一个练习相同的模块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 );
Solution(不唯一,仅供参考):
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire sel;
wire [31:16] sum1,sum2;
add16 add16_0(
.a(a[15:0]),
.b(b[15:0]),
.cin(1'b0),
.sum(sum[15:0]),
.cout(sel)
);
add16 add16_1(
.a(a[31:16]),
.b(b[31:16]),
.cin(1'b0),
.sum(sum1[31:16]),
.cout()
);
add16 add16_2(
.a(a[31:16]),
.b(b[31:16]),
.cin(1'b1),
.sum(sum2[31:16]),
.cout()
);
assign sum[31:16] = sel?sum2:sum1;//也可以使用case语句
endmodule
Timing Diagram
8.Adder-subtractor
Practice:Build the adder-subtractor below.
翻译:构建下面的加-减法器。如图所示
**提示:**加-减法器可以由加法器构建,可选地对其中一个输入取反,这相当于将输入取反,然后加1。最终的结果是一个可以进行(a + b + 0)和(a + ~b + 1)两种操作的电路。
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
出错 assign bb = b^sub;
改进 assign bb = b^{32{sub}};
Solution(不唯一,仅供参考):
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire cout1;
wire[31:0] bb;
assign bb = b^{32{sub}};
add16 add1(
.a(a[15:0]),
.b(bb[15:0]),
.cin(sub),
.sum(sum[15:0]),
.cout(cout1)
);
add16 add2(
.a(a[31:16]),
.b(bb[31:16]),
.cin(cout1),
.sum(sum[31:16]),
.cout()
);
endmodule
Timing Diagram
总结
1、 在顶层模块中实例化(简称例化)下层模块时,只需关注下层模块的端口,而不必在乎它的内部代码。模块的层次化结构通过在一个模块中例化另一个模块来实现,只要这些模块都处于一个project(项目)中,编译器就能找到相对应的模块。注意,在一个模块中可以例化,但不允许定义和编写其他模块。
2、数字IC有自顶向下和自底向上两种设计方法。前者先定义顶层功能块,再对其分析并不断分解成一个个子模块,直至无法进一步分解的底层功能块;后者先分析现有的功能块,然后用它们搭建更大规模的模块,直至顶层功能块。Verilog就用module(模块)来表示这一个个的功能块(具有特定功能的一块块电路),它可大可小,大到一个微处理器,小到一个晶体管,原则上都可作为一个模块。
3、always @()其中括号内加星号就是表示模块中所有的向量,也可以写为
always @(clk or d or sel or q)
4、全加器的逻辑表达式 为sum = a ^ b ^ cin; cout = a&b | a&cin | b&cin;sum表示和,cout表示进位。
5、6 7题实现的是行波进位加法器(也称串行进位或逐位进位加法器),这类加法器的缺点是较高位的相加结果必须等到低一位的进位产生之后才能开始计算,这使得加法器的计算延迟变大。选择进位是一种改进方法,如图所示,第一级加法器与之前相同,但第二级加法器有两个,一个假设进位为0,另一个假设进位为1,然后用2选1多路选择器来选择哪个是正确的。
6、例化的方法有两种
my_dff my_dff1(.clk(clk), .d(d), .q(q1));
my_dff my_dff1( clk, d, q);//按序排列
最好使用第一种方法,不容易出错