Skip to content

Modules and Hierarchy in Verilog

Introduction

Modules are the building blocks of Verilog designs. They encapsulate functionality and allow hierarchical design by instantiating one module inside another. It helps in improving the readability and allows reuse of code.

Module Definition

A module defines a block of RTL functionality with inputs, outputs, and internal logic.

Syntax

module module_name #(parameter_list) (port_list);
  // Internal declarations
  // Logic
endmodule
  • module_name → name of the module
  • parameter_list → optional parameters for configurability
  • port_list → list of inputs, outputs, and inouts

Example

module and_gate (
  input wire a,
  input wire b,
  output wire y
);
  assign y = a & b;
endmodule
  • input wire → single-bit input
  • output wire → single-bit output
  • assign → continuous assignment for combinational logic

Ports

Ports are interfaces between modules.

Port Type Description
input Signals coming into the module
output Signals going out of the module
inout Bidirectional signals

Vector Ports

module adder (
  input [3:0] a,
  input [3:0] b,
  output [4:0] sum
);
  assign sum = a + b;
endmodule
  • [3:0] → 4-bit input vector
  • [4:0] → 5-bit output vector (to accommodate carry)

Module Instantiation

Modules can be instantiated inside higher-level modules, enabling hierarchy.

Named Port Mapping

module tb_module;
  reg a, b;
  wire y;

  and_gate u1 (
    .a(a_sig),
    .b(b_sig),
    .y(y_sig)
  );
endmodule
  • u1 → instance name
  • .port(signal) → connects module port to a local signal
  • tb_module is a custom name for test bench.

Positional Port Mapping

and_gate u2 (a, b, y);
  • Order must match module definition
  • Less readable than named mapping

Hierarchical Design Example

module full_adder (
  input a, b, cin,
  output sum, cout
);
  wire s1, c1, c2;

  // Sum calculation
  xor(s1, a, b);
  xor(sum, s1, cin);

  // Carry calculation
  and(c1, a, b);
  and(c2, s1, cin);
  or(cout, c1, c2);
endmodule

module tb_module;
  reg a, b, cin;
  wire sum, cout;

  full_adder fa1 (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
endmodule
  • top_module instantiates full_adder
  • Hierarchy allows complex designs to be built from smaller blocks

Parameterized Modules

Modules can be made configurable using parameters:

module counter #(parameter WIDTH = 8) (
  input clk, reset,
  output reg [WIDTH-1:0] count
);
  always @(posedge clk or posedge reset) begin
    if (reset)
      count <= 0;
    else
      count <= count + 1;
  end
endmodule
  • WIDTH can be overridden during instantiation:
counter #(16) my_counter (.clk(clk), .reset(reset), .count(count16));

Multiple parameters and instantiation

// Module with multiple parameters
module param_adder #(
    parameter WIDTH = 8,       // Bit-width of inputs
    parameter DELAY = 5        // Propagation delay for simulation
)(
    input  [WIDTH-1:0] a, b,
    output [WIDTH-1:0] sum
);
    // Delay added only for simulation clarity
    assign #(DELAY) sum = a + b;
endmodule

Instantiation

// Method 1 : It takes default value of WIDTH=8 and DELAY=5
param_adder uut1 (
    .a(a_sig),
    .b(b_sig),
    .sum()
);
// Method 2 : Ordered parameter override, WIDTH=16 and DELAY=10
param_adder #(16, 10) uut2 (
    .a(a_sig),
    .b(b_sig),
    .sum()
);
// Method 3 : Named parameter override, WIDTH=4 and DELAY=2
param_adder #(
    .WIDTH(4),
    .DELAY(2)
) uut3 (
    .a(a_sig),
    .b(b_sig),
    .sum()
);

Best Practices

  • Use named port mapping for readability
  • Keep one module per file for maintainability
  • Make modules parameterized for flexibility
  • Use hierarchy to simplify complex designs

Summary

Concept Description Example
Module definition Defines a block of logic module and_gate (input a,b, output y);
Ports Interface signals (input, output, inout) input [3:0] a; output [4:0] sum;
Instantiation Use module inside another module full_adder fa1 (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
Hierarchy Build complex designs using smaller modules Top module instantiates multiple submodules
Parameterization Make module flexible #(parameter WIDTH=8)