How to get simulation warning when comparing std_logic with 'X'?

点点圈 提交于 2021-01-28 00:32:04

问题


In order to catch more bugs in simulation, it is an advantage to get a warning if std_logic with 'X' is used in = compare.

When using the ieee.std_logic_1164 package, the std_logic compare function = does not warn about 'X' in either of the operands. So the ´if´ branch in the code below is taken when sl_i is '1', but the else branch is taken when sl_i is either of '0', 'X', etc.:

if sl_i = '1' then
  sl_o <= '1';
else  -- sl_i in "UX0ZWLH-"
  sl_o <= '0';
end if;

So for example an 'X' or 'U', due to use of some unknown or uninitialized value, is silently ignored during simulation. However, if a warning was given, it would improve the possibility of finding bugs in simulation, like when the ieee.numeric_std package warns about metavalue ('X' etc.) in compare with =.

? Is there any standard VHDL way to get warning for metavalues in std_logic at compare with = ?

One possibility, is to make a package where the implicit = for std_logic is redefined, and then use this package with .all so the = is replaced. Such package with may look like:

library ieee;
use ieee.std_logic_1164.std_logic;

package std_logic_warning is
  function "="(l, r : std_logic) return boolean;
end package;

library ieee;
use ieee.std_logic_1164.is_x;
use ieee.std_logic_1164;  -- For access to "=" using std_logic_1164."="

package body std_logic_warning is

  function "="(l, r : std_logic) return boolean is
  begin
    assert not (is_x(l) or is_x(r))
      report "std_logic_warning.""="": metavalue detected"
      severity WARNING;
    return std_logic_1164."="(l, r);
  end function;

end package body;

? Will such a redefine be VHDL standard compliant, and is it likely to work with the tools in general ?

As Jim Lewis points out with reference to ISAC IR2058 the idea of overriding the implicit = may not work in general for tool when using VHDL-2003. VHDL-2008 should fix this.


Note that above question and suggestion has been edited based on David Koontz previous comments.


回答1:


Depending on which language revision you are using, you may experience portability problems. I suggest you avoid them by using VHDL-2008, which removes a number of issues.

Prior to VHDL-2008, some tools did not allow explicit operators to overload implicit operators. Prior to VHDL-2008, tools interpreted the reference to "ieee.std_logic_1164.std_logic" differently. See ISAC IR2058 for a discussion: http://www.eda.org/isac/IRs-VHDL-2002/IR2058.txt. Even with the implementation of IR2058, my interpretation is that is_x will not be included in your reference to std_logic as only overloaded operators are included and not all functions - so if that works it is probably not portable between tools.

Hence, I would use VHDL-2008 and the following code. I replaced the reference to ieee.std_logic_1164."=" with one to ieee.numeric_std.std_match, as it is not clear to me if you can still reference an implicit operator once an explicit operator is visible to replace it - even if it is legal, I would expect this to be a fringe case that may break tools (make sure to report the bugs). Use of std_match also has the benefit of correctly handling an 'L' or 'H'.

library ieee;
use ieee.std_logic_1164.all;

package std_logic_warning is
  function "="(l, r : std_logic) return boolean;
end package;

package body std_logic_warning is

  function "="(l, r : std_logic) return boolean is
  begin
    assert not (is_x(l) or is_x(r))
      report "std_logic_warning.""="": metavalue detected"
      severity WARNING;
    return ieee.numeric_std.std_match(l, r);
  end function;

end package body;

If you don't like the behavior of std_match, you can use std_match as a template to create the functionality, however, I don't recommend this as synthesis tools may not like it.

While you could use the modified "=", as a counter suggestion, there are two sources of X, external from other designs and internal from uninitialized registers. I don't worry about uninitialized registers as I am rigorous about my resets. Hence, at the core level, I may (depending on my confidence of others or the testbench), use the assert statement directly on core inputs.

assert not is_x(core_input_1) 
  report "meta value detected on core_input_1" severity ERROR ; 



回答2:


There are a couple things wrong with this scenario.

There isn't an explicit std_logic_1164."=" defined. Equality and inequality operators are implicitly declared for all types.

IEEE Std 1076-1993 Section 3 Types, Para 2:

...The set of operations of a type includes the explicitly declared subprograms that have a parameter or result of the type. The remaining operations of a type are the basic operations and the predefined operators (see 7.2). 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 extended name should be ieee.std_logic_1164."=".

A relational operator in an expression is given as an operator symbol, so no extended name with left and right arguments. A function call to the equality operator function you've declared can be an extended name.

As long as the "=" operator being declared in the package declaration isn't used elsewhere in the package body you could use a context clause before the package body:

library ieee;
use ieee.std_logic_1164."=";

and

return l = r;

Also the equality operator is rigidly defined.

IEEE Std 1076-1993, 7.2.2 Relational operators, Para 4:

... Two scalar values of the same type are equal if and only if the values are the same.

So, no equality returns FALSE just because they are meta values. It's illegal to redefine what 'equal' means.

