techmore.in

Verilog parameterized Modules

In Verilog, parameterized modules allow you to create reusable and flexible designs by defining parameters that can be configured when the module is instantiated. This helps in creating generic modules that can be used in multiple contexts by changing specific parameters, such as word widths, data sizes, or array dimensions, without altering the underlying module code.

Defining Parameters in a Module

You define parameters using the parameter keyword. These parameters can then be used throughout the module, allowing the module to become flexible with configurable properties like bit-widths, sizes, or constants.

Syntax:

verilog
module module_name #(parameter PARAM_NAME = default_value) (input ..., output ...); // Internal logic using PARAM_NAME endmodule

In the above syntax:

  • parameter keyword declares a parameter.
  • PARAM_NAME is the name of the parameter.
  • default_value is the value that the parameter takes if no other value is specified when the module is instantiated.

Example of a Parameterized Module

Let’s consider a parameterized adder module where the bit-width of the input and output can be controlled via a parameter.

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

In this example:

  • The parameter WIDTH determines the bit-width of the input and output signals.
  • The default width is 8 bits, but it can be changed when the module is instantiated.

Instantiating a Parameterized Module

When you instantiate the module, you can either use the default parameter value or override it by specifying a different value.

Instantiation Using Default Parameter:

verilog
adder my_adder ( .a(a), .b(b), .sum(sum) );

In this case, WIDTH will be 8 (the default value).

Instantiation With a Different Parameter Value:

verilog
adder #(16) my_adder_16bit ( .a(a), .b(b), .sum(sum) );

Here, WIDTH is explicitly set to 16, so the module will work with 16-bit input and output signals.

Example: Parameterized Multiplexer

Another common use of parameters is in the creation of a multiplexer. A parameterized multiplexer can support different sizes of inputs based on the parameter value.

verilog
module mux #(parameter WIDTH = 8) ( input [WIDTH-1:0] in0, input [WIDTH-1:0] in1, input select, output [WIDTH-1:0] out ); assign out = (select) ? in1 : in0; endmodule

In this example:

  • The parameter WIDTH controls the bit-width of the multiplexer inputs and output.
  • The default width is 8 bits, but this can be overridden during instantiation.

Instantiating the Parameterized Multiplexer:

verilog
mux #(4) my_4bit_mux ( .in0(in0), .in1(in1), .select(select), .out(out) );

Here, WIDTH is set to 4, meaning the multiplexer will operate on 4-bit inputs and produce a 4-bit output.

Parameterized Modules with Multiple Parameters

You can define multiple parameters in a module to further increase its flexibility. Each parameter can have its own default value, and you can selectively override them during instantiation.

Example: Parameterized RAM Module

verilog
module ram #(parameter DATA_WIDTH = 8, parameter ADDR_WIDTH = 4) ( input clk, input [ADDR_WIDTH-1:0] addr, input [DATA_WIDTH-1:0] data_in, input we, output reg [DATA_WIDTH-1:0] data_out ); reg [DATA_WIDTH-1:0] memory [(1<<ADDR_WIDTH)-1:0]; // Memory array always @(posedge clk) begin if (we) memory[addr] <= data_in; // Write operation else data_out <= memory[addr]; // Read operation end endmodule

In this example:

  • DATA_WIDTH controls the width of the data inputs and outputs.
  • ADDR_WIDTH controls the number of address bits (hence the depth of the memory).

Instantiating the Parameterized RAM:

verilog
ram #(16, 8) my_ram ( .clk(clk), .addr(addr), .data_in(data_in), .we(we), .data_out(data_out) );

Here, DATA_WIDTH is set to 16 bits, and ADDR_WIDTH is set to 8 bits, meaning the RAM will have 16-bit data and 256 addresses.

Local Parameters

In addition to regular parameters, Verilog allows the use of local parameters. A localparam is a constant value within the module that cannot be overridden when the module is instantiated. This is useful when you want to define constants inside a module but don't want them to be modifiable externally.

Example:

verilog
module localparam_example; localparam DELAY = 5; // Internal constant, not modifiable from outside reg [3:0] a; initial begin a = 4'b0001; #DELAY a = 4'b0010; // Delay is a constant end endmodule

Advantages of Parameterized Modules

  • Reusability: You can design a module once and reuse it with different configurations.
  • Scalability: By changing parameter values, the same module can handle different sizes of inputs or outputs, making it scalable.
  • Maintainability: Instead of duplicating code, you maintain one generic version, which reduces redundancy and eases debugging.

Summary

  • Parameterized modules allow the creation of flexible, reusable designs by defining configurable parameters.
  • Parameters are defined with the parameter keyword and can be overridden during instantiation.
  • You can use local parameters (localparam) for internal constants that cannot be overridden.
  • Parameterized modules simplify design by enabling scalability and reusability.

Understanding how to use parameterized modules is a crucial skill in Verilog, allowing you to write more efficient, scalable, and maintainable hardware descriptions.