3
votes

In vhdl I can define my own enumeration type and create a signal of this type:

type tp is (red,green,blue,yellow);
signal sg: tp := red;

But now I want a for loop to run over all of these states. Something like

for i in sg'min to sg'max loop
   <something>
end loop;

In c++ there are iterators for this purpose. But in VHDL all I can find is sg'pos that converts the signal to a number that I can increment. But I cannot seem to find a way to convert the number back to a signal.

2
Do you want to do this in a testbench or in something that's supposed to become hardware? Because if it's the latter: this screams XY problem. - DonFusili

2 Answers

1
votes

This is what you need:

for i in tp'left to tp'right loop
   <something>
end loop;

`left and `right are called type attributes. They are useful in your testbench, but not recommended for your design. This is because you the synthesiser may change the order of the enumerations, which might cause you problems.

0
votes

You can specify the type of the loop parameter where the discrete range is a range of values of a specified scalar type:

entity enum is
end entity;

architecture enum_range of enum is
    type tp is (red,green,blue,yellow);
    signal sg: tp := red;
begin
    process (sg)
    begin
        for i in tp range red to yellow loop
            if sg = i then
                report "sg = " & tp'image(sg);
            end if;
        end loop;
    end process;
end architecture;

This produces:

enum.vhdl:12:17:@0ms:(report note): sg = red



TL;DR explanation

IEEE Std 1076-2008 10.10 Loop statement

iteration_scheme ::=
      while condition
    | for loop_parameter_specification

parameter_specification ::=
     identifier in discrete_range

and

For a loop statement with a for iteration scheme, the loop parameter specification is the declaration of the loop parameter with the given identifier. The loop parameter is an object whose type is the base type of the discrete range. Within the sequence of statements, the loop parameter is a constant. Hence, a loop parameter is not allowed as the target of an assignment statement. Similarly, the loop parameter shall not be given as an actual corresponding to a formal of mode out or inout in an association list.

For the execution of a loop with a for iteration scheme, the discrete range is first evaluated. If the discrete range is a null range, the iteration scheme is said to be complete and the execution of the loop statement is therefore complete; otherwise, the sequence of statements is executed once for each value of the discrete range (subject to the loop not being left as a consequence of the execution of a next statement, an exit statement, or a return statement), after which the iteration scheme is said to be complete. Prior to each such iteration, the corresponding value of the discrete range is assigned to the loop parameter. These values are assigned in left-to-right order.

5.3.2 Array types, 5.3.2.1 General

discrete_range ::= discrete_subtype_indication | range

5.3.2.2 Subtype indications

subtype_indication ::=
     [ resolution_indication ] type_mark [ constraint ]

constraint ::=
      range_constraint
    | array_constraint
    | record_constraint

5.2 Scalar types 5.2.1 General

range_constraint ::= range range

range ::= range_attribute_name
     | simple_expression direction simple_expression

direction ::= to | downto

It helps to understand how defining a range as the discrete range works. Without specifying a subtype indication in the discrete range the type is derived from the simple expressions in the range. The type of a numeric literal (9.3.2 Literals) is universal_integer convertible to type integer. The type can also be supplied by attribute as Matthew Taylor shows. Only dipping a toe in simple_expression (9.1) term -> factor -> primary, a primary can be a name (attribute name, 8.6) or a literal.

BNF other than found in Annex C (informative) Syntax summary, is normative.