模块
module是一个通过输入和输出端口与其外部交互的电路。更大、更复杂的电路是通过将更大的模块从更小的模块和连接在一起的其他部分(例如assign 语句和always模块)组成构建的。
这形成了一个层次结构,因为模块可以包含其模块的实例。
下图显示了一个带有子模块的的简单电路,通过创建一个module实例mod_a,然后将模块的三个引脚(in_1、in_2和out)连接到顶层模块的三个端口(wires a,b,and out),该模块是为您提供的,您必须实例化它
连接模块时,只有模块上的端口很重要,您不需要知道模块内部的代码。模块的代码mod_a如下所示:

module mod_a (input in1,input in2,output out);
// Module body
endmodule
模块的层次结构是通过在另一个模块中实例化一个模块来创建的,只要使用的所有模块都属于同一个项目(因此编译器知道在哪里可以找到该模块)。一个模块的代码没有写在另一个模块的主体中(不同模块的代码没有嵌套)。
将信号连接到模块端口
- 按位置
按位置将电线连接到端口的语法应该很熟悉,因为它使用类似 C 的语法。实例化模块时,端口根据模块的声明从左到右连接。例如:
mod_a instance1 (wa, wb, wc);
这会实例化一个类型为mod_a "instance1"的模块,然后将信号(在新模块之外)连接到新模块的第一个端口(in1)、第二个端口(in2)和第三个端口(out)。这种语法的一个缺点就是:如果模块的端口列表发生更改,则还需要找到并更改模块的所有实例以匹配新模块。
- 按名字
按名称将信号连接到模块的端口可以使线网即使在端口列表发生更改的情况下,保持正确连接。然而,这种语法更加冗长。
mod_a instance2(.out(wc),.in1(wa),.in2(wb))
上面的行实例化了一个mod_a名为“instance2”类型的模块,然后将wa(外部模块)连接到名为in1的端口,wb连接到名为in2端口,wc连接到out的端口。请注意这里的端口顺序如何是无关的,因为无论其在子模块端口列表中的位置如何,都将使用正确的名称进行连接,还要注意此语法中端口名称之前的点号.
题目.png
module top_module ( input a, input b, output out );
mod_a instance1(.in1(a),.in2(b),.out(out));
endmodule
-------------
[示例答案]
module top_module (
input a,
input b,
output out
);
// Create an instance of "mod_a" named "inst1", and connect ports by name: 创建一个mod_a实例,并将其命名为inst1
mod_a inst1 (
.in1(a), // Port"in1"connects to wire "a" ; in1连接到线网a
.in2(b), // Port "in2" connects to wire "b" : in2连接到线网b
.out(out) // Port "out" connects to wire "out" : out连接到线网out
// (Note: mod_a's port "out" is not related to top_module's wire "out".
// It is simply coincidence that they have the same name)
);
/*
// Create an instance of "mod_a" named "inst2", and connect ports by position:
mod_a inst2 ( a, b, out ); // The three wires are connected to ports in1, in2, and out, respectively.
*/
endmodule
-
按位置求解
例题2.png
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a inst1(out1,out2,a,b,c,d);
endmodule
-
按模块名称
image.png
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a inst1(.out1(out1), .out2(out2), .in1(a), .in2(b), .in3(c), .in4(d));
endmodule
模块移位(Module Shift)
您将获得一个my_dff具有两个输入和一个输出的模块(实现 D 触发器)。实例化其中的三个,然后将它们链接在一起以制作长度为 3 的移位寄存器。clk端口需要连接到所有实例。
提供的模块是: module my_dff ( input clk, input d, output q );
请注意,要建立内部连接,您需要声明一些连线。命名你的线网和模块实例时要小心:名称必须是唯一的。

module top_module ( input clk, input d, output q );
wire a,b;
my_dff f1(.clk(clk), .d(d) ,.q(a));
my_dff f2(.clk(clk), .d(a) ,.q(b));
my_dff f3(.clk(clk), .d(b) ,.q(q));
endmodule
/*在这里,可以看到有3个触发器,所以要实例化3个,但是q的输出端只有一个被实例化,还少两个需要被声明,因此首先就是声明两个线网类型*/
----
【示例解答:】
module top_module (
input clk,
input d,
output q
);
wire a, b; // Create two wires. I called them a and b.
// Create three instances of my_dff, with three different instance names (d1, d2, and d3).
// Connect ports by position: ( input clk, input d, output q)
my_dff d1 ( clk, d, a );
my_dff d2 ( clk, a, b );
my_dff d3 ( clk, b, q );
endmodule

