Using Parameters in System Verilog

Introduction to Parameters in System Verilog

In a digital design, it’s common to need to make small changes (usually localparams) that will affect the functionality of an overall design to meet project specifications. As an example, suppose you need to transmit data to two UART compatible devices and you decide to use/instance two of your UART transmitters from ECEn 220. You find out that one of the devices uses a BAUD rate of 115200 while the other device uses a BAUD rate of 9600. You then realize that the UART transmitter from the ECEn 220 lab is only configured for a BAUD rate of 19200 which means you would have to create a new UART module and rewrite the ECEn 220 UART again but configured for a BAUD rate of 9600 then repeat the process for a BAUD rate of 115200.

The example above illustrates how inconvenient and awkward it can be to adapt hardware for similar use cases with small differences. The solution is to write a generic UART transmitter that uses a parameter to set the BAUD rate (you could even add more parameters to set something like the parity type (ODD, EVEN, NONE)). The parameter can then be adjusted accordingly to each module instanced. It’s important to highlight that another benefit of using parameters is for future reusability which prevents code from being rewritten/designed.

How to Add a Parameter to a Module in System Verilog

For a parameter to be modified when instancing, the module has to have the parameter defined. The notation to add a parameter to a module is:

module "module_name" #(parameter "parameter1_name"="default_value")("ports");

where the variables within the quotes are whatever the names/values are for the module, parameters, the default values for parameters and ports. Here’s an example of adding a parameter to a module using the UART transmitter from the previous examples.

module tx #(parameter BAUD_RATE=19200)(clk, Reset, Send, Din, Sent, Sout);
    // Define ports
    .
    .
    .

    // Do some math to convert BAUD_RATE into number of ticks
    .
    .
    .
    
    // UART transmitter logic
    .
    .
    .

endmodule

How to Modify (Override) a Parameter when Instancing a Module in System Verilog

It’s important to first understand that all parameters are CONSTANTS. Using the UART from above as an example, suppose that you must reduce the logic in your design. You decide to remove one of the UART instanced modules and add logic to the other instanced UART module that will change BAUD_RATE depending on the value of the down button. This is NOT possible with parameters since it would require the hardware to change for given conditions (the down button).

The notation to override a parameter of a instanced module is:

"module_instance_name" #(."parameter1_name"("constant1")) "module_name"("ports");

where the variables within the quotes are whatever the names/values are for the module instance name, module, parameters, constants and ports. Here’s an example of using a top module to instance two UART transmits from the previous examples.

module top_device_talker ("ports");
    // Define ports
    .
    .
    .

    localparam DEVICE1_BAUD_RATE = 115200;
    localparam DEVICE2_BAUD_RATE = 9600;

    tx #(.BAUD_RATE(DEVICE1_BAUD_RATE)) tx_device1("ports");

    tx #(.BAUD_RATE(DEVICE2_BAUD_RATE)) tx_device2("ports");
    
    .
    .
    .

endmodule

It’s worth noting that if #(."parameter1_name"("constant1")) is not included in the instanced module then the default value of that parameter will be used ("default_value"). In the case of the UART example, that would be 19200.


Last Modified: 2024-07-01 00:08:02 +0000