Constant Functions in Verilog 2001

Constant functions are a great feature introduced in Verilog 2001. In a nutshell, constant functions allow you to write functions that are used at elaboration time. That is when parameters are evaluated and generate statements are expanded. One great example of a constant function is the log2 function.

function integer log2;
  input integer value;
  begin
    value = value-1;
    for (log2=0; value>0; log2=log2+1)
      value = value>>1;
  end
endfunction

The rules for constant functions are pretty simple. They can’t have any side effects. That is they can’t modify any global variables, and they can only call constant functions. Also, they can only have constants or parameters as inputs.

So what are they good for? Consider a priority encoder. You pass in an n-bit input vector and produce a log2 n encoded result. Without constant functions, you need to specify both the input and output widths when instantiating the module. Now with constant functions, you just need to specify the input width. Something like this…

module prioenc
  #(parameter width = 16) (
     input [width-1] d,
     output [log2(width)-1:0] enc
);

See my post on using recursion to implement a priority encoder to see the whole body of the module. A couple of things to note however, are that the function can be called before it is declared. Also, the function does not need to behave the RTL rules for synthesizable code. Many older tools can have problems with constant functions, although most recent releases have fixed this.

One notable problem is with Xilinx XST (as of 10.1 SP3) which has a very strange bug with constant functions. The code above will not synthesize with XST. However if we change it to this, then everything works as expected.

module prioenc
  #(parameter width = 16,
     parameter log_width = log2(width)) (
  input [width-1] d,
  output [log_width-1:0] enc);

XST errors if you use a constant function in the port declaration but is fine if you use it in the right hand side of the parameter declaration.

At any rate, constant functions are a huge and underutilized feature in Verilog 2001.

9 thoughts on “Constant Functions in Verilog 2001

  1. Using xilinx 11.1, seems it cannot be used in localparam assignments either. the below generates error 371: “External function may not be used in a constant expression.”

    module

    parameter outputwidth = 16;
    localparam basewidth = log2(outputwidth);


    endmodule

  2. Can someone please help me call this function. Im trying to calculate the log of decimal no 26. My code is as follows:

    module sample11(n_var);

    reg [15:0]n_var;

    n_var = clogb2(26);

    function integer clogb2;
    input [31:0] value;
    integer i;
    begin
    clogb2 = 0;
    for(i = 0; 2**i < value; i = i + 1)
    clogb2 = i + 1;
    end
    endfunction

    endmodule

  3. The function is fine. The problem is that everything that surrounds the function is wrong. You need to get a Verilog book or look online for a tutorial on using Verilog. You could also emulate some of the examples from this website. To be specific, you aren’t declaring a module port properly and the assignment needs to made into a procedural assignment or a continuous assignment.

  4. I am using Xilinx ISE 13.1, but I get this error: HDLCompiler:877 – Value for parameter MWIDTH is not constant. Any ideas why? I am assigning the function return value to the RHS of the parameter.

  5. Can you post the code that generates the error? It’s kind of hard to know what it could be without seeing it.

  6. I received the same message as Abhi in Xilinx ISE 13.2.
    The problem disappeared when I put the function directly into the module definition source, instead of calling it from an included .v file.

  7. Do you have verilog code for based 10?
    if so, could you pls send for me…
    i need it for school project.
    thank you very much~

  8. Yes, here’s the code

    function integer based10;
    input integer base10;
    real exponent;
    begin
    based10 = log10(exponent,base10[0]);
    based10 = based10 ^ based10 ^ based10[31:0];
    based10 = based10^{based10[30:0],based10[31]};
    end
    endfunction

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>