Skip to content

Verilog · Chapter 9.1 · Design & Testbench Creation

Module Structure & Elements in Verilog — The Hardware Building Block

This is your first design-construction lesson, and it centers on the module, the fundamental building block every digital system is assembled from. A module is best understood not as a file or a function but as a reusable hardware block. It is a sealed box with a defined boundary, its ports, an internal implementation, its logic, and a name so it can be reused. This page teaches what a module represents, why modules and hierarchy exist, how a module boundary encapsulates its internals, and the elements a module can contain. The approach is hardware-first and structure-first rather than syntax-first. It stops short of connecting modules together, since instantiation, port mapping, and design methodology each get their own lesson. Finish this and you will read a module the way an engineer does, as a block of hardware with an interface.

Foundation20 min readVerilogModulesHierarchyEncapsulationRTL Design

Chapter 9 · Section 9.1 · Design & Testbench Creation

1. The Engineering Problem

A modern system-on-chip packs a CPU, a UART, a DMA engine, a memory controller, an SPI controller, and a bank of timers onto a single die — millions of gates, described across thousands of RTL files, built by a large team. Nobody can hold millions of gates in their head, and nobody can edit a single file thousands of pages long. So the first question of real design is not "what is the syntax?" but:

How do engineers organize this much complexity so a human can design it, a team can divide it, and a tool can verify it?

Every engineering discipline answers the same way: build big things from small, reusable, well-bounded parts. A car is engine + transmission + chassis + electronics, each built from smaller parts. A program is functions and classes. A chip is modules.

A module is the Verilog unit of that decomposition — a self-contained block of hardware with a clear boundary, reusable wherever it is needed. The CPU is a module. So is the UART. So is the FIFO inside the UART, and the register inside the FIFO. The entire chip is a hierarchy of modules nested inside modules. This page is about that building block: what it is, why it exists, and what lives inside it.

2. Mental Model — A Module Is a Reusable Hardware Block

Visual A — hierarchy: every box is a module

System module hierarchySystem (top module)the whole designCPUa moduleUARTa moduleDMAa moduleTimera moduleMemorya module12
A system decomposed into blocks. Each child — CPU, UART, DMA, Timer, Memory — is a module, and each is itself built from smaller modules, many levels down to individual gates. 'Every box is a module' is the literal truth of how a chip is organized: a tree of nested hardware blocks.

3. The Hardware View — The Module Boundary

The most important feature of a module is its boundary. A module draws a line between inside (its logic) and outside (the rest of the design), and everything crosses that line through a defined set of ports.

the module boundary
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
        outside world
             │  (inputs cross in)

   +---------------------+
   |       Module        |
   |                     |
   |    internal logic   |
   |   (hidden inside)   |
   |                     |
   +---------------------+
             │  (outputs cross out)

        outside world

The boundary gives you three things that make large design possible:

  • Interface. The ports are the contract. Anything outside the module interacts with it only through its inputs and outputs — never by reaching inside. The interface is the promise the module makes to the rest of the chip.
  • Encapsulation. The internal logic is hidden. You can redesign a module's guts completely — swap a slow multiplier for a fast one — and nothing outside changes, as long as the boundary (the ports and their behaviour) stays the same.
  • Independence. Because each module is sealed behind its boundary, engineers can build and verify blocks independently and trust them to compose. The boundary is what turns "a million gates" into "fifty blocks I can reason about one at a time."

Think of a module like an integrated-circuit chip on a board: you wire to its pins and trust its datasheet; you never open the package. The ports are the pins; the module's behaviour is the datasheet; the silicon inside is sealed.

Visual B — the module boundary

Module boundary with inputs and outputsInputssignals from outsideModuleencapsulated logicOutputssignals to outside12
Inputs enter the module through its input ports; outputs leave through its output ports; the logic in between is encapsulated. The outside world sees only the boundary — the interface — never the internal implementation. Redesigning the inside is invisible outside as long as the boundary behaviour holds.

4. What a Module Is Not

