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;
    value = value-1;
    for (log2=0; value>0; log2=log2+1)
      value = value>>1;

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.

November 10, 2008 • Posted in: Verilog

9 Responses to “Constant Functions in Verilog 2001”

  1. dane - March 26th, 2010

    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.”


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


  2. dane - March 26th, 2010

    nevermind– silly typo in my module!

  3. UFK - May 28th, 2010

    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;
    clogb2 = 0;
    for(i = 0; 2**i < value; i = i + 1)
    clogb2 = i + 1;


  4. Pete Johnson - May 28th, 2010

    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.

  5. Abhi - June 30th, 2011

    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.

  6. admin - June 30th, 2011

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

  7. student0 - December 8th, 2011

    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.

  8. jen - July 2nd, 2012

    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~

  9. admin - July 2nd, 2012

    Yes, here’s the code

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

Leave a Reply