Search code examples
vhdl

Why does `to_unsigned(0, 4) >= -1` evaluate to `FALSE` at runtime?


Using the test code below:

library ieee;
use ieee.numeric_std.all;
architecture sim of tb is
begin
  process is
  begin
    for c in -1 to 1 loop
      assert to_unsigned(0, 4) >= c report "Fails: 0 >= " & integer'image(c) severity NOTE;
    end loop;
    wait;
  end process;
end architecture;

Shows this output using ModelSim 10.5a:

Loading work.tb(sim)
** Note: Fails: 0 >= -1
   Time: 0 ns  Iteration: 0  Instance: /tb
** Note: Fails: 0 >= 1
   Time: 0 ns  Iteration: 0  Instance: /tb

So effectively to_unsigned(0, 4) >= -1 evaluated to FALSE, and this is not reported at run-time when I used the for loop. Why is this?

Note that if I write to_unsigned(0, 4) >= -1 without using the for loop for getting the -1 value at runtime, then the ModelSim compiler will report that "Value -1 (of type std.STANDARD.NATURAL) is out of range 0 to 2147483647.".


Solution

  • TL/DR : Please ask this wherever you get tech support for Modelsim, and update the question with their response.

    A quick rewrite and a cross-check with the (generally pretty strict and accurate) ghdl simulator:

    library ieee;
    use ieee.numeric_std.all;
    
    entity tb is
    end tb;
    
    architecture sim of tb is
    begin
      process is
      begin
        for c in -1 to 1 loop
          assert to_unsigned(0, 4) 
           >= 
           c 
           report "Fails: 0 >= " & integer'image(c) severity NOTE;
        end loop;
        wait;
      end process;
    end architecture;
    

    ghdl -r tb
    ./tb:error: bound check failure at tb.vhd:14
    ./tb:error: simulation failed

    shows a bound check error precisely at the evaluation of c which is not within the legal range for an Unsigned or Natural.

    So the question is, did either ghdl or Modelsim pick an inappropriate >= operator?

    The source for numeric_std shows only two >= operator definitions where the first argument is an unsigned. (This file is "copyright 2008" so for the VHDL-2008 standard.)

      -- Id: C.19
      function ">=" (L, R : UNRESOLVED_UNSIGNED) return BOOLEAN;
      -- Result subtype: BOOLEAN
      -- Result: Computes "L >= R" where L and R are UNRESOLVED_UNSIGNED vectors possibly
      --         of different lengths.
    
      -- Id: C.23
      function ">=" (L : UNRESOLVED_UNSIGNED; R : NATURAL) return BOOLEAN;
      -- Result subtype: BOOLEAN
      -- Result: Computes "L >= R" where L is an UNRESOLVED_UNSIGNED vector and
      --         R is a nonnegative INTEGER.
    

    Neither of which permits a signed quantity (Signed or Integer) as the second argument.

    So, you might want to look at the source for numeric_std in your installation to see if it's a different revision, with a >= operator permitting mixed Unsigned and Integer datatypes. I doubt it exists : it would be dangerously prone to just this sort of misunderstanding.

    If there is no such operator, Modelsim is being permissive here; are there compilation options to turn on stricter compliance?

    And if you think this is unnecessarily pedantic, consider this:

    c := -1;
    if to_unsigned(0, 4) >= c then
        emergency_stop;
    end if;