dwjbosman
dwjbosman

Reputation: 966

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?

Upvotes: 1

Views: 11207

Answers (2)

user1155120
user1155120

Reputation:

The accepted answer from Kevin Thibedeau could not be readily reconciled with the actual question (why this error?). The answer can be explained in terms of the VHDL standard.

First a Minimum, Complete, and Verifiable example can be constructed for the question:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity foo is
end entity;

architecture fum of foo is
    constant SAMPLE_WIDTH:  natural := 42;   -- pick a  number
    subtype sample_t is signed(SAMPLE_WIDTH-1 downto 0);
    signal max_sample : sample_t;
begin
    -- max_sample <= (max_sample'LEFT => '0', others => '1'); -- analyzes
    max_sample <= (max_sample'LEFT => '0', others => '1')/2;  -- Doesn't analyze
end architecture;

Because we're dealing with semantic rules during analysis (compile) the example doesn't have to do anything besides replicate the error. Error messages aren't standardized in VHDL and will vary by implementation.

The semantics for using an others choice in an aggregate:

IEEE Std 1076-2008 9.3 Aggregates, 9.3.3 Array aggregates, para 7 (in part):

The index range of an array aggregate that has an others choice shall be determinable from the context. That is, an array aggregate with an others choice shall appear only in one of the following contexts: ...

e) As a value expression in an assignment statement, where the target is a declared object (or member thereof), and either the subtype of the target is a fully constrained array subtype or the target is a slice name

This is why the first example (commented out) analyzes. sample_t is a fully constrained subtype, see 5. Types, 5.1 General the definition of fully constrained, para 6 (in part):

A composite subtype is said to be fully constrained if:

-- It is an array subtype with an index constraint and the element subtype either is not a composite subtype or is a fully constrained composite type, or
...

Where the sample_t element base type is std_ulogic and the subtype has an index constraint.

Back to the second example.

We don't satisfy rule e), the aggregate isn't a value expression for the assignment statement, it's an operand for the division operator defined by the "/" function for overload in IEEE package numeric_std:

-- Id: A.25
function "/" (L : UNRESOLVED_SIGNED; R : INTEGER) return UNRESOLVED_SIGNED;
-- Result subtype: UNRESOLVED_SIGNED(L'LENGTH-1 downto 0)
-- Result: Divides an UNRESOLVED_SIGNED vector, L, by an INTEGER, R.
--         If NO_OF_BITS(R) > L'LENGTH, result is truncated to L'LENGTH.

(For earlier revisions of numeric_std the parameter and result types would be SIGNED instead of UNRESOLVED_SIGNED, -2008 formally defines how resolution functions of composite types drivers are defined.)

Because the rules of 9.3.3 paragraph 7 are inclusive instead of exclusive we need to find a rule that allows us to use the aggregate, and one is readily identified:

i) As the operand of a qualified expression whose type mark denotes a fully constrained array subtype

We can use a qualified expression:

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

And this analyzes (compiles) successfully.

To clarify the value expression being assigned to max_sample is the result of division by 2 which uses an operator overload and who's function does not return a constrained subtype. (UNRESOLVED_SIGNED or SIGNED is not constrained).

The reason why there are inclusive rules is to allow the code for associating values with elements of an aggregate to be determined at analysis time (compile time). You'd find by examining previous revisions of the VHDL standard that the list of inclusive rules has been expanded.

The answer to your question with respect to the second example:

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

is that the elements of the aggregate can't be identified without knowing the subtype from context.

If you were to look at the output of the parser producing an abstract syntax tree used for semantic analysis the right hand side expression in the assignment statement can be expressed hierarchically. (11.6 Concurrent signal assignment statements, the waveform is comprised of one or more waveform elements, see 10.5.2 Simple signal assignments, 10.5.2.1 General, a waveform element can contain a value expression, see 10.5.2.2 Executing a simple assignment statement, 9. Expressions, 9.1 General the BNF.)

Using inclusive rules alleviates the need of traversing the expression hierarchy and calculating the subtype of the aggregate (an operand) during analysis and would require semantic characterization of the "/" function not required by the standard. You can also construct cases where the subtype can't be readily ascertained by characterization at analysis time. The result is the rules found in 9.3.3 Array aggregates paragraph 7.

The qualified expression provides the subtype directly.

Upvotes: 1

Kevin Thibedeau
Kevin Thibedeau

Reputation: 3411

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);

Upvotes: 3

Related Questions