Keywords: Verilog | Module Instantiation | Hardware Description Language
Abstract: This article provides an in-depth exploration of module instantiation in Verilog, covering key techniques such as positional port connection, named port connection, automatic connection, and wire declaration. Through detailed code examples and references to IEEE standards, it analyzes the advantages and disadvantages of different methods, offering practical advice to avoid common pitfalls and helping readers write more robust and maintainable hardware description code.
In Verilog hardware description language, module instantiation is fundamental for building complex digital systems. It enables designers to combine functional modules into larger systems, facilitating hierarchical design. Based on the IEEE Std 1800-2012 standard, this article systematically introduces various methods of module instantiation and their application scenarios.
Positional Port Connection
The simplest instantiation method is positional port connection, where signals are connected directly in the order of the submodule's port declarations. For example, given the top and subcomponent modules, the instantiation code is as follows:
module top(
input clk,
input rst_n,
input enable,
input [9:0] data_rx_1,
input [9:0] data_rx_2,
output [9:0] data_tx_2
);
subcomponent subcomponent_instance_name (
clk, rst_n, data_rx_1, data_tx );
endmodule
While concise, this method has significant drawbacks. If the port order of the submodule changes, such as swapping clk and rst_n, the compiler will not report an error, but functionality will be compromised. This implicit dependency reduces code robustness and maintainability.
Named Port Connection
To avoid order dependency, named port connection is recommended. This method explicitly specifies the connection for each port, enhancing code readability and maintainability. Example code:
subcomponent subcomponent_instance_name (
.clk(clk), .rst_n(rst_n), .data_rx(data_rx_1), .data_tx(data_tx) );
To further improve code quality, it is advisable to place each port on a separate line with proper indentation and add comments indicating port direction:
subcomponent subcomponent_instance_name (
.clk ( clk ), // input
.rst_n ( rst_n ), // input
.data_rx ( data_rx_1 ), // input [9:0]
.data_tx ( data_tx ) // output [9:0]
);
This format not only facilitates reading but also reduces misunderstandings in team collaborations.
Wire Declaration and Multi-Module Interconnection
When signals need to be passed between modules, wires must be explicitly declared. Consider a scenario where a clock generation module outputs a clock signal used by two submodules. Example code:
wire [9:0] data_temp;
subcomponent subcomponent_instance_name (
.clk ( clk_sub ), // input
.rst_n ( rst_n ), // input
.data_rx ( data_rx_1 ), // input [9:0]
.data_tx ( data_temp ) // output [9:0]
);
subcomponent subcomponent_instance_name2 (
.clk ( clk_sub ), // input
.rst_n ( rst_n ), // input
.data_rx ( data_temp ), // input [9:0]
.data_tx ( data_tx ) // output [9:0]
);
Here, data_temp is explicitly declared as a 10-bit wide wire, ensuring port width matching. If omitted, Verilog defaults to creating a 1-bit wide wire, leading to width mismatch warnings and potential errors.
SystemVerilog Automatic Connection Features
SystemVerilog introduces automatic connection features to simplify code, but they should be used with caution. The first method uses the .port syntax to automatically connect signals with the same name:
subcomponent subcomponent_instance_name (
.clk, // input **Auto connect**
.rst_n, // input **Auto connect**
.data_rx ( data_rx_1 ), // input [9:0]
.data_tx ( data_tx ) // output [9:0]
);
While this reduces code volume, when signal names are identical but functions differ (e.g., multiple clock domains), it may cause hidden wiring errors.
A more aggressive automatic connection method uses the .* syntax to connect all unmentioned ports to signals of the same name:
subcomponent subcomponent_instance_name (
.*, // **Auto connect**
.data_rx ( data_rx_1 ), // input [9:0]
.data_tx ( data_tx ) // output [9:0]
);
This approach might save time in prototyping, but it is high-risk in production code. When a submodule adds new ports, if the top level has signals with the same name, they will be automatically connected without warnings, potentially introducing hard-to-debug errors.
Conclusion and Best Practices
Module instantiation is a critical aspect of Verilog design. Based on IEEE standards and engineering experience, the following best practices are recommended: prioritize named port connection with formatted code for readability; always explicitly declare wires with correct widths; use automatic connection features cautiously, especially in team projects or production code. By adhering to these principles, more reliable and maintainable digital systems can be constructed.