In Verilog, the concepts of modules and ports are foundational. They allow you to build hardware designs in a structured and hierarchical way. This article explains what modules and ports are, how they interact, rules for connecting them, and how instantiations work.
What is a Module?
A module in Verilog is the primary building block of any design. It encapsulates functionality — which could range from a simple gate-level operation to a complex system comprised of many smaller pieces.
Key points about modules:
- Each module has a name, a port interface, and optionally parameters to customize behavior.
- Inside a module you may have declarations (signals, regs, wires), procedural or continuous assignments, sub-module instantiations, always/initial blocks, tasks or functions.
- Every Verilog module must begin with a
module <name>
declaration and terminate withendmodule
. - Modules cannot be declared inside other modules (i.e. no nested modules). To achieve hierarchy, you instantiate modules inside other modules.
Ports: The Interface of a Module
Ports allow modules to communicate with the outside world — other modules or testbenches. They define inputs, outputs, or bidirectional connections.
Types of Ports
Verilog uses a few types to classify ports:
Port Kind | Role |
---|---|
input | Receives data or signals from outside the module. |
output | Drives signals out of the module to something external. |
inout | Supports two-way (bidirectional) signaling. |
Important Port Rules
- By default, unless explicitly declared otherwise, ports are of net type. Nets transport signals without storing values.
- If you need an output port to retain its value (for example in certain sequential logic or if it needs to register a value until changed), it must be declared in a type that supports storage (e.g.
reg
). - Inputs and inouts cannot be of storage types that imply holding values since they represent external driving.
Connecting Between Modules (Port Connection Rules)
When using a module, you’ll connect its ports to signals in the external environment (could be another module, or testbench). There are some rules and best practices to ensure correct connections:
Port Type | Inside Module Must Be Net / Reg | Outside Module Must Be Net / Reg |
---|---|---|
input | net | net or reg |
output | reg or net | net |
inout | net | net |
- The internal side of an input must be a net since inputs simply receive values.
- Output ports internally can be either nets or regs (depending on whether you need stored state or not), but externally must connect to a net.
- Inout ports are always nets on both ends because they allow bidirectional flow; there cannot be storage of value in the port itself.
Module Instantiation and Hierarchy
Large systems are built by connecting multiple modules together. You “instantiate” a module inside another to create hierarchical design.
- When you instantiate, you give it a unique instance name so that you can distinguish multiple instances.
- Signals from one module are passed to ports of another.
Ways to Connect Ports During Instantiation
There are generally two ways to connect the ports of an instantiated module:
- Ordered Port Connection
You list external signals in exactly the same sequence as the module’s port list is declared. Order matters here. If you mismatch order, you will misconnect signals. - Named Port Connection
You explicitly name each connection by matching the port name in the module to the external signal. Order does not matter here; clarity is improved, especially in modules with many ports.
Using named port connections helps reduce human errors and improves readability in complex designs.