Home > Software design >  How to use imported enum in if condition?
How to use imported enum in if condition?

Time:05-10

In a process I need to do something depending if one of the ports has a specific value. This value is defined in a type def in a separate package file.

The comparison should be done in an 'if-statement' to have short and readable code.

As I need to make sure there is no confusion I cannot use use work.pkg.all, instead I use pkg_name.enum_name


    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    use work.all;
    
    use work.SAWTOOTH_INNER_pkg.all;  -- other pkg which is needed. 
    
    entity SAWTOOTH_entity is
        PORT(
            p_clk : in std_logic;
            p_event_enum_next : in SAWTOOTH_pkg.in_event_enum
        );
    end entity;

    architecture arch of SAWTOOTH_entity is
    
    begin
        process(p_clk)
        begin
            if rising_edge(p_clk) then              
                
                -- Throws error. Modelsim says 'no feasable entry for /='
                if (p_event_enum_next /= SAWTOOTH_pkg.event_enum_empty) then
                    -- do something
                end if;
                
                -- Does the same but compiles without errors. But it is much longer.
                case p_event_enum_next is
                    when  SAWTOOTH_pkg.event_enum_empty =>
                        -- do nothing
                    when others =>  
                        -- do something
                end case;
            end if;
        end process;        
    end architecture;

Edited: more information:

Exact error:

** Error: C:\Users\4DIAC\Desktop\ModelSimWS\Bug.vhd(25): (vcom-1581) No feasible entries for infix operator '/='.
** Error: C:\Users\4DIAC\Desktop\ModelSimWS\Bug.vhd(25): Type error resolving infix expression "/=" as type std.STANDARD.BOOLEAN.

The packages: SAWTOOTH_INNER_PKG:

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

    package SAWTOOTH_INNER_pkg is
            
            TYPE in_event_enum is (event_enum_empty, event_enum_START, event_enum_STOP, event_enum_REQ, event_enum_CONFIG);
            TYPE buffer_event_type is array (0 to 3) of in_event_enum;
            

                    
     end SAWTOOTH_INNER_pkg;

SAWTOOTH_PKG:

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

use work.all;

package SAWTOOTH_pkg is
    
    TYPE in_event_enum is (event_enum_empty, event_enum_CONFIG, event_enum_START, event_enum_STOP);
    TYPE buffer_event_type is array (0 to 3) of in_event_enum;

                
 end SAWTOOTH_pkg;


CodePudding user response:

There's a defect in the purported declaration of package SAWTOOTH_pkg in the question in that while the question text says SAWTOOTH_pkg the declaration is shown as SAWTOOTH_INNER_pkg:

SAWTOOTH_PKG:

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

    package SAWTOOTH_INNER_pkg is
            
            TYPE in_event_enum is (event_enum_empty, event_enum_START, event_enum_STOP, event_enum_REQ, event_enum_CONFIG);
            TYPE buffer_event_type is array (0 to 3) of in_event_enum;
            

                    
     end SAWTOOTH_INNER_pkg;

For purposes of a minimal, complete, and verifiable example these two packages can be identical other than the package name, so package SAWTOOTH_pkg should have the package name as SAWTOOTH_pkg (in both places) in place of SAWTOOTH_INNER_pkg.

Predefined operators are implicitly declared immediately following a type declaration. The implication is that making the type declaration visible by selected name doesn't make the the operator declarations visible.

IEEE Std 1076-2008
9.2 Operators
9.2.3 Relation operators

The equality and inequality operators (= and /=) are defined for all types other than file types and protected types. The equality operator returns the value TRUE if the two operands are equal and returns the value FALSE otherwise. The inequality operator returns the value FALSE if the two operands are equal and returns the value TRUE otherwise.

The standard includes a mechanism for providing overloading subprograms and operators in subsections 4.5 Subprogram overloading, 4.5.1 General, 4.5.2 Operator overloading ("The declaration of a function whose designator is an operator symbol is used to overload an operator. The sequence of characters of the operator symbol shall be one of the operators in the operator classes defined in 9.2.") and 4.5.3 Signatures. These can be used to overload operators for new types such as your enumeration type (5.2 Scalar types 5.2.1 General) in_event_enum.

12.5 The context of overload resolution

12.5 The context of overload resolution

Overloading is defined for names, subprograms, and enumeration literals.

For overloaded entities, overload resolution determines the actual meaning that an occurrence of an identifier or a character literal has whenever the visibility rules have determined that more than one meaning is acceptable at the place of this occurrence; overload resolution likewise determines the actual meaning of an occurrence of an operator or basic operation (see 5.1).

Here entities refers to named entities and not external blocks declared by an entity declaration.

All this is predicated on 12.3 Visiblity:

For each identifier and at each place in the text, the visibility rules determine a set of declarations (with this identifier) that define the possible meanings of an o ccurrence of the identifier. A declaration is said to be visible at a given place in the text when, according to the visibility rules, the declaration defines a possible meaning of this occurrence. The following two cases arise in determining the meaning of such a declaration:

