Parameters are Verilog constructs that allow a module to be reused with a different specification. For example, a 4-bit adder can be parameterized to accept a value for the number of bits and new parameter values can be passed in during module instantiation. So, an N-bit adder can become a 4-bit, 8-bit or 16-bit adder. They are like arguments to a function that are passed in during a function call.

	parameter MSB = 7;                  // MSB is a parameter with a constant value 7
	parameter REAL = 4.5;               // REAL holds a real number
	parameter FIFO_DEPTH = 256, 
	          MAX_WIDTH = 32;           // Declares two parameters
	parameter [7:0] f_const = 2'b3;     // 2 bit value is converted to 8 bits; 8'b3

Parameters are basically constants and hence it's illegal to modify their value at runtime. It is illegal to redeclare a name that is already used by a net, variable or another parameter.

There are two major types of parameters, module and specify and both accepts a range specification. But, they are normally made as wide as the value to be stored requires them to be and hence a range specification is not necessary.

Module parameters

Module parameters can be used to override parameter definitions within a module and this makes the module have a different set of parameters at compile time. A parameter can be modified with the defparam statement or in the module instance statement. It is a common practice to use uppercase letters in names for the parameter to make them instantly noticeable.

The module shown below uses parameters to specify the bus width, data width and the depth of FIFO within the design, and can be overriden with new values when the module is instantiated or by using defparam statements.

	// Verilog 1995 style port declaration
	module design_ip  ( addr,  
	     parameter  BUS_WIDTH    = 32, 
	                DATA_WIDTH   = 64,
	                FIFO_DEPTH   = 512;
	     input addr;
	     input wdata;
	     input write;
	     input sel;
	     output rdata;
	     wire [BUS_WIDTH-1:0] addr;
	     wire [DATA_WIDTH-1:0] wdata;
	     reg  [DATA_WIDTH-1:0] rdata;
	     reg [7:0] fifo [FIFO_DEPTH];
	     // Design code goes here ...

In the new ANSI style of Verilog port declaration, you may declare parameters as show below.

module design_ip 
	#(parameter BUS_WIDTH=32, 
		parameter DATA_WIDTH=64) (	
		input [BUS_WIDTH-1:0] addr,
   	// Other port declarations

Overriding parameters

Parameters can be overridden with new values during module instantiation. The first part instantiates the module called design_ip by the name d0 where new parameters are passed in within #( ). The second part uses a Verilog construct called defparam to set the new parameter values. The first method is the most commonly used way to pass new parameters in RTL designs. The second method is commonly used in testbench simulations to quickly update the design parameters without having to reinstantiate the module.

module tb;
	  // Module instantiation override
		design_ip  #(BUS_WIDTH = 64, DATA_WIDTH = 128) d0 ( [port list]);
		// Use of defparam to override
		defparam d0.FIFO_DEPTH = 128;


The module counter has two parameters N and DOWN declared to have a default value of 2 and 0 respectively. N controls the number of bits in the output effectively controlling the width of the counter. By default it is a 2-bit counter. Parameter DOWN controls whether the counter should increment or decrement. By default, the counter will decrement because the parameter is set to 0.

2-bit up-counter

module counter
  #( 	parameter N = 2,
   		parameter DOWN = 0)
  ( input 							clk,
    input 							rstn,
    input 							en,
   	output 	reg [N-1:0] out);
  always @ (posedge clk) begin
    if (!rstn) begin
      out <= 0;
    end else begin
      if (en)
        if (DOWN)
          out <= out - 1;
          	out <= out + 1;
         out <= out;     

The module counter is instantiated with N as 2 even though it is not required because the default value is anyway 2. DOWN is not passed in during module instantiation and hence takes the default value of 0 making it an up-counter.

module design_top (    input clk,
                input rstn,
                input en,
                output [1:0] out);

    counter #(.N(2)) u0 (	.clk(clk),

See that default parameters are used to implement the counter where N equals two making it a 2-bit counter and DOWN equals zero making it an up-counter. The output from counter is left unconnected at the top level.

4-bit down-counter

In this case, the module counter is instantiated with N as 4 making it a 4-bit counter. DOWN is passed a value of 1 during module instantiation and hence an down-counter is implemented.

module design_top (    input clk,
                input rstn,
                input en,
                output [3:0] out);

    counter #(.N(4), .DOWN(1)) 
    		u1 (	.clk(clk),

Specify parameters

These are primarily used for providing timing and delay values and are declared using the specparam keyword. It is allowed to be used both within the specify block and the main module body.

	// Use of specify block
		specparam  t_rise = 200, t_fall = 150;
		specparam  clk_to_q = 70, d_to_q = 100;
	// Within main module
	module  my_block ( ... );
	 	specparam  dhold = 2.0;
	 	specparam  ddly  = 1.5;
	 	parameter  WIDTH = 32;

Difference between specify and module parameters

Specify parameterModule parameter
Declared by specparamDeclared by parameter
Can be declared inside specify block or within main moduleCan only be declared within the main module
May be assigned specparams and parametersMay not be assigned specparams
SDF can be used to override valuesInstance declaration parameter values or defparam can be used to override