Search code examples
vhdl

Complex if statements are not simulatable


I intend to summerize many if statements into one (in VHDL), like:

from this working snippet

if config = "0001" and counter = 40 then
    res <= '1';
elsif config = "0010" and counter = 52 then
    res <= '1';
else
    res <= '0';
end if;

to this unworking snippet

if config = "0001" and counter = 40 or config = "0010" and counter = 52 then
    res <= '1';
else
    res <= '0';
end if;

Vivado tells me "there is a problem near 'or'", but I don't see one.

Will this be better (more robust) on hardware implementation?

Thank you


Solution

  • Provide a Minimal, Complete, and Verifiable example, e.g.:

    library ieee;
    use ieee.std_logic_1164.all;
    
    entity unworking_snippet is
    end entity;
    
    architecture snippet of unworking_snippet is
        signal config:  bit_vector (3 downto 0) := "0001";
        signal counter: integer range 0 to 52 := 40;
        signal res:  std_logic;
    begin
    
        process  (config, counter)
        begin
    
            if config = "0001" and counter = 40 or config = "0010" and counter = 52 then
                res <= '1';
            else
                res <= '0';
            end if;
        end process;
    end architecture;
    

    Which will produce an error message pointing to your if statement. ghdl for example points to two errors in the if statement:

    ghdl -a unworking_snippet.vhdl
    unworking_snippet.vhdl:16:45:error: only one type of logical operators may be used to combine relation
    unworking_snippet.vhdl:16:64:error: only one type of logical operators may be used to combine relation
    ghdl:error: compilation error
    

    where line 16 contains the if statement condition, character 45 is the 'o' in or and character 64 is the 'a' in the second and.

    These are hard coded into VHDL's expression parsing described in the Baccus Naur Form (BNF) in IEEE Std 1076-2008 9. Expressions, 9.1 General:

    An expression is a formula that defines the computation of a value.
    expression ::=
          condition_operator primary
        | logical_expression
    
    logical_expression ::=
          relation { and relation }
        | relation { or relation }
        | relation { xor relation 
        | relation [ nand relation ]
        | relation [ nor relation ]
        | relation { xnor relation }
    
    relation ::=
        shift_expression [ relational_operator shift_expression ]
    
    shift_expression ::=
        simple_expression [ shift_operator simple_expression ]
    
    simple_expression ::=
        [ sign ] term { adding_operator term }
    
    term ::=  
        factor { multiplying_operator factor }
    
    factor ::=
          primary [ ** primary ]  
        | abs primary
        | not primary
        | logical_operator primary  
    
    primary ::=  
          name
        | literal
        | aggregate
        | function_call
        | qualified_expression
        | type_conversion
        | allocator
        | ( expression )
    

    where you'll find by hand parsing the if statement condition the only way to have two different logical operators as relations in another logical operator is if the primary is contained in parentheses:

            if (config = "0001" and counter = 40) or (config = "0010" and counter = 52) then
    

    The path through the BNF is relation => shift_expression => simple_expression => term => logical_operator primary, primary => (expression). This occurs for both sides of the or operator.

    Substituting the updated if statement condition allows the MCVe to analyze (compile) successfully.

    While superfluous parentheses are often introduced by those with programming backgrounds parentheses are required for different logical operators in the same expression (config = "0001" and counter = 40 or config = "0010" and counter = 52 in the original 'unworking' snippet).

    Because it's a syntax analysis requirement in the BNF there can be no difference between simulation and post synthesis functionality.

    VHDL treats logical operators with the same precedence:

    9.2 Operators

    9.2.1 General

    The operators that may be used in expressions are defined as follows. Each operator belongs to a class of operators, all of which have the same precedence level; the classes of operators are listed in order of increasing precedence.

    ...
    logical_operator ::= and | or | nand | nor | xor | xnor

    relational_operator ::= = | /= | < | <= | > | >= | ?= | ?/= | ?< | ?<= | ?> | ?>=
    ...

    Operators of higher precedence are associated with their operands before operators of lower precedence. Where the language allows a sequence of operators, operators with the same precedence level are associated with their operands in textual order, from left to right. The precedence of an operator is fixed and cannot be changed by the user, but parentheses can be used to control the association of operators and operands.

    In general, operands in an expression are evaluated before being associated with operators. For certain operations, however, the right-hand operand is evaluated if and only if the left-hand operand has a certain value. These operations are called short-circuit operations. The binary logical operations and, or, nand, and nor defined for operands of types BIT and BOOLEAN are all short-circuit operations; furthermore, these are the only short-circuit operations.

    Here the language doesn't allow the sequence of operators based on the lack of precedence between logical operators.

    9.1 paragraphs 3 & 4

    Each primary has a value and a type. The only names allowed as primaries are attributes that yield values and names denoting objects or values. In the case of names denoting objects other than objects of file types or protected types, the value of the primary is the value of the object. In the case of names denoting either file objects or objects of protected types, the value of the primary is the entity denoted by the name.

    The type of an expression depends only upon the types of its operands and on the operators applied; for an overloaded operand or operator, the determination of the operand type, or the identification of the overloaded operator, depends on the context (see 12.5). For each predefined operator, the operand and result types are given in the following subclause.

    The following subclause is 9.2 and the type of expressions resulting from relational operators is type BOOLEAN (9.2.3 Relational operators).

    The BNF restriction requiring parentheses avoids the complexity of evaluating an entire expression repetitively to determine it's tree structure without superimposing logical operator precedence on George Boole's algebra, noting expressions can also produced values of arbitrary types. There are no restrictions on the size or complexity of expressions and the parentheses imply sub-trees.