1
\$\begingroup\$

I have the following assertion in my code:

assert (debug_decoded_opcode = types.AUIPC_OP) report "00000317 not AUIPC";

Vivado gives the error:

ERROR: [VRFC 10-724] found '0' definitions of operator "=", cannot determine exact overloaded matching definition for "="

But the type that the signal is, is an enum, defined here:

signal debug_decoded_opcode : types.opcode;

types.vhd definition:

type opcode is (INVALID, LUI, AUIPC_OP, JAL, JALR, BEQ, BNE, BLT, BGE, BLTU, BGEU, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI, ADD, SUB, inst_SLL, SLT, SLTU, inst_XOR, inst_SRL, inst_SRA, inst_OR, inst_AND, FENCE, FENCEI, EXALL, EBREAK, CSRRW, CSRRS, CSRRC, CSRRSI, CSRRCI, CSRRWI);

Is enum equality not defined in VHDL 2008?

It says here that "The equality and inequality operators are predefined for all types, and they return a boolean value" https://www.ics.uci.edu/~jmoorkan/vhdlref/operator.html Maybe Vivado thinks there's a type mistmatch? but that's not what should be seen It's worth noting that the same result is produced when I change = to /= There's only 10 results on google for this error, and they aren't helpful, as they deal with people mixing up std_logic_vectors and things like unsigned.

\$\endgroup\$
9
  • \$\begingroup\$ While your authority for the operator being predefined isn't a recognized authority it's correct. See IEEE Std 1076-2008 9.2.3 Relational operators "The equality and inequality operators (= and /=) are defined for all types other than file types and protected types." If you had provided a minimal, complete, and verifiable example your use clauses could be examined to determine if the "=" and /=" functions implementing those operators are directly visible. You can make those functions directly visible with aliases to the function declarations in the package. They'd require signatures. \$\endgroup\$ Dec 5, 2021 at 5:28
  • \$\begingroup\$ @user16145658 Why would it be the default that I have to alias the equality operator if it's already defined for my type? \$\endgroup\$
    – tuskiomi
    Dec 5, 2021 at 5:48
  • 2
    \$\begingroup\$ Do you have use work.types.all;? (Noting you used a selected name for the type). \$\endgroup\$ Dec 5, 2021 at 5:52
  • 1
    \$\begingroup\$ -2008 5.Types , 5.1` General, 2nd para "The set of operations of a type includes the explicitly declared subprograms that have a parameter or result of the type. ... These operations are each implicitly declared for a given type declaration immediately after the type declaration and before the next explicit declaration, if any." To understand the paragraph you may need to read earlier revisions (e.g. -2002 3. Types). From other language perspectives types aren't classes. \$\endgroup\$ Dec 5, 2021 at 6:04
  • 1
    \$\begingroup\$ @user_1818839 It had better not. A prefix for the subprogram "=" implementing the operator overload must be a package. Types are not classes, the "=" is not part of the type declaration. use work.types."="; makes all equality operator overloads found in package types directly visible. Operations of a type, not part of the type. An alias on the other hand would have a signature and make one specifically visible. \$\endgroup\$ Dec 5, 2021 at 22:36

1 Answer 1

1
\$\begingroup\$

A minimal, complete and verifiable example is provided to allow duplicating the problem in a VHDL simulator using the snippets provided in the question:

package types is
    type opcode is ( INVALID, LUI, AUIPC_OP, JAL, JALR, BEQ, BNE, BLT, BGE,
                     BLTU, BGEU, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI,
                     SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI, ADD,
                     SUB, inst_SLL, SLT, SLTU, inst_XOR, inst_SRL, inst_SRA,
                     inst_OR, inst_AND, FENCE, FENCEI, EXALL, EBREAK, CSRRW,
                     CSRRS, CSRRC, CSRRSI, CSRRCI, CSRRWI);
end package;

use work.all;
-- use work.types."=";

entity zero_definitions is
end entity;

architecture foo of zero_definitions is
    signal debug_decoded_opcode : types.opcode;
    -- alias "=" is work.types."=" [types.opcode, types.opcode return boolean];
begin
    assert (debug_decoded_opcode = types.AUIPC_OP) report "00000317 not AUIPC";
end architecture;

That produces the same error:

%: ghdl -a zero_definitions.vhdl
zero_definitions.vhdl:21:34:error: no function declarations for operator "="
    assert (debug_decoded_opcode = types.AUIPC_OP) report "00000317 not AUIPC";
                                 ^
ghdl:error: compilation error
%: 

The -a command to ghdl stands for analysis, commonly described as compiling but in VHDL has the added implication an error free design unit is inserted into the working library.

use work.all;

The snippets don't provide the design unit context clauses. That the selected name in the assertion statement wasn't an error says there was a use clause making the primary design unit names (here package types) directly visible.

The type name is made visible by selection. The reason for using a selected named might be to provide the package name here telling someone where to look for it's declaration. (Instead of potentially searching through declarations made directly visible by use clauses).

That leads to a problem. VHDL doesn't treat the type opcode as a class. (The only objects VHDL are of class constant, variable, signal and file.) VHDL is intended as a formal language used for formal verification and in the -1993 revision started formalizing implicit declarations, here the implicitly declared equality operator (IEEE Std 1076-2008 9.2.3 Relational operators).

Type as a class would have the declarations of implicitly declared operators as part of the type declaration that is not the case:

2008 5.Types , 5.1 General, 2nd paragraph:

The set of operations of a type includes the explicitly declared subprograms that have a parameter or result of the type. ... These operations are each implicitly declared for a given type declaration immediately after the type declaration and before the next explicit declaration, if any.

The implicit declarations immediately follow the declaration of the type and are not part of it's declaration and are not made directly visible.

There can be reasons to avoid direct visibility through use clauses. For declarations not used future code supporters should think twice before adding direct visibility, there can be reasons to avoid particular declarations. For simulation those can be to prevent running out of memory or avoiding limits in stripped down simulators for example.

Here there are three ways to make the the equality operator directly visible. Two are shown commented out in the code. A use clause making all "=" operators in package type directly visible and the alias which allows you to restrict to one specifically based on the function implementing the overloaded operator's signature. The third way is a use clause making all the declarations in the package directly visible.

There are also alternatives. A condition is an expression providing a Boolean value. The condition in an assertion evaluates FALSE for the remainder of an assertion statement to take effect (here the report statement). (Also note a condition does not require parentheses, it's syntactically unique.)

An overloaded operator can be called as the function implementing it:

    assert work.types."="(debug_decoded_opcode, types.AUIPC_OP)
        report "00000317 not AUIPC";

Note that implicitly declared functions parameter names are not visible and named association cannot be used in the parameter list. This is just cumbersome enough to prefer wider ranging use clauses or an alias declaration depending on a perceived need to block unused declarations from being directly visible, noting that an inner declarative region would override visibility made by use clause.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.