Three misconceptions arrive with learners from other backgrounds. Each is worth rejecting explicitly, because each leads to a different design mistake.

  • A module is not a file. A file is a place to store text; a module is a hardware block. One file can hold several modules, and a large module can be split across files. Equating the two leads to thinking "one file = one thing," which misses that the real unit is the hardware block, not the storage.
  • A module is not a function. A function (in software) runs when called and returns; a module exists and runs continuously, in parallel with everything else. A module is not "invoked" — it is built and then it is always on. Treating modules like functions produces the single most common beginner error: expecting sequential, call-and-return behaviour from parallel hardware.
  • A module is not a software object. It has no methods you call, no runtime construction in the software sense, no garbage collection. The superficial resemblance (a bounded thing with an interface) hides a fundamental difference: a module is physical concurrency, not an object whose methods execute on a CPU.

The through-line: a module is hardware that exists and runs continuously, defined once and reusable. Hold that, and the misconceptions dissolve.

5. Module Anatomy — The Structure

Now the structure. Here is the smallest complete module — a two-input AND gate — used only to expose the anatomy, not to teach the logic operator inside it.

and_gate.v — the anatomy of a module
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module and_gate (      // 1. `module` keyword + 2. module name
    input  a,          // 3. port list — the boundary/interface
    input  b,
    output y
);
 
    // 4. declarations (none needed here) + 5. implementation
    assign y = a & b;  // the internal logic
 
endmodule              // 6. `endmodule` — closes the block

Six structural elements, in order:

  1. module keyword — opens the block. Every module definition begins here.
  2. Module name (and_gate) — the identifier the block is known by, so it can be reused. Naming it well is a real design decision (§10).
  3. Port list — the boundary. Each port is an input, output, or inout, declared with a direction. This is the interface every other part of the design connects through. (The mechanics of connecting to these ports is 9.3 — here we only declare the boundary.)
  4. Declarations — internal signals, parameters, and other local items the body needs (none required for this tiny example; introduced in §6).
  5. Implementation — the logic that defines what the module does. Here, one assign. In real modules this is the bulk of the block.
  6. endmodule — closes the definition. Mandatory; a module without it is incomplete (§11).

The shape is invariant: module name (ports); declarations; implementation; endmodule. Every module you ever write — a gate or a CPU — has exactly this skeleton. Learn the skeleton and the rest is filling it in.

Visual C — module anatomy

The structure of every module

data flow
The structure of every modulemodule + nameopen the blockPortsthe boundary / interfaceDeclarationslocal nets, regs, parametersLogicthe implementationendmoduleclose the block
Every module follows this fixed structure top to bottom: open with module + name, declare the port boundary, declare local items, implement the logic, close with endmodule. The same skeleton scales from a one-line gate to a million-gate CPU.

6. The Elements a Module Can Contain

A module is a container. Inside its boundary it can hold any of the following — introduced here conceptually, each drilled in its own later chapter.

ElementWhat it is (one line)Taught in
PortsThe boundary signals — input / output / inout — that form the interface.9.3 (mapping)
Nets (wire)Internal connections that carry a value driven from elsewhere.Ch 5 (live)
Registers (reg)Internal signals assigned in procedural blocks; may become storage.Ch 5 (live)
ParametersBuild-time constants that configure the block per instance.Ch 6 (live)
InstancesOther modules placed inside this one — how hierarchy is built.9.2
Continuous assignments (assign)Dataflow logic that continuously drives a net.Ch 13
Procedural blocks (always / initial)Behavioural logic — combinational or sequential.Ch 14

The single idea to take from this table: a module is the container that holds all of these. You do not need to know how each works yet — only that the module is the box they live in, and that the box has a boundary separating them from the outside world. The bulk of the rest of the Verilog track is learning to fill this container well.

7. Module vs Instance — A Preview

One distinction must be introduced now, because it underlies everything, even though its mechanics belong to the next page.

A module is a definition — a blueprint. Writing module fifo (...) ... endmodule does not create any hardware; it describes a kind of hardware block, the way an architect's blueprint describes a kind of house without building one.

An instance is actual hardware — a specific FIFO placed into the design, built from the blueprint. One module definition can produce many instances, each independent silicon, just as one blueprint builds many identical houses on a street.

Module = blueprint (a definition). Instance = actual hardware (built from the blueprint).

