Behavior of VHDL comparison operator with integer argument

Discussion in 'VHDL' started by Josh, Mar 15, 2012.

  1. Josh

    Josh Guest

    Consider the following example, compiling with VHDL-2008 support.

    library ieee;
    use ieee.numeric_std.all;
    ....
    if (to_unsigned(0, 3) <= 8) then
    StatementsA
    end if;
    if (to_unsigned(1, 3) <= 8) then
    StatementsB
    end if;

    In my experience, StatementsA get executed, but not StatementsB.
    Logically I would expect that both statements get executed since 0 and
    1 are both less than 8. My theory is that 8 is interpreted as a 3 bit
    number, and the top bit is being lost, creating the value of 0.

    Questions
    1. Is this the intended behavior of VHDL?
    2. What is the logic/reasoning behind this? Why wouldn't the size of
    the comparison automatically be resized to the required size of the
    integer?
    3. What is a logical & safe practice to encourage in order to avoid
    situations like this?
    Josh, Mar 15, 2012
    #1
    1. Advertising

  2. On Thu, 15 Mar 2012 09:26:44 -0700, Josh wrote:

    > Consider the following example, compiling with VHDL-2008 support.
    >
    > library ieee;
    > use ieee.numeric_std.all;
    > ...
    > if (to_unsigned(0, 3) <= 8) then
    > StatementsA
    > end if;
    > if (to_unsigned(1, 3) <= 8) then
    > StatementsB
    > end if;


    When I see
    if (some cond) then
    I suspect someone who learned C first. Those parentheses are unnecessary
    (but harmless).

    > My theory is that 8 is interpreted as a 3 bit
    > number, and the top bit is being lost, creating the value of 0.


    Yes.

    > Questions
    > 1. Is this the intended behavior of VHDL?


    The VHDL language is not responsible for this; the library you are using
    (numeric_std) is. There is nothing hidden there, you can answer the
    question yourself by looking at the source for the <= function with
    (unsigned, int) arguments.

    >2. What is the logic/reasoning
    > behind this? Why wouldn't the size of the comparison automatically be
    > resized to the required size of the integer?


    Automatically changing word sizes or automatic type conversions increase
    the scope for unexpected behaviour. That certainly shouldn't be a
    property of the language! It should do what you write according to well
    defined rules.

    In this case, the LHS is an Unsigned with a well defined size. Maybe you
    had good reasons for wanting a 3-bit comparator. Presumably you did,
    since you made the Unsigned 3 bits wide. It shouldn't create hardware you
    didn't ask for!

    Instead there should be scope for adding such behaviour where you want it
    intentionally, perhaps through a library of functions, like numeric_std,
    but with different behaviour. I believe that library would turn out to be
    much less generally useful, but YMMV.

    > 3. What is a logical & safe practice to encourage in order to avoid
    > situations like this?


    Completely avoid? I don't know of one.
    Good practice? A few things can help.

    Sanitize inputs - Check assumptions. Presuming the above example was an
    unfortunate meeting of quantities from different sources (e.g. a=3 in
    your design, b=8 was supplied as an input)
    assert b >= 0 and b < 2**a report "Input data b out of range"
    severity failure;
    Now you can be sure that the input is valid.

    Use the type system, don't fight it...
    -- in a package somewhere...
    constant Word_width : integer := 3;
    subtype Word_type is unsigned (Word_width - 1 downto 0);
    subtype Num_type is natural range 0 to 2**Word_width - 1;
    -- in your design
    signal a : Word_type := to_unsigned(0,Word_width);
    signal b : Num_type := 8; -- compiler catches the error here
    --before you even start simulating!
    if a <= b then ...
    Writing like this, with everything relevant derived from Word_width, is a
    bit more work in a small design. But probably less work, by the time you
    have eliminated 100 occurrences of "std_logic_vector(31 downto 0)"
    And when you realise you really needed that 4th bit, just change
    Word_width and everything else is still correct.

    Use procedures and functions. They can be local to a specific process or
    even to another procedure. Or hidden in a package. You wrote the same
    comparison twice, giving 2 identical pieces of complex behaviour to
    modify.
    function OK(natural a; natural b) return boolean is
    begin
    return to_unsigned(a, 3) <= b;
    end function OK;
    if OK(a,b) then ...
    Now when you have to change the behaviour (perhaps testing b for valid
    range with an assert) you only have to change it once.

    And others, no doubt.
    - Brian
    Brian Drummond, Mar 15, 2012
    #2
    1. Advertising

  3. Josh

    KJ Guest

    On Thursday, March 15, 2012 12:26:44 PM UTC-4, Josh wrote:
    > Consider the following example, compiling with VHDL-2008 support.
    >
    > library ieee;
    > use ieee.numeric_std.all;
    > ...
    > if (to_unsigned(0, 3) <= 8) then
    > StatementsA
    > end if;
    > if (to_unsigned(1, 3) <= 8) then
    > StatementsB
    > end if;
    >
    > In my experience, StatementsA get executed, but not StatementsB.


    You might want to re-check this experience. The full code that I have posted at the end simply reports out when the condition branches are taken and produces the following result which shows that both branches are taken...which contradicts your statement.

    Results obtained using Modelsim 6.4 (which does not support -2008...I guessreally should upgrade to something more recent here at home I suppose).

    # vsim tb_unsigned
    # Loading std.standard
    # Loading ieee.std_logic_1164(body)
    # Loading ieee.numeric_std(body)
    # Loading work.tb_unsigned(rtl)
    # ** Note: 0 <= 8
    # Time: 0 ns Iteration: 0 Instance: /tb_unsigned
    # ** Note: 1 <= 8
    # Time: 0 ns Iteration: 0 Instance: /tb_unsigned

    > Logically I would expect that both statements get executed since 0 and
    > 1 are both less than 8.


    That would be what I would expect.

    > My theory is that 8 is interpreted as a 3 bit
    > number, and the top bit is being lost, creating the value of 0.
    >


    If you run my code below and get different results than what I posted here it suggests one of the following theories (listed from what I would rank asleast to most probable):

    - A new definition of "<=" in the numeric_std library came out with VHDL-2008 and my code, when compiled with VHDL-2008, behaves differently.
    - Your simulator has a bug, get a better one.
    - You are mistaken. Perhaps your stripped down example didn't correctly represent what you had experienced leading to the incorrect theory. If so, you should go back to your original code that seemed to produce the unexpected result and analyze that (or post it here for review).

    Kevin Jennings

    ---- START OF CODE ----
    library ieee;
    use ieee.numeric_std.all;
    entity tb_unsigned is
    end tb_unsigned;
    architecture rtl of tb_unsigned is
    begin
    process
    begin
    if (to_unsigned(0, 3) <= 8) then
    report "0 <= 8";
    end if;
    if (to_unsigned(1, 3) <= 8) then
    report "1 <= 8";
    end if;
    wait;
    end process;
    end rtl;
    ---- END OF CODE ----
    KJ, Mar 16, 2012
    #3
  4. KJ wrote:

    > If you run my code below and get different results than what I posted here
    > it suggests one of the following theories (listed from what I would rank
    > as least to most probable):
    >
    > - A new definition of "<=" in the numeric_std library came out with
    > VHDL-2008 and my code, when compiled with VHDL-2008, behaves differently.


    I don't have access to the source of the 2008 version of numeric_std. I just
    tried your example in ModelSim 10.1, both in 1993 and 2008 mode. No
    difference there. I see the same results as you see. Pfew.

    --
    Paul Uiterlinden
    www.aimvalley.nl
    Paul Uiterlinden, Mar 16, 2012
    #4
  5. Josh

    Guest

    Too cool. Good test case. This is not a VHDL-2008 change.

    The following is from, IEEE Std 1076.3-1997 (Numeric_std) standard, sectionA.3.2:
    "When a relation operator compares a SIGNED or UNSIGNED argument value withan INTEGER or NATURAL value, the function has the effect of converting theSIGNED or UNSIGNED argument to its equivalent universal integer value and then doing the corresponding comparison of integer values." ...

    I note that std_logic_arith does not do it correctly - or does it the way the OP speculated.

    Best Regards,
    Jim
    , Apr 4, 2012
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. afd
    Replies:
    1
    Views:
    8,264
    Colin Paul Gloster
    Mar 23, 2007
  2. fons
    Replies:
    0
    Views:
    742
  3. Replies:
    4
    Views:
    526
  4. Brian Mitchell
    Replies:
    77
    Views:
    725
    Austin Ziegler
    Nov 10, 2005
  5. Deepu
    Replies:
    1
    Views:
    217
    ccc31807
    Feb 7, 2011
Loading...

Share This Page