# VHDL constant value overflow

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?

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?

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

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.

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.

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.

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.

I already started to code such a functionality but only for VHDL, not for verilog.

1 Like

I maybe should have said senate in stead of community

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.

@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?)

I got bit by this again. MyHDL doesnâ€™t always handle the large constants correctly. Take, for example, this piece of MyHDL-generated VHDL:

``````if (signed(unsigned(rescale1_result(68-1 downto drop))) >= 68719476735) then
scaled_output <= signed'("011111111111111111111111111111111111");
rescale2_overflow <= '1';
elsif (signed(unsigned(rescale1_result(68-1 downto drop))) < (- 68719476736)) then
scaled_output <= signed'("100000000000000000000000000000000000");
rescale2_overflow <= '1';
else
scaled_output <= resize(signed(unsigned(rescale1_result(68-1 downto (drop + 1)))) + to_signed(rescale1_result(drop), 2), 36);
rescale2_overflow <= '0';
end if;
``````

68719476735 and -68719476736 are values of two MyHDL constants. They are over 32 bits long, so I would have expected to see them converted to bit string literals. However, the conversion result is a 37-bit wide integer that breaks the compilation in Quartus. Can someone point me to a place in the MyHDL source code where this happens, so I can fix it? (Or if @DrPiâ€™s constant type is ready, Iâ€™d be glad to test it.)

Can you provide a fully functional minimal example reproducing the problem ?

In this case as the test-values are a power of 2 you could, as a work-around, use simple bit checking:

``````SCALING = 36
if not rescale_result[high] and rescale_result[high - 1 : drop + SCALING] != 0:
scaled_output.next =  ...
elif rescale_result[high] and rescale_result[high - 1 : drop + SCALING] == 0:
scaled_output.next = ....
else:
...
``````

This is how I did it in VHDL

@DrPi, hereâ€™s a minimum working example:

``````from myhdl import block, always_comb, Signal, intbv

@block
def test_constant(x, y):
THRESHOLD = 2**(len(x) - 2)

@always_comb
def logic():
if x > THRESHOLD:
y.next = 1
else:
y.next = 0

return logic

if __name__ == '__main__':
x = Signal(intbv(0, -2**35, 2**35))
y = Signal(bool(0))
rtl = test_constant(x, y)
rtl.convert('VHDL')
``````

The VHDL conversion results in:

``````library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;

use work.pck_myhdl_010.all;

entity test_constant is
port (
x: in signed (35 downto 0);
y: out std_logic
);
end entity test_constant;

architecture MyHDL of test_constant is

begin

TEST_CONSTANT_LOGIC: process (x) is
begin
if (x > 17179869184) then
y <= '1';
else
y <= '0';
end if;
end process TEST_CONSTANT_LOGIC;

end architecture MyHDL;
``````

The threshold constant 17179869184 is wider than 32 bits, but it is not expressed as a bit string literal.

@josyb, I used to do that (check that the high bits are either all 0 or all 1). If I remember correctly, it results in fewer FPGA resources being used as a bonus. However, if you want rounding, a new case is introduced (high bits all 0, low bits all 1), so the code would be much more readable with simple >= and < checks.

As a quick workaround, you can declare THRESHOLD like this :

``````THRESHOLD = Signal(intbv(2**(len(x) - 2), -2**35, 2**35))
``````

Iâ€™m working on a better solution.

1 Like

The fix is 4 lines of code in _toVHDL.py module.

In _AnnotateTypesVisitor() class, the new code for visit_Compare() function is the following :

``````    def visit_Compare(self, node):
node.vhd = vhd_boolean()
self.generic_visit(node)
left, op, right = node.left, node.ops[0], node.comparators[0]
if isinstance(left.vhd, vhd_std_logic) or isinstance(right.vhd, vhd_std_logic):
left.vhd = right.vhd = vhd_std_logic()
elif isinstance(left.vhd, vhd_unsigned) and maybeNegative(right.vhd):
left.vhd = vhd_signed(left.vhd.size + 1)
elif maybeNegative(left.vhd) and isinstance(right.vhd, vhd_unsigned):
right.vhd = vhd_signed(right.vhd.size + 1)
if isinstance(left.vhd, (vhd_nat, vhd_int)) :    # New
left.vhd = right.vhd                         # New
if isinstance(right.vhd, (vhd_nat, vhd_int)) :   # New
right.vhd = left.vhd                         # New
node.vhdOri = copy(node.vhd)
``````
1 Like