Search code examples
vhdl

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


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.


Solution

  • 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 ;