module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] q
);
wire[7:0] a,b,c;
my_dff8 d1(clk,d,a);
my_dff8 d2(clk,a,b);
my_dff8 d3(clk,b,c);
always@(*) // always语句块,在断电或中断前,会一直执行
case(sel) // case语句,根据不同的sel值选择不同的输出值
2'b00: q = d; // 输入sel=00时,输出q=d
2'b01: q = a; // 输入sel=01时,输出q=a
2'b10: q = b;
2'b11: q = c;
endcase
endmodule
-------------
【示例答案】
module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output reg [7:0] q
);
wire [7:0] o1, o2, o3; // output of each my_dff8
// Instantiate three my_dff8s
my_dff8 d1 ( clk, d, o1 );
my_dff8 d2 ( clk, o1, o2 );
my_dff8 d3 ( clk, o2, o3 );
// This is one way to make a 4-to-1 multiplexer
always @(*) // Combinational always block
case(sel)
2'h0: q = d;
2'h1: q = o1;
2'h2: q = o2;
2'h3: q = o3;
endcase
endmodule
add16执行 16 位加法的模块。实例化其中两个以创建一个 32 位加法器。一个 add16 模块计算加法结果的低 16 位,而第二个 add16 模块在接收到第一个加法器的进位后计算结果的高 16 位。您的 32 位加法器不需要处理进位(假设为 0)或进位(忽略),但内部模块需要才能正常工作。(换句话说,add16模块执行 16 位 a + b + cin,而顶层模块执行 32 位 a + b)
如下图所示将模块连接在一起。提供的模块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[15:0] c,cout1;
add16 a1 (a[15:0] ,b[15:0],0,sum[15:0],c);
add16 a2 (a[31:16],b[31:16],c,sum[31:16],cout1);
assign sum = {sum[31:16],sum[15:0]};
endmodule
--------
[上面为我的求解,下面为B站UP主:脱发秘籍搬运工的求解:]
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cout1;
add16 add_1 (.a(a[15:0]), .b(b[15:0]), .cin(1'b0), .sum(sum[15:0]), .cout(cout1));
add16 add_2 (.a(a[31:16]), .b(b[31:16]), .cin(cout1), .sum(sum[31:16]), .cout());
endmodule
/*作者:脱发秘籍搬运工 https://www.bilibili.com/read/cv11188383?spm_id_from=333.788.b_636f6d6d656e74.12 出处:bilibili
*/
In this exercise, 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.
Like module_add, you are given a module add16 that performs a 16-bit addition. You must 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. Your 32-bit adder does not need to handle carry-in (assume 0) or carry-out (ignored).Connect the add16 modules together as shown in the diagram below. The provided module add16 has the following declaration:
module add16 ( input[15:0] **a**, input[15:0] **b**, input **cin**, output[15:0] **sum**, output **cout** );Within each add16, 16 full adders (module add1, not provided) are instantiated to actually perform the addition. You must write the full adder module that has the following declaration:
module add1 ( input a, input b, input cin, output sum, output cout );Recall that a full adder computes the sum and carry-out of a+b+cin.In summary, there are three modules in this design:
-
top_module— Your top-level module that contains two of... -
add16, provided — A 16-bit adder module that is composed of 16 of... -
add1— A 1-bit full adder module.
image.png
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);//
-----------------三个变量的大小要对应声明明确--------------------
wire[0:0] c1;
wire[15:0] sum1;
wire[31:16] sum2;
add16 add_1 (.a(a[15:0]), .b(b[15:0]), .cin(1'b0), .sum(sum1),.cout(c1));
add16 add_2 (.a(a[31:16]), .b(b[31:16]), .cin(c1), .sum(sum2));
assign sum = {sum2,sum1};
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
// Full adder module here
assign {cout,sum} = a + b + cin; // This is describtion for adder module. 这个需要消化理解下
endmodule

加法器计算进位的延迟(从进位,在最坏的情况下)相当慢,并且第二级加法器在第一级加法器完成之前无法开始计算其进位. 这使加法器变慢。一种改进是进位选择加法器,如下所示。第一级加法器和以前一样,但是我们复制第二级加法器,一个假设进位=0,一个假设进位=1,然后使用快速2对1多路复用器选择哪个结果碰巧是正确的。在本练习中,您将获得与上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 );
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
/*声明中间连接的线网变量*/
wire [0:0] cout1;
wire [15:0] sum1;
wire [15:0] sum2;
wire [15:0] sum3;
wire [15:0] sum_2;
/*三个加法器实例,要明确数据选择器存在的真实含义是什么*/
add16 a_1(.a(a[15:0]),.b(b[15:0]),.cin(1'b0),.sum(sum1),.cout(cout1));
add16 a_2(.a(a[31:16]),.b(b[31:16]),.cin(1'b0),.sum(sum2));
add16 a_3(.a(a[31:16]),.b(b[31:16]),.cin(1'b1),.sum(sum3));
assign sum_2 = cout1?sum3:sum2;
assign sum = {sum_2,sum1};
endmodule
- An adder-subtractor can be built from an adder by optionally negating one of the inputs, which is equivalent to inverting the input then adding 1. The net result is a circuit that can do two operations: (a + b + 0) and (a + ~b + 1). See Wikipedia if you want a more detailed explanation of how this circuit works.Build the adder-subtractor below.You are provided with a 16-bit adder module, which you need to instantiate twice:
module add16 ( input[15:0] **a**, input[15:0] **b**, input **cin**, output[15:0] **sum**, output **cout** );Use a 32-bit wide XOR gate to invert the b input whenever sub is 1. (This can also be viewed as b[31:0] XORed with sub replicated 32 times)Also connect the sub input to the carry-in of the adder.

这里首先需要了了解到b与sub的异或是让sub连续复制32次再与a异或;其他解答思路同上一题:
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire [31:0] b1;
wire c1;
wire [15:0] sum1;
wire [31:16] sum2;
assign b1 = b ^ {32{sub}}; // b XOR sub
add16 a1(.a(a[15:0]),.b(b1[15:0]),.cin(sub),.sum(sum1),.cout(c1));
add16 a2(.a(a[31:16]),.b(b1[31:16]),.cin(c1),.sum(sum2));
assign sum = {sum2,sum1};
endmodule



