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.

13 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

  9. No. You don’t provide enough information to even begin to answer your question. You don’t seem like you even know enough to know what to ask. You don’t even ask politely. This is for a school assignment. Why should I help?

  10. Quoting an answer above.
    ——-
    student0 on December 8, 2011 at 3:19 am said:
    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.
    ——-
    Is there a better alternative?
    In my design, there are too many files where the .v file is included. It is inefficient to copy paste the function definition everywhere.

  11. Vineesh,

    I’m not sure that there is. One thing with ISE is the parser changes depending on which FPGA you are targeting. Certainly targeting a Virtex 5 versus a Virtex 6 will get you a different parser and thus different behavior. Much of this is history of course since things have been moved on to Vivado for a while now. Vivado is much better about this type of thing. Of course, you can use SystemVerilog in Vivado and use the import construct.

    If you must use Vivado, you could try my vpp Perl script. It is a Verilog preprocessor and will do the includes for you. This way ISE will just see the contents of the included file. But you will need to have some type of script or make file to build your sources. And that doesn’t integrate well with the ISE or Vivado GUI modes.

    -Pete

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.