Verilog模块实例化
正如我们在前一篇文章中看到的,更大、更复杂的设计是通过以分层的方式集成多个模块来构建的。模块可以在其他模块中实例化,这些实例的端口可以与父模块中的其他信号连接。这些端口连接可以通过有序列表或按名称进行。
端口连接按顺序排列
在模块实例中列出的端口表达式与父模块内部的信号之间建立连接的一种方法是通过有序列表。
mydesign是在名为tb_top的另一个模块中以名称d0实例化的模块。 端口以一定顺序连接,该顺序由该端口在模块声明的端口列表中的位置确定。 例如,测试台中的b连接到设计的y仅仅是因为两者都在端口列表中的第二个位置。
module mydesign ( input x, y, z, // x is at position 1, y at 2, x at 3 and
output o); // o is at position 4
endmodule
module tb_top;
wire [1:0] a;
wire b, c;
mydesign d0 (a[0], b, a[1], c); // a[0] is at position 1 so it is automatically connected to x
// b is at position 2 so it is automatically connected to y
// a[1] is at position 3 so it is connected to z
// c is at position 4, and hence connection is with o
endmodule
为了正确连接,应知道设计模块中端口的顺序。
这非常不方便,因为如果将新端口添加到列表中或设计中的端口数量很大,则顺序可能会更改。
端口按名称连接
连接端口的更好方法是使用端口名称在两侧显式链接端口。
“.”表示点后面的端口名称属于该设计。 接下来必须在括号()中给出设计端口必须连接的信号名称。
module design_top;
wire [1:0] a;
wire b, c;
mydesign d0 ( .x (a[0]), // mydesign中的信号“ x”应连接到该模块中的“ a [0]”(design_top)
.y (b), //mydesign中的信号“ y”应连接到此模块中的“ b”(design_top)
.z (a[1]),
.o (c));
endmodule
建议将每个端口连接编码在单独的行中,以便任何编译错误消息都将正确指向发生错误的行号。 与不知道是哪个端口在同一行中而导致错误相比,调试和解决起来要容易得多。
由于这些连接是按名称建立的,因此它们的出现顺序无关紧要。 不允许多个模块实例端口连接。
module design_top;
mydesign d0 ( .x (a[0]),
.z (a[1]), // z at second position is okay because of explicit connection
.y (a[1]),
.x (b), // illegal - x is already connected to a[0]
.o (c));
endmodule
未连接/浮动端口
未连接到实例化模块中任何电线的端口将具有高阻抗值。
module design_top;
mydesign d0 ( // x是输入且未连接,因此a [0]将为Z
.y (a[1]),
.z (a[1]),
.o ()); //o在mydesign中具有有效值,但由于它未连接到design_top中的“ c”,因此c为Z
endmodule
例
让我们以我们之前看到的移位寄存器为例,并保留一些未连接的端口。
module shift_reg ( input d,
input clk,
input rstn,
output q);
wire [2:0] q_net;
dff u0 (.d(d), .clk(clk), .rstn(rstn), .q(q_net[0]));
dff u1 (.d(q_net[0]), .clk(clk), .rstn(rstn), .q()); // Output q is left floating
dff u2 (.d(q_net[1]), .clk(clk), .rstn(rstn), .q()); // Output q is left floating
dff u3 (.d(q_net[2]), .clk(clk), .rstn(rstn), .q(q));
endmodule
请注意,实例u1和u2的输出在合成后获得的RTL示意图中保持未连接状态。由于实例u2和u3的输入d现在已连接到不受任何接地驱动的nets。
在仿真中,这种未连接的端口将被表示为高阻抗('hZ),通常以波形形式显示为中间垂直对齐的橙色线。
所有端口声明都隐式声明为wire,因此在这种情况下,端口方向就足够了。 但是,需要存储值的输出端口应声明为reg数据类型,并且可以在程序块中使用,如Always和initial块。
input或inout类型的端口不能声明为reg,因为它们是从外部连续驱动的,不应存储值,而应尽快反映外部信号的变化。 连接两个具有不同矢量大小的端口是完全合法的,但是以较小矢量大小的端口为准,而另一个宽度较大的端口的其余位将被忽略。
// Case #1 : Inputs are by default implicitly declared as type "wire"
module des0_1 (input wire clk ...); // wire need not be specified here
module des0_2 (input clk, ...); // By default clk is of type wire
// Case #2 : Inputs cannot be of type reg
module des1 (input reg clk, ...); // Illegal: inputs cannot be of type reg
// Case #3: Take two modules here with varying port widths
module des2 (output [3:0] data, ...); // A module declaration with 4-bit vector as output
module des3 (input [7:0] data, ...); // A module declaration with 8-bit vector as input
module top ( ... );
wire [7:0] net;
des2 u0 ( .data(net) ... ); // Upper 4-bits of net are undriven
des3 u1 ( .data(net) ... );
endmodule
// Case #4 : Outputs cannot be connected to reg in parent module
module top_0 ( ... );
reg [3:0] data_reg;
des2 ( .data(data) ...); // Illegal: data output port is connected to a reg type signal "data_reg"
endmodule
参考文献:
【1】https://www.chipverify.com/verilog/verilog-module-instantiations