- Verilog Basics
- Verilog Introduction
- Verilog Install
- Verilog Datatypes
- Verilog Conditions
- Verilog Loops
- Verilog Objects
- Verilog Libs
- Verilog Control Flow
- Verilog Modules
- Verilog Ports
- Verilog Operators
- Verilog Procedural Blocks
- Verilog Wires
- Verilog - Advanced
- Verilog Param-Modules
- Verilog Interfaces
- Verilog Classes
- Verilog Assertions
- Verilog Generating Blocks
- Verilog Clocking Blocks
- Verilog State Machines
- Verilog Coverage
- Verilog Race Conditions
- Verilog Timing
- Verilog Testing
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:
verilogmodule module_name #(parameter PARAM_NAME = default_value) (input ..., output ...); // Internal logic using PARAM_NAME endmodule
In the above syntax:
parameterkeyword declares a parameter.PARAM_NAMEis the name of the parameter.default_valueis 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.
verilogmodule 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
WIDTHdetermines 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:
verilogadder my_adder ( .a(a), .b(b), .sum(sum) );
In this case, WIDTH will be 8 (the default value).
Instantiation With a Different Parameter Value:
verilogadder #(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.
verilogmodule 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
WIDTHcontrols 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:
verilogmux #(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
verilogmodule 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_WIDTHcontrols the width of the data inputs and outputs.ADDR_WIDTHcontrols the number of address bits (hence the depth of the memory).
Instantiating the Parameterized RAM:
verilogram #(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:
verilogmodule 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
parameterkeyword 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.