Search code examples
vhdlaliasenumerationenumerated-typesghdl

What is the correct syntax for an alias to a character literal in an enumeration?


For educational purposes, I'm trying to declare an alias to an enumeration value that is a character literal. In the example below, I'm trying to create the alias bit_one for the value '1' in enumeration type bit (declared in std.standard).

I am puzzled as to why the first form below is rejected by two compilers (GHDL 0.29.1 and Quartus II 13.01), while the second form is accepted by the same two, plus ModelSim and ActiveHDL. Hence the question: is it illegal to declare this alias as in the commented-out line below?

entity character_literal_alias is
end;

architecture rtl of character_literal_alias is
    --alias bit_one is '1'[return bit];             -- Doesn't work in GHDL or Quartus
    alias bit_one is std.standard.'1'[return bit];  -- Works with ModelSim, ActiveHDL, GHDL, and Quartus

    alias append is append_mode[return file_open_kind];  -- Works with the whole bunch
begin
end;

I'm using the VHDL-2002 switch in GHDL and VHDL-2008 in the other tools.

If I were to speculate a little, in the VHDL-2008 LRM all the examples are written in the form:

-- implicit aliases ...
-- alias '0' is STD.STANDARD.'0' [return STD.STANDARD.BIT];
-- alias '1' is STD.STANDARD.'1' [return STD.STANDARD.BIT];

But those are implicit declarations, and even if the examples use selected names, it doesn't mean that every alias should be declared this way, IMO. So maybe some vendors misinterpreted the standard?


Solution

  • This actually relates to which VHDL tool is compliant to which standard revision

    One of the two sets of VHDL analyzers is not compliant with the standard, but which standard revision?

    ghdl says:

    charlitalias.vhdl:5:22: identifier expected here
    ghdl: compilation error
    

    While not a particularly enlightening error message ghdl is by default IEEE Std 1076-1993 compliant by and large. ghdl defaults to --std=93c, which is -1993 compliant with relaxed rules relating to later standard changes. There are no standard changes affecting this question before -2008 revision, so --std=02 should have no bearing.

    The following extracts are from the -1993 standard unless otherwise noted. Also note the EBNF found in the standard body is normative specifying syntax, while the text provides semantic specification.

    4.3.3 Alias declarations

    An alias declaration declares an alternate name for an existing named entity.

    alias_declaration ::=  
         alias alias_designator [ : subtype_indication ] is name [ signature ] ;
    

    Where:

    name ::=                                                    [§ 6.1]  
          simple_name  
        | operator_symbol  
        | selected_name
        | indexed_name  
        | slice_name  
        | attribute_name  
    

    The EBNF for name is updated in the -2008 standard, 8.1:

    name ::= 
        simple_name
      | operator_symbol 
      | character_literal 
      | selected_name
      | indexed_name
      | slice_name
      | attribute_name 
      | external_name
    

    In -2008 it includes a character literal, which is a lexical element.

    This makes the example:

    alias bit_one is '1'[return bit];  
    

    legal in -2008. A character literal can be treated as a name in the alias_declaration.

    The example that worked universally specifies a selected name (an expanded name) with a suffix that is a character literal:

    alias bit_one is std.standard.'1'[return bit];
    

    The reason why a selected name works for a character literal is found in 6.3 Selected names, para 9:

    An expanded name denotes a named entity declared in a package if the prefix denotes the package and the suffix is the simple name, character literal, or operator symbol of a named entity whose declaration occurs immediately within that package.

    Further that suffix is treated as if it were the name of a function:

    3.1.1 Enumeration types, para 4:

    The identifiers and character literals listed by an enumeration type definition must be distinct within the enumeration type definition. Each enumeration literal is the declaration of the corresponding enumeration literal; for the purpose of determining the parameter and result type profile of an enumeration literal, this declaration is equivalent to the declaration of a parameterless function whose designator is the same as the enumeration literal and whose result type is the same as the enumeration type.

    There's a bit of clarification in the -2008 standard, 5.2.2.1:

    ...,this declaration is equivalent to the declaration of a parameterless function whose designator is the same as the enumeration literal and whose result type is the same as the enumeration type; the declaration is, nonetheless, a declaration of a literal, not of a function.

    The reason why this is of interest is because functions are named, operators are functions and operator symbols in double quotes are allowed as function names. There isn't anything allowing character literals as function names however.

    Aliases are classified by whether or not they refer to objects (signals, constants, variables, files, named objects) or other named entities.

    A nonobject alias (-1993 4.3.3.2, -2008 6.6.3) requires a signature for a character literal. The signature supplies a return type like a function, enabling overload resolution for the character literal, which by itself is ambiguous. Knowing the type is necessary to disambiguate the positional value of an enumeration literal. Take type BIT and type std_ulogic for instance. Both have '1' enumeration literals, yet the positional value (a natural) is 1 for BIT ('0', '1') and 3 for std_ulogic ('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'). Evaluating expressions requires the positional value.

    Back to ghdl/-1993:

    So a selected name worked. A character literal by itself doesn't fit anywhere is in the -1993 expansion of name, but does for -2008.

    If Modelsim and ActiveHDL were strictly -1993 compliant, they'd be in error. It's apparent in retrospect they are -2008 compliant which explains the difference in accepted syntax.

    If they had been passed a flag to insure -1993 compliance Modelsim and ActiveHDL would have appeared to be treating the enumeration literal declaration as a function name had they accepted the alias declaration.

    Prior to -2008 you couldn't treat a character literal as a name. You could always treat named enumeration literals as a name. You could imagine this disparity is why character_literal was added to name in -2008. Now all enumeration literals are 'named'.

    So we get to the question:

    But those are implicit declarations, and even if the examples use selected names, it doesn't mean that every alias should be declared this way, IMO. So maybe some vendors misinterpreted the standard?

    The implicit alias declarations are syntactically and semantically correct representations found in the section on nonobject alias. They happen to be both compliant to both the -1993 and -2008 standards. Your example that fails in ghdl and passes in Modelsim isn't.

    To maintain portability across revisions, use a selected name. You might gather adoption of new VHDL revisions lags significantly.

    That's a critical mass issue, solved by first Jerry Kaczynski at Aldec driving ActiveHDL followed by Modelsim. The two open source implementations being actively developed I'm aware of are progressing toward -2008 compliance too.