— The visibility rules determine at most one possible meaning. In such a case, the visibility rules are sufficient to determine the declaration defining the meaning of the occurrence of the identifier, or in the absence of such a declaration, to determine that the occurrence is not legal at the given point.

— The visibility rules determine more than one possible meaning. In such a case, the occurrence of the identifier is legal at this point if and only if exactly one visible declaration is acceptable for the overloading rules in the given context or all visible declarations denote the same named entity.

The vcom-1581 error is telling us the first case is not met no declaration of the operator overload (designated by "/=") is visible that returns a boolean and has parameter base types of in_event_enum.

We could make the declarations of the package directly visible by use clause forbidden to you per your question, the reasoning not provided or we could make the declaration visible by selection (which runs up against the question requirement "The comparison should be done in an 'if-statement' to have short and readable code." A selected name can be used as a prefix for a function call but not an operator and using the designator as a function call may or may not meet the requirement. (It's only longer by prefix, the parentheses enclosing the parameters and the double quotations to designate the operator symbol.) We can already see you attempt to 'shorten' the if statement condition by using the use clause use work.all; to make package declarations found in the working library directly visible. Normally the use of such a such a use clause would be considered gauche by the advanced VHDL user, it actually requires you to scan back for the use clause to understand how visibility comes about.

So is there a way to make the implicit declaration for the predefined inequality operator directly visible (avoiding the prefix for the function call)?

VHDL supports the use of aliases (6.6 Alias declarations) where a non-object alias uses a signature in it's declaration to provide information to meet the first case of 12.3 mentioned above (every type declaration found in package SAWTOOTH_pkg, a reference to SAWTOOTH_pkg."/=" would be ambiguous falling afoul of the second case).

So our alias declaration can look like

architecture arch of SAWTOOTH_entity is
    alias "/=" is work.sawtooth_pkg."/="
        [work.sawtooth_pkg.in_event_enum,
         work.sawtooth_pkg.in_event_enum return boolean];
begin  
    process(p_clk)
    begin
        if rising_edge(p_clk) then              
            
            -- Throws error. Modelsim says 'no feasable entry for /='
            if (p_event_enum_next /= SAWTOOTH_pkg.event_enum_empty) then
                -- do something
            end if;
            

And can either be made as an architecture declarative item or because the inequality operator is only used in the process statement, in the process declarative part.

With the operator designator directly visible the secondary design entity (the architecture) analyzes (when the question provides a minimal, complete, and verifiable example, providing both package declarations).

There's also the concept of scope of declarations (12.2 Scope of declarations). If the prohibitions on the use of a use clause making all the declarations from package SAWTOOTH_pkg directly visible were due to the occurrence of identical declarations in package SAWTOOTH_INNER_pkg you could take advantage of an inner declarative region where no declarations from package SAWTOOTH_INNER_pkg are depended on to use a use clause to make declarations from package SAWTOOTH_pkg directly visible:

begin  
    process (p_clk)
        use work.SAWTOOTH_pkg.all;
    begin
        if rising_edge(p_clk) then              
            
            -- Throws error. Modelsim says 'no feasable entry for /='
            if p_event_enum_next /= event_enum_empty then
                -- do something
            end if;

and this also works here, which may or may not be the result of the example being overly minimal. A process statement is an inner declarative region, which allows any occurrence of a declaration also made visible by all use clauses who's scope includes this place to be hidden by a a declaration made visible by a use clause in the inner declarative region (see 12.4 Use clauses).

The question example code doesn't preclude partitioning visibility by the use of inner declarative regions by hiding declaration in an outer declarative region.

Relying on neither of these methods of making the declaration of the inequality operator overload directly visible would rely on selected names and doesn't meet the shortest readable code subjective criteria for the if statement:

architecture arch of SAWTOOTH_entity is
    -- alias "/=" is work.sawtooth_pkg."/="
    --     [work.sawtooth_pkg.in_event_enum,
    --    work.sawtooth_pkg.in_event_enum return boolean];
begin  
    process (p_clk)
        -- use work.sawtooth_pkg.all;
    begin
        if rising_edge(p_clk) then              
            
            -- Throws error. Modelsim says 'no feasable entry for /='
            -- if p_event_enum_next /= sawtooth_pkg.event_enum_empty then
            --     -- do something
            -- end if;
            if sawtooth_pkg."/="(p_event_enum_next, 
                                 sawtooth_pkg.event_enum_empty) then
                -- do something
            end if;
            
            -- Does the same but compiles without errors. But it is much longer.
            case p_event_enum_next is
                when  SAWTOOTH_pkg.event_enum_empty =>
                    -- do nothing
                when others =>  
                    -- do something
            end case;
        end if;
    end process;        
end architecture;
  • Related