Verilog · Chapter 9.2 · Design & Testbench Creation
Module Instantiation in Verilog — From Blueprint to Real Hardware
A module is a blueprint, a definition that describes a hardware block but is not itself any hardware. This page is where blueprints become real logic. Instantiation is the act of placing a module into a design as a working instance, and one definition can produce a single instance or a thousand, each an independent piece of hardware. Instantiation is also how hierarchy is built, because a module becomes a parent by holding instances of other modules inside its boundary, and a chip sits at the top of that nesting. This lesson teaches what an instance is, why every instance needs a name, how one definition is reused across many instances, and how nesting instances assembles the module tree. It stops short of the detailed rules for wiring ports, which the port mapping lesson covers next.
Foundation20 min readVerilogInstantiationHierarchyModulesStructural Modeling
Chapter 9 · Section 9.2 · Design & Testbench Creation
1. The Engineering Problem
You followed 9.1 and wrote a clean full_adder module — a well-bounded hardware block. Now you need a 32-bit adder. Do you write the addition logic over again, 32 times, in one giant module? Of course not. You wrote the 1-bit block once; you want to use it 32 times.
But here is the catch a 9.1 graduate hits immediately: a module definition, by itself, builds nothing. Writing module full_adder (...) ... endmodule describes a kind of block. It does not place any adder into your design any more than drawing a blueprint pours any concrete. So the question this page answers is:
How do you take a module definition and turn it into actual hardware inside a larger design — once, or a thousand times?
The answer is instantiation. Instantiation is the act of saying "build one of these here, and call it that." Each time you instantiate a module you create an instance — a real, independent piece of hardware. And because a module can be instantiated inside another module, instantiation is also the mechanism that builds hierarchy: the nesting of blocks within blocks that 9.1 showed as the shape of every chip. This page is about turning blueprints into hardware, and hardware into hierarchies.
2. Mental Model — Instantiation Builds Hardware From a Blueprint
Visual A — instantiation turns a definition into instances
From definition to hardware
data flow3. The Hardware View — Each Instance Is Independent Silicon
The most important physical fact: every instance is its own hardware. When you instantiate the same module three times, you get three separate copies of the circuit, not one circuit shared three ways. They occupy different silicon, hold different state, and operate fully in parallel.
register (definition / blueprint)
│ instantiated 3x
┌──────────┼──────────┐
▼ ▼ ▼
reg_a reg_b reg_c <- three independent physical registers
(state A) (state B) (state C) each with its own value, in parallelThis is the deepest difference from software. A software function is one piece of code that many callers share; calling it more does not create more code. An instantiated module is the opposite — each instance is duplicated hardware. Three instances of a 1,000-gate block cost 3,000 gates of area. That is not waste; it is the point: you need three independent copies because they do three independent jobs at the same time.
The consequence for reasoning: when you see three instances of counter, picture three counters on the chip, each counting independently — not one counter being "called" three times. Instances exist simultaneously and permanently, like three identical chips soldered onto a board.
Visual B — instances are independent hardware
4. The Instantiation Statement
An instantiation has three parts. Here is one instance of the and_gate module from 9.1, placed inside a parent module.
module top (
input in1,
input in2,
output result
);
// 1 2 3 (connections — detail is 9.3)
and_gate u_and0 ( .a(in1), .b(in2), .y(result) );
endmoduleThe three parts of every instantiation:
- Module type (
and_gate) — which blueprint to build. This must name a module that has been defined somewhere in the compilation. - Instance name (
u_and0) — the unique label for this particular instance. You choose it; every instance needs one (§5). - Connection list (
( .a(in1), ... )) — how this instance's ports attach to signals in the parent. The form shown —.port(signal)— is the named connection style; the full rules for connecting ports (named vs positional, widths, traps) are Chapter 9.3. Here, read it as "the instance'sapin connects to the parent'sin1," and move on.
Read the statement as a sentence: "Build one and_gate, call it u_and0, and wire its pins to these signals." That is instantiation — naming a blueprint, naming the copy, and attaching it to the surrounding design.
Scope note: this page teaches the instance — its type, its name, and that it connects. The precise mechanics of the connection list belong to 9.3. Treat the
.port(signal)form here as a given.
5. Instance Names — Why Every Instance Needs One
The instance name is not decoration. It is the instance's identity in the design, and it does real work:
- Uniqueness within a parent. Two instances in the same module must have different names.
u_and0andu_and1are two distinct pieces of hardware; the names are how the tools (and you) tell them apart. Duplicate names are an error (§10, DebugLab 1). - Hierarchical path. The names chain into a full path —
top.u_cpu.u_alu.u_adder— that uniquely identifies one block anywhere in the hierarchy. This path is how waveform tools, debuggers, and reports refer to a specific instance among thousands. - Debug and waveforms. When a simulation dumps signals or a timing report flags a violation, it names the instance (
top.u_fifo_3.count). Good instance names make a failure locatable; names likeu1,u2,xxxmake debugging miserable at scale.
The industry convention is a u_ prefix and a descriptive role: u_fetch, u_alu, u_uart_tx. The name is part of how the whole design is navigated — choose it as deliberately as the module name itself.
6. Multiple Instances — Reuse in Action
One definition, instantiated many times, is the entire reason modules exist. Each instance is independent (§3); only the blueprint is shared.
module triple_and (
input a0, b0, a1, b1, a2, b2,
output y0, y1, y2
);
and_gate u_and0 ( .a(a0), .b(b0), .y(y0) ); // instance 1
and_gate u_and1 ( .a(a1), .b(b1), .y(y1) ); // instance 2
and_gate u_and2 ( .a(a2), .b(b2), .y(y2) ); // instance 3
endmoduleThree instances of the same and_gate definition, each wired to different signals, each independent silicon. Change the and_gate definition once and all three update — that is the maintainability win. Place a fourth instance and you have a fourth gate — that is the reuse win. (When you need dozens of identical instances, a generate loop creates them programmatically — that is Chapter 14.7; here, instantiate explicitly.)
7. Building Hierarchy — Instances Inside Modules
This is the idea that makes instantiation the backbone of design: a module becomes a parent by containing instances of other modules. Nesting instances inside modules, level after level, builds the tree 9.1 described.
// Leaf block (the blueprint), defined once.
module full_adder (
input a, b, cin,
output sum, cout
);
assign {cout, sum} = a + b + cin;
endmodule
// Parent block: built structurally from two full_adder INSTANCES.
module adder2 (
input [1:0] a, b,
input cin,
output [1:0] sum,
output cout
);
wire carry; // internal net linking the two instances
full_adder u_fa0 ( .a(a[0]), .b(b[0]), .cin(cin), .sum(sum[0]), .cout(carry) );
full_adder u_fa1 ( .a(a[1]), .b(b[1]), .cin(carry), .sum(sum[1]), .cout(cout) );
endmoduleadder2 contains no addition logic of its own — it is built entirely by instantiating two full_adder blocks and wiring them with an internal carry net. This is structural modeling: describing hardware by composing sub-blocks rather than writing the logic directly. adder2 is now a parent; u_fa0 and u_fa1 are its children. Instantiate adder2 inside a bigger block and the tree grows another level. Scale this idea and you get a CPU built from datapath + control, each built from registers + ALUs, each built from gates — a hierarchy assembled entirely through instantiation.
Visual C — hierarchy is built by nesting instances
8. Elaboration — How Instances Become a Netlist
One conceptual point ties it together. When the tool reads your design, it performs elaboration: it starts at the top module and recursively expands every instantiation into the actual block it names, building the full tree of real hardware.
top (read the top module)
└── u_adder : adder2 (expand: build an adder2 here)
├── u_fa0 : full_adder (expand: build a full_adder)
└── u_fa1 : full_adder (expand: build another full_adder)Elaboration is where "blueprint + instantiation" becomes a concrete, fully-built design. Before elaboration you have definitions and instantiation statements; after it you have a complete tree of real instances — the netlist the simulator runs and the synthesizer maps to gates. The mental takeaway: the design you write is a set of blueprints plus instructions for placing copies; elaboration carries those instructions out and produces the actual hardware tree. (Elaboration is also when parameters — Chapter 6 — fix each instance's configuration; that interaction is previewed here and drilled with parameterized instantiation later.)
Visual D — elaboration builds the tree from definitions + instantiations
Elaboration — from source to instance tree
data flow9. Worked Examples
Three instantiations, growing from one instance to a hierarchy.
9.1 Example 1 — instantiate one module
module top (
input x, y,
output z
);
and_gate u_and ( .a(x), .b(y), .y(z) );
endmoduleThe minimum: one and_gate definition becomes one u_and instance inside top. top now contains a gate. Read it as hardware — top is a box with an AND gate placed inside it, its pins wired to top's ports.
9.2 Example 2 — multiple instances of one definition
module quad_reg (
input clk,
input [3:0] d0, d1, d2, d3,
output [3:0] q0, q1, q2, q3
);
// One register blueprint, four independent instances.
reg4 u_reg0 ( .clk(clk), .d(d0), .q(q0) );
reg4 u_reg1 ( .clk(clk), .d(d1), .q(q1) );
reg4 u_reg2 ( .clk(clk), .d(d2), .q(q2) );
reg4 u_reg3 ( .clk(clk), .d(d3), .q(q3) );
endmoduleFour instances of a reg4 definition — four independent 4-bit registers, each holding its own value, all clocked together but otherwise unrelated. This is reuse: one blueprint, four pieces of hardware, four unique instance names.
9.3 Example 3 — a hierarchy
module adder4 (
input [3:0] a, b,
input cin,
output [3:0] sum,
output cout
);
wire c1, c2, c3; // internal carry chain between instances
full_adder u_fa0 ( .a(a[0]), .b(b[0]), .cin(cin), .sum(sum[0]), .cout(c1) );
full_adder u_fa1 ( .a(a[1]), .b(b[1]), .cin(c1), .sum(sum[1]), .cout(c2) );
full_adder u_fa2 ( .a(a[2]), .b(b[2]), .cin(c2), .sum(sum[2]), .cout(c3) );
full_adder u_fa3 ( .a(a[3]), .b(b[3]), .cin(c3), .sum(sum[3]), .cout(cout) );
endmoduleA 4-bit ripple-carry adder built structurally from four full_adder instances, the carry-out of each feeding the carry-in of the next. adder4 has no adder logic of its own — it is pure composition. This is how real datapaths are assembled: small verified blocks, instantiated and wired into bigger ones. Instantiate adder4 itself inside a larger block and the hierarchy deepens.
10. Common Mistakes
Five mistakes rooted in misunderstanding instances and definitions.
- Duplicate instance names. Two instances in the same parent with the same name is illegal — each instance needs a unique label (§5, DebugLab 1).
- Instantiating an undefined module. Naming a module type that was never defined (a typo, a missing file) leaves an instance with no blueprint to build (§10 → DebugLab 2).
- Confusing the definition with the instance. Editing a definition expecting to change one instance, or thinking the definition is itself hardware. The definition is shared by all instances; the instance is the hardware.
- Forgetting the instance name entirely. Writing
and_gate ( .a(x), ... );with no name. Every instantiation requires an instance name. - Treating instantiation like a function call. Expecting an instance to "run and return a value." An instance is permanent parallel hardware, not a call — it is built once and is always on (DebugLab 3).
11. Debugging Lab
Three instantiation debug post-mortems
12. Industry Perspective
Instantiation is the load-bearing operation of real design.
- Structural composition is most of RTL integration. Above the leaf blocks, large designs are assembled almost entirely by instantiation — a chip's top level is page after page of sub-block instances wired together, with little logic of its own. Integration engineers spend their days instantiating and connecting, not writing gate logic.
- IP reuse is instantiation. A purchased or in-house IP block (a PCIe controller, a memory subsystem) is delivered as a module and used by instantiating it. The entire semiconductor-IP economy runs on "instantiate this verified block into your chip."
- Regular structures are arrays of instances. Ripple adders, register files, crossbars, memory arrays — repeated hardware is repeated instances of one block (written explicitly, or generated with a
generateloop for large counts). The blueprint is authored once; the array is instances. - Instance names are the design's coordinate system. Across thousands of instances, the hierarchical instance path is how every tool — simulation, timing, power, physical layout — refers to a specific block. Disciplined instance naming is a real, valued engineering practice.
13. Interview Q&A
14. Exercises
Four exercises, progressive.
Exercise 1 — Identify the parts of an instantiation
For the statement below, name the three parts: the module type, the instance name, and the connection list.
full_adder u_fa2 ( .a(a[2]), .b(b[2]), .cin(c2), .sum(sum[2]), .cout(c3) );Exercise 2 — Instantiate a single module
Given a defined module inverter with ports input a, output y, write a top module with inputs in, output out, that contains one inverter instance named u_inv connecting in to a and out to y.
Exercise 3 — Build a small hierarchy
Given a defined full_adder (input a, b, cin, output sum, cout), write a adder2 module (inputs [1:0] a, b, input cin, outputs [1:0] sum, output cout) that instantiates two full_adders, chaining the carry from the first to the second with an internal wire. Give each instance a unique name.
Exercise 4 — Find the instantiation bugs
The module below has three instantiation-related problems. Identify each (referencing §10) and state the fix in one line per bug — do not rewrite the whole module.
module top (input a0, b0, a1, b1, output y0, y1);
and_gate u_and ( .a(a0), .b(b0), .y(y0) );
andgate u_and ( .a(a1), .b(b1), .y(y1) );
endmodule15. Summary
Instantiation turns a module definition (a blueprint that is not hardware) into a concrete instance (real, independent hardware) placed inside a design. It is the step where blueprints become silicon, and the mechanism by which hierarchy is built.
The core ideas:
- Definition vs instance. The module is the blueprint, written once; the instance is hardware built from it. One definition → many instances, each independent silicon with its own state.
- The instantiation statement has three parts — module type (which blueprint), instance name (this copy's unique identity), and connection list (how it attaches; detailed rules in 9.3).
- Every instance needs a unique name, which forms the hierarchical path used to locate any block in the design.
- Each instance is independent hardware — three instances are three circuits, not one shared three ways. This is the core difference from a software function call.
- Hierarchy is built by nesting instances — a module becomes a parent by containing instances of other modules. This is structural modeling.
- Elaboration expands definitions + instantiations, from the top module down, into the complete instance tree (the netlist).
The discipline this page instils:
- Name every instance uniquely and descriptively (the
u_convention) — names are the design's coordinate system. - Instantiate to reuse — write a block once, place it everywhere; don't duplicate logic.
- Compose, don't call — an instance is permanent parallel hardware, never a function that runs and returns.
You can now turn the blueprints from 9.1 into real, reusable hardware and assemble them into hierarchies. What remains is the precise art of connecting them: Chapter 9.3 Module Port Mapping drills how an instance's ports attach to the surrounding design — named vs positional connections, width and direction matching, and the wiring traps that the simple .port(signal) form here glossed over.
Related Tutorials
- Module Structure & Elements — Chapter 9.1; the module definition (blueprint) that this page instantiates.
- Design & Testbench Creation — Chapter 9 overview; where module hierarchy and the design loop were introduced.
- parameter — Chapter 6.1; the build-time constants resolved per instance at elaboration.
- RTL Designing — Chapter 3; the register-transfer model the instantiated blocks implement.