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 moduleparameter_list→ optional parameters for configurabilityport_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 inputoutput wire→ single-bit outputassign→ 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 signaltb_moduleis 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_moduleinstantiatesfull_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
WIDTHcan 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) |