Skip to content

Verilog · Chapter 9.3 · Design & Testbench Creation

Module Port Mapping in Verilog — Named vs Positional Connections

When you instantiate a module, its pins attach to signals in the surrounding design, and this page makes that connection precise. It matters more than it looks, because a wrong connection produces a design that compiles cleanly yet is silently incorrect. Port mapping is how an instance's ports wire to parent signals, and there are two ways to do it. Connecting by name attaches each port to a signal explicitly, so the order does not matter, while connecting by position relies on order and is the source of one of the most punishing silent bugs in RTL. This lesson teaches both styles, the width and direction rules that govern every connection, what happens when a port is left unconnected, and why production teams insist on always connecting by name.

Foundation20 min readVerilogPort MappingInstantiationNamed ConnectionRTL Design

Chapter 9 · Section 9.3 · Design & Testbench Creation

1. The Engineering Problem

You instantiate a verified divider block — inputs dividend and divisor, output quotient — and connect it by position, the way it looked natural to write:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// divider ports, in declaration order:  (dividend, divisor, quotient)
divider u_div ( b, a, result );   // intended a/b ... but wired b/a

The design compiles. No error, no warning. Simulation runs. And every division is backwards — the block computes b / a instead of a / b — because the positional connection wired a to the divisor port and b to the dividend port. The divider block is flawless; the connection is wrong. There is nothing in the source to catch your eye, because order-based connection has no names to check against.

This is the defining hazard of port mapping:

A wrong port connection is not a syntax error — it is a silent functional bug. The tool happily wires whatever you tell it to; whether you told it the right thing is not something it can check when you connect by position.

Port mapping looks like trivial plumbing, but it is where verified blocks get wired into broken designs. This page teaches the two ways to connect ports, the rules that govern every connection, and the one practice — connecting by name — that turns the silent-swap class of bug into an impossibility.

2. Mental Model — Mapping Honors the Interface Contract

Visual A — two ways to connect the same instance

Named versus positional port connectioninstanceports: a, b, yBy name.a(x) .b(z) .y(out) —order-free, checkedBy position(x, z, out) — order IS themeaning12
The same instance, two connection styles. Named connection states each port-to-signal pairing explicitly, so order does not matter and a wrong name is caught. Positional connection relies on the order matching the definition's port order exactly — compact, but a wrong order is a silent bug. Both produce identical hardware when correct; they differ entirely in how errors are caught.

3. The Hardware View — A Connection Is a Wire Join

Physically, a port connection merges two nodes into one. The instance's port pin and the parent signal it connects to become the same electrical wire. Which side drives that wire is set by the port's direction:

  • input port — the parent drives, the instance receives. The connected parent signal feeds a value into the instance.
  • output port — the instance drives, the parent receives. The instance's internal logic feeds a value out to the parent signal.
  • inout port — bidirectional; either side may drive (a bus). Always a net.
a connection merges instance pin and parent signal into one wire
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   parent:  in1 ───────────┐
                           │  (same wire after connection)
   instance port:  a ──────┘     a receives in1's value  (a is an input)
 
   instance port:  y ──────┐

   parent:  result ────────┘     result receives y's value  (y is an output)

This is why direction governs what a port may connect to. An output is driven by the instance, so in the parent it must connect to something that can receive a drive — a net (wire), not a procedural variable (reg). An input is driven by the parent, so the parent side can be a net or a variable (whatever computes the value). Get the direction-vs-target rule wrong and the tool rejects it — or worse, the design behaves unexpectedly. (The net-vs-variable distinction is Chapter 5; here, the rule to hold is outputs connect to nets in the parent.)

4. Named Connection — The Robust Form

Named connection states each pairing explicitly with .port_name(parent_signal).

named-connection.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// definition:  module full_adder (input a, b, cin, output sum, cout);
full_adder u_fa (
    .a    (x),
    .b    (y),
    .cin  (carry_in),
    .sum  (s),
    .cout (carry_out)
);

