As we saw in a previous article, bigger and complex designs are built by integrating multiple modules in a hierarchical manner. Modules can be instantiated within other modules and ports of these instances can be connected with other signals inside the parent module.
These port connections can be done via an ordered list or by name.
Port Connection by ordered list
One method of making the connection between the port expressions listed in a module instantiation with the signals inside the parent module is by the ordered list.
mydesign is a
module instantiated with the name d0 in another module called tb_top. Ports are connected in a certain order which is determined by the position of that port in the port list of the module declaration. For example, b in the testbench is connected to y of the design simply because both are at the second position in the list of ports.
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, b, a, c); // a is at position 1 so it is automatically connected to x // b is at position 2 so it is automatically connected to y // a is at position 3 so it is connected to z // c is at position 4, and hence connection is with o endmodule
Order of ports in the design module should be known for a correct connection.
This is very inconvenient because the order might change if a new port is added to the list or when the number of ports in the design is very large.
Port Connection by name
A better way to connect ports is by explicitly linking ports on both the sides using their port name.
. indicates that the port name following the dot belongs to the design. The signal name to which the design port has to be connected is given next within parentheses
module design_top; wire [1:0] a; wire b, c; mydesign d0 ( .x (a), // signal "x" in mydesign should be connected to "a" in this module (design_top) .y (b), // signal "y" in mydesign should be connected to "b" in this module (design_top) .z (a), .o (c)); endmodule
It is recommended to code each port connection in a separate line so that any compilation error message will correctly point to the line number where the error occured. This is much easier to debug and resolve compared to not knowing which port created the error had they been all in the same line.
Because these connections are made by name, the order in which they appear is irrelevant. Multiple module instance port connections are not allowed.
module design_top; mydesign d0 ( .x (a), .z (a), // z at second position is okay because of explicit connection .y (a), .x (b), // illegal - x is already connected to a .o (c)); endmodule
Ports that are not connected to any wire in the instantiating module will have a value of high-impedance.
module design_top; mydesign d0 ( // x is an input and not connected, hence a will be Z .y (a), .z (a), .o ()); // o has valid value in mydesign but since // it is not connected to "c" in design_top, c will be Z endmodule
Let us take the shift register example we had seen before, and leave some ports unconnected.
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)); dff u1 (.d(q_net), .clk(clk), .rstn(rstn), .q()); // Output q is left floating dff u2 (.d(q_net), .clk(clk), .rstn(rstn), .q()); // Output q is left floating dff u3 (.d(q_net), .clk(clk), .rstn(rstn), .q(q)); endmodule
Note that outputs from instances u1 and u2 are left unconnected in the RTL schematic obtained after synthesis. Since the input d to instances u2 and u3 are now connected to nets that are not being driven by anything it is grounded.
In simulations, such unconnected ports will be denoted as high impedance ('hZ) typically shown in waveforms as an orange line vertically aligned in the middle.
All port declarations are implicitly declared as
wire and hence the port direction is sufficient in that case. However
output ports that need to store values should be declared as
reg data type and can be used in a procedural block like
Ports of type
inout cannot be declared as
reg because they are being driven from outside continuously and should not store values, rather reflect the changes in the external signals as soon as possible. It is perfectly legal to connect two ports with varying vector sizes, but the one with lower vector size will prevail and the remaining bits of the other port with a higher width will be ignored.
// 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