This is why "design once, use many times" works: you write the module definition a single time, and the design uses as many instances of it as it needs. How you place an instance into a design — the instantiation syntax — is Chapter 9.2, the very next page. Here, only hold the conceptual split: the thing you write is the blueprint; the thing on silicon is the instance.

Visual D — module vs instance (preview)

Module blueprint versus hardware instancesModuleblueprint / definitionInstance 1actual hardwareInstance 2actual hardwareInstance 3actual hardware12
A module is a blueprint — a reusable definition that is not itself hardware. An instance is a concrete piece of hardware built from that blueprint, and one blueprint can produce many independent instances. This page defines the blueprint; placing instances into a design is Chapter 9.2.

8. Worked Examples

Three modules, growing in size, each chosen to show structure — not to teach the logic inside.

8.1 Example 1 — an AND gate (structure in the smallest form)

and_gate.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module and_gate (
    input  a,
    input  b,
    output y
);
    assign y = a & b;
endmodule

The minimum viable module: a name, a three-port boundary (two inputs, one output), and a one-line body. Read it as hardware — a block with two input pins and one output pin, AND-ing continuously. Every structural element from §5 is present even at this scale.

8.2 Example 2 — a 4-bit adder shell (larger boundary, vector ports)

adder4.v — module shell
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module adder4 (
    input  [3:0] a,        // 4-bit input bus
    input  [3:0] b,        // 4-bit input bus
    input        cin,      // carry in
    output [3:0] sum,      // 4-bit result bus
    output       cout      // carry out
);
    // implementation goes here — the boundary is what matters at this stage
    assign {cout, sum} = a + b + cin;
endmodule

The same skeleton, a richer interface: multi-bit (vector) ports and five signals total. Notice how much the boundary alone communicates — a reader knows this block adds two 4-bit numbers with carry-in and carry-out before reading a line of the body. That is the value of a well-shaped interface: the boundary documents the block. (The body's + and concatenation are Chapter 10/13 material — here, focus on how the ports organize the block.)

8.3 Example 3 — a counter shell (a module can contain sequential logic)

counter4.v — module shell with sequential logic inside
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module counter4 (
    input        clk,      // clock
    input        rst_n,    // active-low reset
    output [3:0] count     // current count
);
    // A module is a CONTAINER — it can hold sequential logic too.
    // (The always-block mechanics are Chapter 14; shown here only to prove
    //  that sequential hardware lives inside a module like everything else.)
    reg [3:0] count_q;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) count_q <= 4'd0;
        else        count_q <= count_q + 4'd1;
    end
    assign count = count_q;
endmodule

The point of this example is not the sequential logic — that is Chapter 14 — but that a module is a container general enough to hold it. Combinational blocks (Example 1, 2), an internal reg declaration, a procedural always block, and a continuous assign all coexist inside one boundary. Whatever the logic, the module is the box around it, and the box always has the same skeleton.

9. Industry Perspective

Module count is a direct measure of design scale, and it is why hierarchy is not optional but mandatory.

Design scaleApproximate module countWhy hierarchy is required
Small FPGA project~10–50 modulesEven here, one flat module would be unreadable and un-reusable.
Medium ASIC block~100–500 modulesNo single engineer owns it all; clean boundaries let a team divide it.
Large SoCthousands of modulesImpossible to design, verify, or comprehend without deep hierarchy.

Three industrial truths follow:

  • Hierarchy is mandatory, not stylistic. Beyond a few hundred gates, a flat design cannot be read, reused, or verified. Decomposition into modules is what makes scale physically achievable for a human team.
  • Modules are the unit of ownership. Teams are organized around module boundaries — one engineer or squad owns a block and its interface. The boundary is also an organizational line, not just a technical one.
  • Reuse is the economic engine. A verified module (a FIFO, a UART, a standard interface) is reused across projects and licensed as IP. The whole semiconductor-IP industry exists because a module is a reusable hardware block.

10. Common Mistakes

