VHDL constant value overflow


#1

How do MyHDL people usually work around the VHDL size limit for integer literals? Consider the following MyHDL code:

Y_LEN = 71
Y_MIN, Y_MAX = (-2**(Y_LEN - 1), 2**(Y_LEN - 1))
y = Signal(intbv(0, Y_MIN, Y_MAX))

# An attempt to implement saturation somewhere in the code
if result < 0:
    accumulator.next = Y_MIN
else:
    accumulator.next = Y_MAX - 1

This converts to VHDL as follows:

if (result < 0) then
    accumulator <= signed'("11111111111111111111111111111111111100000000000000000000000000000000000");
else
    accumulator <= to_signed(34359738368 - 1, 71);
end if;

The first case translates to a bit string literal, which is fine (although hexadecimal would be much easier to read than binary at these lengths). The second case with the arithmetic operation translates to an integer literal that is too large – at least as far as the compiler is concerned. Tweaking the constants would take care of this, but all the added plus ones and minus ones are not exactly good for reducing off-by-one errors. Are there any other options?


#2

Would it be difficult or undesirable for some reason to have MyHDL compute the result of constant expressions and replace them with bit string literals, just like in the case of a single constant?


#3

IMHO it should be fairly straightforward to do, and surely an improvement. It would even be nicer if his code would generate a constant declaration:

    constant prefix_Y_MIN : signed(70 downto 0) := b"100...000...000...000";
    constant prefix_Y_MAX : signed(70 downto 0) := x"3fffffffffffffffff";
    constant prefix_Y_MAX_ALT : signed(70 downto 0) := (x"3fffffffffffffffff")(70 downto 0);

I’m not sure whether the hexadecimal notation will apply if the bits are a: not a multiple of 4 and b: more than 32. Perhaps the the alternative notation works?

BTW: 34359738368 != 2**70, neither is the binary string equal to -2**70


#4

Ah, yes! Constant declarations would be sweet. I could try implementing them myself, but I find the MyHDL source code a bit hard to navigate, so I don’t know where to look for it.

Hexadecimal string literals need to contain a multiple of four bits, but there is no limit to the length. Only integers are limited to 32 bits. (Or is it 34 bits in the spec? Vendor tools may have the 32-bit limit anyway.)

True. The saturation is at 36 bits. I copied a piece of code without thinking, so the Y_MIN and Y_MAX are not what they are supposed to be.


#5

I wonder whether the community is ready for a Constant type, but I think we can do it under the radar by tweaking the _toVHDL.py code.
It would be nice if you’d provide small but complete example code; it saves me from having to type (and think) to get a test running.


#6

Would this Q0.x fixed-point gain be small enough?

"""Scale fixed-point signal"""

from myhdl import block, always_comb, always_seq
from myhdl import Signal, ResetSignal, intbv

@block
def rescale(clk, reset, x, gain, shift, y):
    """Rescale with fractional gain and bit shift

    The rescale block operates with signed (two's complement) fixed-point
    numbers [-1.0, 1.0) with the following roles:
        Input:   x
        Output:  y = gain * x << shift
    """
    X_LEN = len(x)
    Y_LEN = len(y)
    GAIN_LEN = len(gain)
    Y_MIN, Y_MAX_M1 = (-2**(Y_LEN - 1), 2**(Y_LEN - 1) - 1)
    ZERO_SHIFT = GAIN_LEN - 1 + X_LEN - Y_LEN
    RESULT_LEN = Y_LEN + shift
    RESULT_MIN, RESULT_MAX = (-2**(RESULT_LEN - 1), 2**(RESULT_LEN - 1))
    
    # Internal signals
    result = Signal(intbv(0, RESULT_MIN, RESULT_MAX))
    
    @always_comb
    def logic():
        """Rescale"""
        result.next = x * gain >> ZERO_SHIFT - shift

    @always_seq(clk.posedge, reset=reset)
    def propagate():
        """Update y, and saturate in case of overflow"""
        if result[:Y_LEN].signed() > 0:
            y.next = Y_MAX_M1
        elif result[:Y_LEN].signed() < -1:
            y.next = Y_MIN
        else:
            y.next = result

    return logic, propagate

# Auxiliary functions

def convert(hdl):
    """Convert the design to HDL"""
    clk = Signal(bool(0))
    reset = ResetSignal(0, active=1, async=True)
    gain, shift = [Signal(intbv(0)[32:]) for _ in range(2)]
    x, y = [Signal(intbv(0)[32:]) for _ in range(2)]
    rtl = rescale(clk, reset, x, gain, shift, y)
    rtl.convert(hdl)

if __name__ == '__main__':
    convert('VHDL')

It doesn’t have constant arithmetic expressions aside from the declaration, though, but one could change the following lines to make one:

Y_MIN, Y_MAX = (-2**(Y_LEN - 1), 2**(Y_LEN - 1))
y.next = Y_MAX - 1

Edit: The original example was purely combinational, but I’m not sure not sure whether it was actually synthesizable.


#7

With VHDL 2008, you can specify the bit length of the literal : 3X"2" is equal to “010”.
The MyHDL VHDL converter already uses this notation.

We already spoke about this before in other threads. I think we need constants in MyHDL.
I already started to code such a functionality but only for VHDL, not for verilog.


#8

I maybe should have said senate in stead of community :slight_smile:


#9

Do you mean this one? What do you guys think about adding generics support in the constant type? In my opinion, the constructor for the constant type could have a named parameter with default value parameter=False. If parameter were set to True, a generic would be generated instead of a constant.


#10

@mhavu
No, not this one.
There are few threads where it is discussed. I don’t remember which one exactly except this one : VHDL conversion - missing constant

From my point of view, the problem with MyHDL dev is with PRs that are very long to be accepted/rejected ( A future for the MyHDL community?)