0
0
VerilogHow-ToBeginner · 3 min read

How to Create Parameterized Module in Verilog: Syntax and Example

In Verilog, you create a parameterized module by declaring parameter inside the module header or body, allowing you to customize values like bit widths. You can override these parameters when instantiating the module using the #() syntax to pass different values.
📐

Syntax

A parameterized module in Verilog uses the parameter keyword to define constants that can be changed during module instantiation. Parameters are typically declared inside the module header or body. When instantiating, you override parameters using #(value) before the instance name.

  • parameter: Defines a constant value inside the module.
  • #(): Used to pass new parameter values during instantiation.
  • module name: The module identifier.
  • instance name: The name of the module instance.
verilog
module my_module #(parameter WIDTH = 8) (input [WIDTH-1:0] in, output [WIDTH-1:0] out);
  assign out = in;
endmodule

// Instantiation with default parameter
my_module instance1 (.in(data_in), .out(data_out));

// Instantiation with overridden parameter
my_module #(16) instance2 (.in(data_in_16), .out(data_out_16));
💻

Example

This example shows a parameterized module adder that adds two inputs of configurable bit width. The parameter WIDTH sets the input and output size. We instantiate it twice: once with the default width 8, and once with width 16.

verilog
module adder #(parameter WIDTH = 8) (
  input  [WIDTH-1:0] a,
  input  [WIDTH-1:0] b,
  output [WIDTH-1:0] sum
);
  assign sum = a + b;
endmodule

module testbench;
  reg  [7:0]  a8 = 8'd15;
  reg  [7:0]  b8 = 8'd10;
  wire [7:0]  sum8;

  reg  [15:0] a16 = 16'd1000;
  reg  [15:0] b16 = 16'd2000;
  wire [15:0] sum16;

  // Instance with default WIDTH=8
  adder adder8 (.a(a8), .b(b8), .sum(sum8));

  // Instance with WIDTH=16
  adder #(16) adder16 (.a(a16), .b(b16), .sum(sum16));

  initial begin
    #1;
    $display("8-bit sum: %d + %d = %d", a8, b8, sum8);
    $display("16-bit sum: %d + %d = %d", a16, b16, sum16);
  end
endmodule
Output
8-bit sum: 15 + 10 = 25 16-bit sum: 1000 + 2000 = 3000
⚠️

Common Pitfalls

Common mistakes when using parameterized modules include:

  • Forgetting to use #() when overriding parameters during instantiation, which causes the default value to be used.
  • Using parameters inside the module before they are declared or initialized.
  • Confusing parameter with localparam (localparam cannot be overridden).
  • Not matching the parameter width with input/output port widths, causing synthesis or simulation errors.
verilog
/* Wrong: overriding parameter without #() */
module wrong #(parameter WIDTH = 8) (input [WIDTH-1:0] in, output [WIDTH-1:0] out);
  assign out = in;
endmodule

// Incorrect instantiation - parameter override ignored
wrong instance_wrong (.in(data), .out(data_out)); // WIDTH stays 8

/* Correct: use #() to override */
wrong #(16) instance_right (.in(data16), .out(data_out16));
📊

Quick Reference

Remember these tips when working with parameterized modules:

  • Declare parameters with parameter keyword inside the module.
  • Override parameters during instantiation using #(value) syntax.
  • Use parameters to set widths or constants for flexible modules.
  • Do not confuse parameter with localparam.

Key Takeaways

Use the parameter keyword inside modules to create customizable constants.
Override parameters during instantiation with #(new_value) syntax.
Parameters help make modules flexible for different bit widths or settings.
Always match parameter values with port widths to avoid errors.
localparam cannot be overridden, unlike parameter.