And ya, I know of one tool that will let you analyze this or something close, but it'll fail when using the operator. Even if it worked it would not be portable (while still being illegal, immoral and likely bad for the waistline).

This code crashes in ghdl, it was an attempt to avoid using the -fexplicit flag artificially changing the precedence of overloaded operators, which isn't -2008 standard compliant:

library ieee;
use ieee.std_logic_1164.std_logic;
use ieee.std_logic_1164.to_x01;
use ieee.std_logic_1164.is_x;

package std_logic_warning is
  function "="(l, r : std_logic) return boolean;
end package;

package body std_logic_warning is

    use ieee.std_logic_1164."=";

    function "="(l, r : std_logic) return boolean is
    begin
    if is_x(l) or is_x(r) then
      report "std_logic_warning.""="": metavalue detected, returning FALSE"
        severity WARNING;
      return FALSE;
    end if;
    return l = r; -- std_logic_1164."="(l, r);
    end function;

end package body;

library ieee;
use ieee.std_logic_1164.std_ulogic;
use ieee.std_logic_1164.std_logic;
-- use ieee.std_logic_1164.all;

use work.std_logic_warning.all;
entity warning_test is
end entity;

architecture foo of warning_test is
    signal a: std_logic;
    signal b: std_logic;
begin

UNLABELLED:
    process
    begin
        wait for 1 ns;
        a <= 'X';
        wait for 1 ns;
        b <= '1';
        wait for 1 ns;
        a <= '0';
        wait for 1 ns;
        b <= '0';
        wait;
    end process;

MONITOR:
    process (a,b)
    begin
        assert a = b 
            report "a = b " & "( " & std_logic'image(a)
                             & "=" & std_logic'image(b) & " )"
                severity NOTE;
    end process;

end architecture;

ghdl -r warning_test
std_logic_warning.vhdl:17:7:@0ms:(report warning):
std_logic_warning."=": metavalue detected, returning FALSE
std_logic_warning.vhdl:57:9:@0ms:(assertion note): a = b ( 'U'='U' )
std_logic_warning.vhdl:17:7:@1ns:(report warning):
std_logic_warning."=": metavalue detected, returning FALSE
std_logic_warning.vhdl:57:9:@1ns:(assertion note): a = b ( 'X'='U' )
std_logic_warning.vhdl:17:7:@2ns:(report warning):
std_logic_warning."=": metavalue detected, returning FALSE
std_logic_warning.vhdl:57:9:@2ns:(assertion note): a = b ( 'X'='1' )
ghdl: exec error

I'd suspect the issue has something to do with stack allocation, determined by trying concurrent assertions instead of the monitor process (which output more before crashing).