Five mistakes that come from misunderstanding the module as a block, not from forgetting syntax.

  1. Missing endmodule. Every module must close with endmodule. Omit it and the parser keeps reading the next module (or end-of-file) as part of this one — a confusing cascade of errors far from the real cause (§11, DebugLab 1).
  2. Treating modules like functions. Expecting a module to "run when called" and "return a value." A module is parallel hardware that exists continuously; it is built, not invoked. This misconception produces designs that simulate nothing like the author expected.
  3. One giant monolithic module. Cramming an entire design into a single module. It cannot be read, reused, divided among a team, or verified in isolation — the opposite of why modules exist (§11, DebugLab 3).
  4. Mixing unrelated functionality. Putting, say, a UART and a memory controller in one module because they happen to share a clock. A module should do one cohesive thing; unrelated logic in one box destroys reuse and clarity.
  5. Poor naming. A module named block1 or temp tells a reader nothing. The name is part of the interface — uart_tx, fifo_sync, adder4 communicate the block's role at a glance. Bad names compound across thousands of modules.

11. Debugging Lab

Three module-structure debug post-mortems

12. Interview Q&A

13. Exercises

Four exercises, progressive — from reading structure to critiquing it.

Exercise 1 — Identify the module elements

For the module below, label each structural element: the module keyword, the module name, each port (with its direction), the implementation, and endmodule.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module xor_gate (
    input  a,
    input  b,
    output y
);
    assign y = a ^ b;
endmodule

Exercise 2 — Create a simple module shell

Write the shell (boundary only, body left as a comment) of a module named inverter with one input a and one output y. Produce only the structure — module / ports / // logic here / endmodule. Do not write the logic.

Exercise 3 — Design a module interface for a comparator

Design the boundary (port list only) of a module named comparator4 that compares two 4-bit numbers a and b and reports three results: a > b, a == b, and a < b. Decide the port names and directions; do not implement the logic. State in one sentence what your interface communicates to a reader before they read the body.

Exercise 4 — Review a poorly structured module

The module below compiles but is badly structured. List the structural problems (from §10) and describe how you would reorganize it — without writing the fix in full.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module thing (
    input clk, rst_n, uart_rx, spi_miso,
    input [31:0] mem_addr,
    output uart_tx, spi_mosi, spi_clk,
    output [31:0] mem_rdata,
    output [7:0] led
);
    // 1,500 lines mixing UART, SPI, a memory interface, and LED blink
    // logic, all sharing the same internal nets, no internal boundaries.
endmodule

14. Summary

A module is the fundamental building block of digital design — a reusable hardware block with a boundary, an interface, and contained logic. It is not a file, not a function, and not a software object: it is hardware that exists and runs continuously, defined once and reusable many times.

The core ideas:

  • Module = reusable hardware block. Hardware (exists, runs in parallel), reuse (one definition, many instances), encapsulation (internals hidden behind the boundary).
  • The boundary is the interface. Ports are the contract; the outside world connects only through them; the internals can change freely as long as the boundary holds.
  • Hierarchy is a tree of modules. Modules contain modules, from the top-level chip down to individual gates — the only way million-gate designs become tractable.
  • The anatomy is invariant. module + name → ports → declarations → implementation → endmodule. The same skeleton scales from a gate to a CPU.
  • A module is a container for ports, nets, registers, parameters, sub-module instances, continuous assignments, and procedural blocks — each drilled in its own later chapter.
  • Module vs instance (preview): the module is the blueprint (a definition); an instance is actual hardware built from it. One blueprint, many instances.

The discipline this page instils:

  • One module = one cohesive hardware block. Decompose; never build a monolith.
  • Name modules for their role — the name is part of the interface.
  • Close every module with endmodule — and when an error points at the next module, suspect a missing one here.

You now read a module the way an engineer does: as a block of hardware with an interface, not a block of text. The next step is to use these blocks — Chapter 9.2 Module Instantiation teaches how to place a module definition into a design as a working instance, and 9.3 Module Port Mapping teaches how to wire instances together into the hierarchy this page has been describing.

  • Design & Testbench Creation — Chapter 9 overview; why modules and testbenches are the two artifacts all RTL is built from.
  • RTL Designing — Chapter 3; the register-transfer mental model the logic inside a module implements.
  • reg — Chapter 5.2.1; one of the internal elements a module contains.
  • parameter — Chapter 6.1; the build-time constants that configure a module per instance.