Question

I have two designs:

library ieee;
use ieee.std_logic_1164.all;

entity eq_test1 is

  port (a,b : IN std_logic_vector (1 downto 0);
        o   : OUT std_logic); 
end eq_test1;

architecture strange_behavior of eq_test1 is
begin  
    P: process (a,b)
    begin
        if a = b then o <= '1';
        else o <= '0';
        end if;
    end process P;
end strange_behavior;

Forcing in Modelsim to a have "00" and b have "0L" shows that o becomes '0'. So L is NOT interpreted as 0, "00" = "0L" is false. Ok.

But when I take the same design and add

use ieee.std_logic_unsigned.all;

to the list, the behavior is different. Then "00" = "0L" returns true, so L IS the same as 0 (0 becomes '1'). With that unsigned packages included, even "0X" = "0Z" returns true.

Can anyone explain why?

Was it helpful?

Solution

Adding use ieee.std_logic_unsigned.all; is like opening Pandora's box to Synopsys libraries. After a deep dive shown below, the conclusion is that the std_logic_unsigned package in this case makes the values '0' and 'L' equal through an table.

The call starts when the "=" operator is redefined to:

function "="(L: STD_LOGIC_VECTOR; R: STD_LOGIC_VECTOR) return BOOLEAN is
begin
    return   UNSIGNED(L) = UNSIGNED(R);
end;

That is however just the beginning, since std_logic_unsigned includes use IEEE.std_logic_arith.all;, which defined the type:

type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;

The compare of UNSIGNED in "=" thus result in call of std_logic_arith function:

function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is
    -- synopsys subpgm_id 341
    constant length: INTEGER := max(L'length, R'length);
begin
    return bitwise_eql( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ),
            STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) );
end;

In this function the CONV_UNSIGNED is interesting:

function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED is
    constant msb: INTEGER := min(ARG'length, SIZE) - 1;
    subtype rtype is UNSIGNED (SIZE-1 downto 0);
    variable new_bounds: UNSIGNED (ARG'length-1 downto 0);
    variable result: rtype;
    -- synopsys built_in SYN_ZERO_EXTEND
    -- synopsys subpgm_id 372
begin
    -- synopsys synthesis_off
    new_bounds := MAKE_BINARY(ARG);
    if (new_bounds(0) = 'X') then
        result := rtype'(others => 'X');
        return result;
    end if;
    result := rtype'(others => '0');
    result(msb downto 0) := new_bounds(msb downto 0);
    return result;
    -- synopsys synthesis_on
end;

Now we are getting close, since the above calls:

function MAKE_BINARY(A : UNSIGNED) return UNSIGNED is
    -- synopsys built_in SYN_FEED_THRU
    variable one_bit : STD_ULOGIC;
    variable result : UNSIGNED (A'range);
begin
    -- synopsys synthesis_off
        for i in A'range loop
            if (IS_X(A(i))) then
                assert false
                report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)."
                severity warning;
                result := (others => 'X');
                return result;
            end if;
            result(i) := tbl_BINARY(A(i));
        end loop;
        return result;
    -- synopsys synthesis_on
end;

And in here we have the reason for 'L' being equal to '0', since the tbl_BINARY is a constant defined as:

type tbl_type is array (STD_ULOGIC) of STD_ULOGIC;
constant tbl_BINARY : tbl_type :=
    ('X', 'X', '0', '1', 'X', 'X', '0', '1', 'X');

To understand this mapping, it is useful to align with the definition of values in STD_ULOGIC:

std_ulogic: ( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-');

tbl_BINARY: ( 'X', 'X', '0', '1', 'X', 'X', '0', '1', 'X');

This shows that after conversion through tbl_BINARY then the equivalent groups are ('U', 'X', 'Z', 'W', '-'), ('0', 'L'), and ('1', 'H').

A closing comment is that even through the std_logic_unsigned package resides in a library called "ieee", the package is not IEEE standard like VHDL, but a Synopsys package. The package, and the other related Synopsys packages, have been around for a while and are widely used.

However, you may consider using the IEEE standard package numeric_std instead.

OTHER TIPS

Look at the definition of std_logic_unsigned. It replaces the original definition of "=" as follows

function "="(L: STD_LOGIC_VECTOR; R: STD_LOGIC_VECTOR) return BOOLEAN is
begin
    return   UNSIGNED(L) = UNSIGNED(R);
end;

and as the type UNSIGNED is an integer type which does not know the literals 'h', and 'l', it is accordingly resolved to an integer value, and thus 'l' becomes '0', the semantic equivalent in UNSIGNED

The short answer is that std_logic_unsigned, as well as its intended replacement numeric_std_unsigned, properly handle 'H' and 'L' as '1' and '0'.

The "unsigned" packages treat std_logic_unsigned as an unsigned numeric value. Here are some benefits:

  • Proper handling of 'H' and 'L'
  • Numeric handling of inputs, especially when they are different sizes
  • Support mixing std_logic_vector with integers (Addr = 0) rather than (Addr = "0000")
  • Overloads >, >=, <, <= so they do math ordering rather than dictionary ordering. Important if sizes are different.

Until vendors (synthesis) implement the VHDL-2008 matching relational operators, ?= ?/= ?> ?>= ?< and ?<=, I recommend that you use one of these packages. When they implement the matching relationals, I recommend using them in new designs.

For more on the VHDL-2008 features, see http://www.synthworks.com/blog/vhdl-standards/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top