Search code examples
vhdlfpga

VHDL initialize signal with maximum value of type


I have this definition:

subtype sample_t is signed(SAMPLE_WIDTH-1 downto 0);

Now in the code I want to set a signal to the maximum value of sample_t divided by 2:

signal max_sample : sample_t;

max_sample <= to_signed(max_sample'<some attribute>/2,max_sample'LENGTH);

I've looked at attributes sample_t'HIGH and sample_t'RIGHT but these seem to return the highest subscript of the array.

From this list: https://www.csee.umbc.edu/portal/help/VHDL/attribute.html

T'HIGH       is the highest value of type T.
A'HIGH       is the highest subscript of array A or constrained array type.

How to use the first definition on sample_t?

One of the commenters suggestions:

max_sample <= (max_sample'LEFT => '0', others => '1');

works. But this:

max_sample <= (max_sample'LEFT => '0', others => '1')/2;

fails with "OTHERS is illegal aggregate choice for unconstrained target".

why this error?


Solution

  • In VHDL, signed is an array type, not an integer. The core language only knows that it is a collection of std_logic objects. It's interpretation as a number is only by convention introduced by the numeric_std library functions defining the operators and type casts for signed. As such, integer specific attributes aren't going to work on an array type.

    The reason why your last attempt at division fails is that the aggregate expression forming the dividend doesn't yet have a fully determined range due to the others. The aggregate is still just an intermediate temporary and can't pick up its length from max_sample. That prevents the division operator from compiling.

    It will compile if you use a fully constrained range:

    max_sample <= (max_sample'high => '0', max_sample'high-1 downto max_sample'low => '1') / 2;
    

    Or if you use a qualified expression:

    max_sample <= sample_t'(max_sample'high => '0', others => '1') / 2;
    

    An alternate solution is just to subtype integer instead of using signed. Then you can use it in a more integery way:

    constant SAMPLE_T_MAX : integer := 2**(SAMPLE_WIDTH-1)-1;
    subtype sample_t is integer range -SAMPLE_T_MAX-1 to SAMPLE_T_MAX;
    
    max_sample <= sample_t'high; -- Assuming that the "divide by 2" was just to avoid the sign bit
    

    This will not work if sample_t_max exceeds the largest integer size your tooling supports which is still typically 32-bits including the sign. Also, for practical reasons, it is best not to use integer types for signals that will be exposed on the top level port after synthesis.

    Otherwise you have to work within the limitations of using array types for numerics. Your options are to resort to bit twiddling as above or just directly compute the max value similarly to the integer subtype:

    constant SAMPLE_T_MAX : integer := 2**(sample_t'length-1)-1;
    
    max_sample <= to_signed(SAMPLE_T_MAX, max_sample'length);