Why named connection is the production default:

  • Order-independent. You can list the ports in any order; the names carry the meaning. Reordering the definition's ports later does not break a named instantiation.
  • Self-checking. A wrong or misspelled port name is a compile error — the tool knows the module's port names and rejects .dividentd(...). The silent-swap bug from §1 is impossible: you cannot connect to the wrong port without naming it.
  • Readable and reviewable. Each line says exactly which pin goes where. A reviewer can verify the wiring without counting positions or opening the definition.
  • Robust to interface change. Add a new port to the module and named instances simply leave it unconnected (a catchable condition) rather than silently shifting every connection by one.

For anything beyond a trivial gate, named connection is the only form a serious codebase allows.

5. Positional Connection — Compact and Fragile

Positional connection lists only the signals, matched to ports in declaration order.

positional-connection.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// definition:  module full_adder (input a, b, cin, output sum, cout);
//                                        1  2   3      4    5
full_adder u_fa ( x, y, carry_in, s, carry_out );
//                1  2     3       4     5

The first signal connects to the first declared port, the second to the second, and so on. It is compact, and that is its only advantage. Its dangers:

  • Order is the meaning, and nothing checks it. Swap two same-width signals and you get a silent functional bug (§1) — no error, because every position is still "valid," just wrong.
  • Fragile to interface change. Insert a port into the middle of the definition, and every positional instantiation downstream silently shifts by one — a catastrophic, hard-to-find break across the whole codebase.
  • Unreadable at scale. dma u_dma ( clk, rst_n, a, b, c, d, e, f, ... ); tells a reviewer nothing about which signal is which without cross-referencing the definition.

Positional connection is tolerable only for tiny, stable, obvious interfaces (a single primitive gate) — and even there, most teams ban it. The rule below is not stylistic preference; it is bug prevention.

Visual B — the silent-swap hazard of positional connection

Positional connection silent swapintendeda→dividend, b→divisorwrote (b, a, ...)order swappedtoolboth positions valid → noerrorsilent bugdivides b/a, not a/b12
Positional connection wires by order alone. If two same-width signals are listed in the wrong order, each still lands on a real port, so the tool sees nothing wrong — but the instance is wired backwards. There is no name to check against, so the bug is silent and survives to simulation or silicon. Named connection makes this class of error impossible.

6. Named vs Positional — The Decision

Named (.port(sig))Positional (ordered)
Meaning carried byThe namesThe order
Wrong connectionCompile error (caught)Silent functional bug
Order sensitivityOrder-independentOrder is everything
Interface changeNew ports just left openShifts every connection
ReadabilitySelf-documentingOpaque at scale
CompactnessMore verboseTerse
Use in production✅ Required❌ Banned (or gate-only)

The rule: connect by name. The verbosity of named connection buys self-checking, readability, and immunity to the silent-swap and interface-shift bug classes — a trade every production team makes without hesitation. Reserve positional connection, if at all, for a single-line primitive whose port order is universally known. (SystemVerilog adds .port implicit-name shorthand and .* auto-connect to reduce named-connection verbosity, but those are IEEE 1800 conveniences — the portable Verilog default is explicit named connection.)

7. Connection Rules — Width, Direction, and Unconnected Ports

Beyond which signal connects to which port, three rules govern whether the connection is sound.

7.1 Width matching

The port and the signal connected to it should have the same bit width. A mismatch does not error — it silently adjusts:

width-mismatch.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// module reg8 (input [7:0] d, ...);   // port is 8 bits
wire [3:0] data4;
reg8 u_r ( .d(data4), ... );           // connecting 4 bits to an 8-bit port
// -> upper 4 bits of d are unconnected (read as 0); usually a bug, only a warning

Connecting a narrow signal to a wide port zero-fills the upper bits; connecting a wide signal to a narrow port truncates the top bits. Both are common, silent defects (DebugLab 2). Match widths deliberately; treat width-mismatch warnings as errors.

7.2 Direction matching