What it does show before bombing out is that 'U'='U' is a valid equality comparison according to the LRM and your `"=" operator say it isn't.

You could note your equality operator "=" is declared in the package declaration while the use clause is in effect in the package body. There should be no IR2058 conflict noted by Jim in his answer. That use clause (in the package body) isn't visible to where your overload function is visible.

To use your declaration in the test bench the order of use clauses was carefully crafted:

library ieee;
use ieee.std_logic_1164.std_ulogic;
use ieee.std_logic_1164.std_logic;
-- use ieee.std_logic_1164.all;

use work.std_logic_warning.all;

This also side steps the use of the Modelsim or ghdl overload rule evasion (-fexplicit as a command line argument in ghdl).

Unfortunately this demonstrates how complex VHDL is more than anything else

An acquaintance pointed out there was recursion in the function call so I proved that was the case by changing the function name (and changing the assertion condition expression).

ghdl -a test.vhdl
ghdl -e warning_test
ghdl -r warning_test
test.vhdl:16:7:@0ms:(report warning): std_logic_warning."=": metavalue detected, returning FALSE
test.vhdl:56:9:@0ms:(assertion note): a = b ( 'U'='U' )
test.vhdl:16:7:@1ns:(report warning): std_logic_warning."=": metavalue detected, returning FALSE
test.vhdl:56:9:@1ns:(assertion note): a = b ( 'X'='U' ) test.vhdl:16:7:@2ns:(report warning): std_logic_warning."=": metavalue detected, returning FALSE
test.vhdl:56:9:@2ns:(assertion note): a = b ( 'X'='1' )
test.vhdl:56:9:@3ns:(assertion note): a = b ( '0'='1' )

The recursion revolves around the function return expression "=".

commenting out the use clause in the package body yields:

-- use ieee.std_logic_1164."=";

ghdl -a test.vhdl
test.vhdl:20:14: no function declarations for operator "="
ghdl: compilation error

Which says the use clause is necessary, and that's expected:

IEEE Std 1076-1993 Section 3 Types, Para 2:

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

So is the issue overload resolution? (No it's visibility).

10.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 the introduction to Section 3).

We've first got to determine if both declarations of the function "=" are visible.

10.4 Use clauses, para 3:

Each selected name in a use clause identifies one or more declarations that will potentially become directly visible. If the suffix of the selected name is a simple name, character literal, or operator symbol, then the selected name identifies only the declaration(s) of that simple name, character literal, or operator symbol contained within the package or library denoted by the prefix of the selected name.

10.4 Use clauses, para 4:

For each use clause, there is a certain region of text called the scope of the use clause. This region starts immediately after the use clause. If a use clause is a declarative item of some declarative region, the scope of the clause extends to the end of the declarative region. If a use clause occurs within the context clause of a design unit, the scope of the use clause extends to the end of the declarative region associated with the design unit. The scope of a use clause may additionally extend into a configuration declaration(see 10.2 ).

And about here we note that this use clause is within the package body, and it's effect doesn't extend anywhere else. We also know that the declared function (originally also "=" is directly visible (i.e. not by selection) from the package declaration.

10.4 Use clauses, para 5:

In order to determine which declarations are made directly visible at a given place by use clauses, consider the set of declarations identified by all use clauses whose scopes enclose this place. Any declaration in this set is a potentially visible declaration. A potentially visible declaration is actually made directly visible except in the following two cases:

a. A potentially visible declaration is not made directly visible if the place considered is within the immediate scope of a homograph of the declaration.

b. Potentially visible declarations that have the same designator are not made directly visible unless each of them is either an enumeration literal specification or the declaration of a subprogram (either by a subprogram declaration or by an implicit declaration).

And There is a homograph, the function declaration in the package declaration.

From Appendix B Glossary:

B.117 homograph: A reflexive property of two declarations. Each of two declarations is said to be a homograph of the other if both declarations have the same identifier and overloading is allowed for at most one of the two. If overloading is allowed for both declarations, then each of the two is a homograph of the other if they have the same identifier, operator symbol, or character literal, as well as the same parameter and result type profile.(§ 1.3.1 , § 10.3 )

B.119 immediate scope: A property of a declaration with respect to the declarative region within which the declaration immediately occurs. The immediate scope of the declaration extends from the beginning of the declaration to the end of the declarative region. (§ 10.2 )

So the issue revolves around immediate scope in 10.4, a. And b tells us that if both are subprogram declarations they are both visible inside the subprogram body.

And we get down to the NOTES:

1--These rules guarantee that a declaration that is made directly visible by a use clause cannot hide an otherwise directly visible declaration.

The use clause declaration that would become potentially visible is with in the immediate scope of the subprogram declaration found in the package declaration.

And if it weren't:

10.5 The context of overload resolution, para 3:

At such a place, all visible declarations are considered. The occurrence is only legal if there is exactly one interpretation of each constituent of the innermost complete context; a complete context is either a declaration, a specification, or a statement.

Not being legal is synonymous with error. We'd have gotten an error.

So the moral here is that VHDL can be complex especially when you're trying to game it. And what I was trying to do resulted in legal code that didn't do what was intended, and didn't generate and error until out of stack space at run time, a catch-22.

The displayed code can be made to function with the following change:

  1. Remove the use clause in the package body:

    -- use ieee.std_logic_1164."=";

  2. Restore EquipDev's return statement:

    return l = r; -- std_logic_1164."="(l, r);  
    

becomes

    return std_logic_1164."="(l, r);  

again. (Undoing my error).

This gives:

ghdl -a std_logic_warning.vhdl
ghdl -e warning_test
ghdl -r warning_test
std_logic_warning.vhdl:17:7:@0ms:(report warning): std_logic_warning."=": metavalue detected, returning FALSE
std_logic_warning.vhdl:58:9:@0ms:(assertion note): a = b ( 'U'='U' )
std_logic_warning.vhdl:17:7:@1ns:(report warning): std_logic_warning."=": metavalue detected, returning FALSE
std_logic_warning.vhdl:58:9:@1ns:(assertion note): a = b ( 'X'='U' )
std_logic_warning.vhdl:17:7:@2ns:(report warning): std_logic_warning."=": metavalue detected, returning FALSE
std_logic_warning.vhdl:58:9:@2ns:(assertion note): a = b ( 'X'='1' )
std_logic_warning.vhdl:58:9:@3ns:(assertion note): a = b ( '0'='1' )

Which appears to be the correct result, because when b is assigned to '0' at 4 ns the assertion test won't trigger for either the function or monitor process.

Recap

Is it possible to replace the relational operator "=" for std_logic?

Yes, But it may not be practical. Notice that there are use clauses for all the package std_logic_1164 names used except "=". In -2008 you can declare contexts where you could construct such a context clause once and invoke it. Or otherwise you could fill the package declaration with use clauses.

And the entire point of this exercise was to show that the adopted definition of "=" wasn't valid for meta values and is not standard compliant. (The 7.2.2 para 4 quote above).

And as Jim points out assertion test monitors can take the place of any usefulness redefining "=" may have.



来源:https://stackoverflow.com/questions/25737877/how-to-get-simulation-warning-when-comparing-std-logic-with-x

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!