Connecting module ports by explicitly writing out every .port_name(signal_name) pair gets repetitive fast, especially once a design has dozens of ports that already share names with the signals feeding them. SystemVerilog adds two shorthands, .name and .*, that let a module instantiation connect ports automatically whenever the port name and the local signal name match.
7 min read | Intermediate Level
What You'll Learn
- How the
.nameshorthand connects a single port to an identically named signal - How
.*connects every remaining port at once, and when to mix it with explicit connections - The one rule that trips up most people:
.nameand.*behave differently when no matching signal exists - Where these shortcuts matter most in design versus verification code
Why Port Connections Get Repetitive
A typical module instantiation lists every port explicitly:
module alu (
output [7:0] alu_out,
output zero,
input [7:0] ain,
input [7:0] bin,
input [2:0] opcode
);
// ...
endmodule
module top;
wire [7:0] alu_out, ain, bin;
wire zero;
wire [2:0] opcode;
alu alu_inst (
.alu_out (alu_out),
.zero (zero),
.ain (ain),
.bin (bin),
.opcode (opcode)
);
endmodule
Every connection here repeats the same identifier twice: once as the port name, once as the local signal name. When a designer deliberately names local signals after the ports they connect to - a very common RTL convention - that repetition is pure boilerplate. SystemVerilog lets you drop it.
The .name Shorthand
.port_name on its own is shorthand for .port_name(port_name). It connects the port to a signal of the exact same name declared in the instantiating scope:
alu alu_inst (
.alu_out, // same as .alu_out(alu_out)
.zero, // same as .zero(zero)
.ain, // same as .ain(ain)
.bin, // same as .bin(bin)
.opcode // same as .opcode(opcode)
);
Two conditions have to hold for .name to work: a signal with that exact name has to exist in the instantiating module, and its data type has to be equivalent to the port's. If either condition fails, elaboration reports an error - .name never silently falls back to leaving the port unconnected, even if the port has a default value.
To genuinely leave a port unconnected while still documenting it, use empty parentheses instead: .zero(). That is different from .zero, and the distinction matters - see the mistakes section below.
The .* Wildcard
.* extends the same idea to every port in one go. It connects every port that is not explicitly listed elsewhere in the same instantiation, as long as a same-named, same-type signal exists locally:
alu alu_inst (.*); // connects alu_out, zero, ain, bin and opcode automatically
.* can appear at most once per instantiation, but it can be mixed with explicit connections to call out exceptions - either a port that needs a different signal, or one you want to leave deliberately unconnected:
alu alu_inst (
.zero (), // leave this one unconnected
.ain (ain_reg), // connect to a differently named signal
.* // everything else (alu_out, bin, opcode) connects by name
);
.name vs. .*: The Default-Value Difference
Both shortcuts connect ports by matching names, but they disagree on what happens when a port has a default value and no matching local signal exists. This is the single most useful distinction to remember:
.name | .* | |
|---|---|---|
| Matching signal found | Connects it | Connects it |
| No matching signal, port has a default value | Error - the default value is ignored | Default value is used |
| No matching signal, no default value | Error | Port is left unconnected |
| Appears more than once per instantiation | Allowed (one per port) | Illegal |
The reasoning is intent. Writing .rst_n by name is a deliberate statement that you want to connect that exact port, so a missing signal is treated as a mistake worth flagging. .* is a broad, catch-all shortcut, so a port it cannot match quietly falls back to whatever the module author intended by giving it a default in the first place.
Quick Check
Q: A module has input logic rst_n = 1'b1. The instantiating scope has no signal called rst_n. What happens with .rst_n versus with .*?
Show Answer
.rst_n is an elaboration error, because an implicit named connection never uses the default value. .* instead uses the default value 1'b1, since the port is left for the wildcard to resolve and no matching signal was found.
Using These Shortcuts in Design and Verification
In RTL design, .* is most valuable at the top level of a block where a wrapper module's ports are already named to match the sub-block underneath it one-for-one - common when a module is a thin reset, clock-gating, or pin-muxing wrapper around a larger core. Explicit connections then call out only the handful of signals that genuinely differ.
In verification, .* is even more common. A testbench module typically declares its signals with exactly the DUT's port names on purpose, so the entire DUT instantiation collapses to dut (.*);. Any signal the testbench deliberately drives through a different net - for example, a force/release wire used only for fault injection - is still called out explicitly alongside the wildcard.
Common Beginner Mistakes
Mistake #1: Confusing .port with .port()
.rst_n (no parentheses) asks for an implicit connection to a signal called rst_n. .rst_n() (empty parentheses) explicitly leaves the port unconnected. Typing the parentheses by habit, out of muscle memory from explicit connections, silently changes the meaning from "connect it" to "don't connect it."
Mistake #2: Relying on .* when names are similar but not identical
Wrong: wire [7:0] aluOut; with a port named alu_out, expecting .* to connect them.
Right: match the exact spelling and capitalization, or connect that one port explicitly.
SystemVerilog is case-sensitive and does not infer connections from similar names - .* only matches an exact, identical identifier. A near-miss name is simply left unconnected or defaulted, with no warning that points directly at the typo.
Mistake #3: Expecting .* to adapt port widths
An explicit named connection can slice a wider bus down to size, such as .dataout(dataout[7:0]). .name and .* cannot - they require the local signal's type to already be equivalent to the port's. A width mismatch simply fails to connect implicitly; it has to be connected explicitly instead.
Practice Exercise
Challenge: Spot the Unconnected Port
Given a module fifo with ports clk, rst_n, wr_en, full, and an instantiating scope that declares local signals clk, rst_n, wr_en but not full, what does fifo fifo_inst (.*); do with the full port, if full is an output with no default value?
Hint
Outputs don't take default values the way inputs do - think about what "no matching signal, no default value" means for .* from the comparison table above.
Solution
full is left unconnected, exactly as if you had written .full() explicitly. No elaboration error occurs, because .* never errors on an unmatched port - it either uses a default value or leaves the port unconnected. The design still elaborates, but any logic that was supposed to read full from this instance now reads a floating signal, which is worth a lint check.
Summary
In this tutorial, you learned:
.nameis shorthand for.name(name)- it requires an exact, equivalent-type signal match or it is an error.*connects every remaining port by the same name-matching rule, but falls back to a default value or leaves the port unconnected instead of erroring.*can appear only once per instantiation, and can be mixed with explicit connections to call out exceptions- Neither shortcut can adapt bus widths or dissimilar names - that still requires an explicit named connection
.*is especially common in verification, where testbench signals are deliberately named to match the DUT