Direction decides what a port may connect to in the parent:

  • output port → connect to a net (wire) in the parent. The instance drives it; a parent that wants to use the value in procedural code reads that wire. Connecting an output to a parent reg is illegal (DebugLab 3).
  • input port → connect to a net or a variable. The parent drives the value; it may come from a wire, a reg, or a literal.
  • inout port → connect to a net only. Bidirectional buses are nets.

7.3 Unconnected ports

A port may be left unconnected, with different consequences by direction:

  • Unconnected input — floats (z), which propagates as x through logic. Almost always a bug; the instance is missing a value it needs.
  • Unconnected output — left open. Harmless if the parent genuinely does not use that output; otherwise a missing connection.

Named connection makes "this port is intentionally unconnected" explicit and reviewable; positional connection forces you to account for every position, often with awkward placeholder commas.

Visual C — the connection rules at a glance

What governs a sound connection

data flow
What governs a sound connectionWhich → Whichname or positionWidth matchsame bit countDirectionoutput → net; input → net/varUnconnected?input floats (bug); output open (ok if unused)
A correct connection clears four checks: the right port-to-signal pairing (use names), matching width, a parent-side target legal for the port's direction, and a deliberate decision about any port left unconnected. The tool catches some of these; width and ordering it largely does not — which is why discipline matters.

8. Worked Examples

Three connections — the right way, the dangerous way, and the partial-connection case.

8.1 Example 1 — named connection (the standard)

named-standard.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module top (
    input  [3:0] a, b,
    input        cin,
    output [3:0] sum,
    output       cout
);
    adder4 u_add (
        .a    (a),
        .b    (b),
        .cin  (cin),
        .sum  (sum),
        .cout (cout)
    );
endmodule

Every port named, every pairing explicit. A reviewer verifies the wiring line by line; reordering adder4's ports later cannot break this; a misspelled port name is caught at compile. This is the form to write by default, every time.

8.2 Example 2 — the positional pitfall

positional-pitfall.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// module divider (input [7:0] dividend, input [7:0] divisor, output [7:0] quotient);
module top (
    input  [7:0] a, b,
    output [7:0] result
);
    // INTENT: result = a / b.  But the first two ports are swapped.
    divider u_div ( b, a, result );   // wires b→dividend, a→divisor → computes b/a
    // Compiles clean. Simulates. Silently computes the wrong thing.
endmodule

Both a and b are 8 bits, so the swap is type-valid and the tool says nothing. The fix is not "be more careful with order" — it is to connect by name, which makes the swap a non-issue:

positional-pitfall-fixed.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
    divider u_div ( .dividend(a), .divisor(b), .quotient(result) );  // unambiguous

8.3 Example 3 — partial / intentionally unconnected ports

partial-connection.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// module uart (input clk, rst_n, rx, output tx, output [3:0] status, output parity_err);
module top (
    input  clk, rst_n, rx,
    output tx
);
    // This design uses tx but not the status or parity_err outputs.
    uart u_uart (
        .clk       (clk),
        .rst_n     (rst_n),
        .rx        (rx),
        .tx        (tx),
        .status    (),          // intentionally unconnected output — open is fine
        .parity_err()           // intentionally unconnected output
    );
endmodule

Named connection makes the intent explicit and reviewable: every input is driven, and the two unused outputs are deliberately left open with empty (). An unconnected input here (say .rx() left empty) would float and be a real bug — the symmetry is the teaching point: open outputs can be fine, open inputs rarely are.

9. Industry Perspective

  • Named connection is policy, not preference. Essentially every production RTL team mandates named port connections and lints positional ones out — the silent-swap and interface-shift bug classes are too costly to leave to care. A code review that finds positional connection on a non-trivial block sends it back.
  • Width-mismatch warnings are treated as errors. Mature flows fail the build on connection-width warnings, because a silent truncate/zero-fill is a functional bug that simulation may not expose until a corner case.
  • IP integration is port mapping at scale. Integrating a purchased IP block means connecting dozens or hundreds of its ports to the SoC fabric — done entirely by name, often generated from a machine-readable interface description, precisely because manual positional wiring at that scale would be hopeless.
  • Lint rules guard the connection. Standard lint decks flag unconnected inputs, width mismatches, and positional connections automatically — the connection is considered too error-prone to leave unchecked.

