verilogxilinx-iseicarus

$rtoi() is not a constant system function


I want to set size of a constant for a counter:

localparam MAX_COUNT = ((debounce_per_ms * clk_freq)) + 1;
parameter MAX_COUNT_UPPER = $rtoi($floor($log10(MAX_COUNT)/$log10(2)));

That work well with XST (ise) and with verilator but in Icarus I've got this error :

src/button_deb.v:20: error: $rtoi() is not a constant system function.

I can solve this using "integer" type :

parameter integer MAX_COUNT_UPPER = $floor($log10(MAX_COUNT)/$log10(2));

But that give me a warning in verilator:

$ verilator -cc src/button_deb.v
%Warning-REALCVT: src/button_deb.v:20: Implicit conversion of real to integer
%Warning-REALCVT: Use "/* verilator lint_off REALCVT */" and lint_on around source to disable this message.
%Error: Exiting due to 1 warning(s)
%Error: Command Failed /usr/local/bin/verilator_bin -cc src/button_deb.v

Do you think there is a good way to do this, and to be compatible with Icarus, verilator and Xst ?


Solution

  • $log10(MAX_COUNT)/$log10(2) is a way to calculate log2 when you do not have log2 available.

    In Verilog systems with $log10() available you should also have $log2().

    The floor function is to round to integer, this will round down. It is more common to want to round up to know the number of bits required to cover that number of locations.

    For this we have Ceiling log2 $clog2(). This is not an exact replacement for your function because it rounds up, not down.

    Example:

    parameter RAM_DEPTH      = 10;
    parameter RAM_ADDR_WIDTH = $clog2(RAM_DEPTH);
    

    The following should also have worked for you (no need to make integer type):

    parameter MAX_COUNT_UPPER = $floor($log10(MAX_COUNT)/$log10(2));