10. Common Mistakes

  1. Positional connection on a non-trivial block — invites the silent-swap bug (§1, DebugLab 1). Use named.
  2. Swapped same-width ports — the specific, undetectable failure of positional connection. Named connection prevents it.
  3. Width mismatch — connecting a narrow signal to a wide port (or vice versa); silent zero-fill/truncation (DebugLab 2).
  4. Connecting an output to a parent reg — direction violation; outputs connect to nets (DebugLab 3).
  5. Unconnected input left floating — the instance is missing a value; propagates x. Distinct from an intentionally-open output.

11. Debugging Lab

Three port-mapping debug post-mortems

12. Interview Q&A

13. Exercises

Exercise 1 — Convert positional to named

Given module mux2 (input sel, input d0, input d1, output y);, rewrite this positional instantiation as a named one:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
mux2 u_mux ( s, in0, in1, out );

Exercise 2 — Spot the silent bug

module sub (input [7:0] minuend, input [7:0] subtrahend, output [7:0] diff); is instantiated as sub u_sub ( x, y, d ); with the intent d = x - y. Is the connection correct? If the intent were d = y - x, what is the safest way to express it? Explain why the positional form is risky here.

Exercise 3 — Apply the connection rules

For module sensor (input clk, output [11:0] reading); instantiated in a parent that needs to register reading into a flop: (a) what type must the parent-side signal connected to reading be, and why; (b) how does the parent then get reading into a reg? Answer in two or three sentences (no full code needed).

Exercise 4 — Review the connections

List every port-mapping problem in the instantiation below (referencing §7/§10), and give a one-line fix for each.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// module alu (input [15:0] a, input [15:0] b, input [2:0] op, output [15:0] y, output zero);
reg [15:0] y_result;
wire [7:0] operand_a;
alu u_alu ( operand_a, b, op, y_result, zero_flag );

14. Summary

Port mapping is how an instance's ports connect to signals in the parent — the wiring layer of instantiation, and the place where verified blocks get wired into correct (or silently broken) designs.

The core ideas:

  • A connection is a wire join between an instance port and a parent signal; the port's direction decides which side drives it (input: parent drives; output: instance drives; inout: bidirectional).
  • Two connection styles — by name (.port(signal), order-free, self-checking) and by position (ordered, where the order is the meaning and nothing checks it).
  • Positional connection is dangerous — a wrong order is a valid connection to the wrong port, a silent functional bug; it is also fragile to interface change and unreadable at scale.
  • Connection rules: match widths (mismatch silently zero-fills or truncates), respect direction (outputs connect to nets, not parent regs), and treat unconnected inputs as bugs (they float) while open outputs may be fine.

The discipline this page instils:

  • Connect by name, always — the names are the contract; let the tool check them.
  • Match widths deliberately and treat width-mismatch warnings as errors.
  • Drive outputs onto nets; leave a port open only on purpose, and never an input.

You can now define modules (9.1), turn them into instances (9.2), and wire those instances together correctly (9.3) — the complete mechanical toolkit for assembling a hierarchy. What remains is judgement: Chapter 9.4 Design Module Fundamentals moves from "how to connect blocks" to "how to write a good design block" — clean interfaces, separation of concerns, and the structural habits that make a module a quality piece of hardware, not just a working one.

  • Module Instantiation — Chapter 9.2; placing the instances whose ports this page connects.
  • Module Structure & Elements — Chapter 9.1; the port list that forms the interface being mapped.
  • reg — Chapter 5.2.1; the net-vs-variable distinction behind the output-connects-to-a-net rule.
  • wire and tri Nets — Chapter 5.1.1; the nets that instance outputs drive.