Search code examples
vhdl

VHDL permissive conversion from unsigned to std_logic_vector in conditional statement


I was wondering why I do not get a warning / error when a bad conversion from unsigned to std_logic_vector is performed inside a conditional statement

--Naturally wrong when input length is not 4, will always be false
if  input = std_logic_vector(to_unsigned(pattern_int,4)) then 

whereas it is detected in an usual other vector affectation.

-- for this you will get a warning, e.g vector truncated
temp <= std_logic_vector(to_unsigned(pattern_int,4));

Simplified code ( MVCE ) with working syntax is like following:

Link to EDA PlayGround (contains both code of "dut" and its testbench)

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity vector_test is
port (  CLOCK   : in std_logic;
        RESET   : in std_logic;
        INPUT   : in std_logic_vector(7 downto 0);
        OUTPUT  : out std_logic);
end entity;

architecture rtl of vector_test is
    constant pattern_int : integer := 16#80#;
    --signal temp : std_logic_vector(7 downto 0);
    begin
        process(CLOCK,RESET,INPUT)
            begin
                -- for this you will get a warning, e.g vector truncated
                --temp <= std_logic_vector(to_unsigned(pattern_int,4));
                if RESET = '1' then
                    output <= '0';
                elsif rising_edge(CLOCK) then 
                    --Naturally wrong, output will alway be 0
                    --if  input = std_logic_vector(to_unsigned(pattern_int,4)) then 
                    if  input = std_logic_vector(to_unsigned(pattern_int,input'length)) then 
                        output <= '1';
                    else
                        output <= '0';
                    end if;
                end if;
        end process;
end architecture;

The testbench so that the question is really complete ( it was already available on EDA Playground but unfortunately you have to register in order to play it ...)

library IEEE;
use IEEE.std_logic_1164.all;

entity test is
end entity;

architecture beh of test is

signal comparison_output : std_logic;
signal input_stim : std_logic_vector(7 downto 0) := x"33";
signal clock : std_logic := '0';
signal reset : std_logic := '1';
begin

vt: entity work.vector_test
port map (  CLOCK => clock,
            RESET => reset,
            input => input_stim,
            output => comparison_output );


clocking: process(clock)
begin
    clock <= not clock after 16.7 ns;
end process;

stimuli: process
begin
    reset <= '0' after 20 ns;
    input_stim <= x"36" after 100 ns;
    input_stim <= x"80" after 100 ns;
 wait;
end process;

end architecture;

Solution

  • I was wondering why I do not get a warning / error when a bad conversion from unsigned to std_logic_vector is performed inside a conditional statement

    IEEE Std 1076-2008 9.2.3 Relational operators paras 3 and 4:

    The equality and inequality operators (= and /=) are defined for all types other than file types and protected types. The equality operator returns the value TRUE if the two operands are equal and returns the value FALSE otherwise. The inequality operator returns the value FALSE if the two operands are equal and returns the value TRUE otherwise.

    Two scalar values of the same type are equal if and only if the values are the same. Two composite values of the same type are equal if and only if for each element of the left operand there is a matching element of the right operand and vice versa, and the values of matching elements are equal, as given by the predefined equality operator for the element type. In particular, two null arrays of the same type are always equal. Two values of an access type are equal if and only if they both designate the same object or they both are equal to the null value for the access type.

    The equality test will return FALSE if the length of the two std_logic_vector values don't match. The length of INPUT declared in a port is 8. The length of the unsigned converted to std_logic_vector is 4 (from the second argument of to_unsigned, a natural specifying the length of the returned unsigned).

    If you uncomment the assignment to temp and run the code you'll get an error message during simulation.

    14.7.3.4 Signal update para 1 and 2:

    For a scalar signal S, both the driving and effective values shall belong to the subtype of the signal. For a composite signal R, an implicit subtype conversion is performed to the subtype of R; for each element of R, there shall be a matching element in both the driving and the effective value, and vice versa.

    In order to update a signal during a given simulation cycle, the kernel process first determines the driving and effective values of that signal. The kernel process then updates the variable containing the driving value with the newly determined driving value. The kernel also updates the variable containing the current value of the signal with the newly determined effective value, as follows:

    a) If S is a scalar signal, the effective value of S is used to update the current value of S. A check is made that the effective value of S belongs to the subtype of S. An error occurs if this subtype check fails. Finally, the effective value of S is assigned to the variable representing the current value of the signal.

    b) If S is a composite signal (including a slice of an array), the effective value of S is implicitly converted to the subtype of S. The subtype conversion checks that for each element of S there is a matching element in the effective value and vice versa. An error occurs if this check fails. The result of this subtype conversion is then assigned to the variable representing the current value of S.

    Evaluation of the condition isn't defined as an error while updating the signal requires there be a matching element in the expression on the right hand side, and that fails.

    It's perfectly valid to compare an array value for relational equality to a null array and get a FALSE return value.

    Line 19 reported in the following error is the temp assignment uncommented:

    ghdl -a vector_test.vhdl
    ghdl -e vector_test
    ghdl -r vector_test
    ../../src/ieee/numeric_std-body.v93:2151:7:@0ms:(assertion warning): NUMERIC_STD.TO_UNSIGNED: vector truncated
    ./vector_test:error: bound check failure at vector_test.vhdl:19
    ./vector_test:error: simulation failed

    besides the bound check failure error dictated by 14.7.3.4 (12.6.2 Propagation of signal values, para 12 in -1993), we see a warning from the package numeric_std function to_unsigned reporting a division remainder other than zero:

      function TO_UNSIGNED (ARG, SIZE : NATURAL) return UNRESOLVED_UNSIGNED is
        variable RESULT : UNRESOLVED_UNSIGNED(SIZE-1 downto 0);
        variable I_VAL  : NATURAL := ARG;
      begin
        if (SIZE < 1) then return NAU;
        end if;
        for I in 0 to RESULT'left loop
          if (I_VAL mod 2) = 0 then
            RESULT(I) := '0';
          else RESULT(I) := '1';
          end if;
          I_VAL          := I_VAL/2;
        end loop;
        if not(I_VAL = 0) then
          assert NO_WARNING
            report "NUMERIC_STD.TO_UNSIGNED: vector truncated"
            severity warning;
        end if;
        return RESULT;
      end function TO_UNSIGNED;
    

    This is caused by providing a SIZE argument (4) not sufficient to contain the natural value of constant pattern_int value 16#80# converted to binary which would require an 8 bit SIZE.

    Being able to execute vector_test with top level ports is implementation dependent.

    14.2 Elaboration of a design entity para 7:

    An implementation may allow, but is not required to allow, a design entity at the root of a design hierarchy to have generics and ports. If an implementation allows these top-level interface objects, it may restrict their allowed forms (that is, whether they are allowed to be interface types, subprograms, packages, or objects), and, in the case of interface objects, their allowed types and modes in an implementation-defined manner.

    Simply put for some simulators your code is an MCVE while for others it is not. Your testbench could be included in your question. The error we see running ghdl occurs outside the if statement with a condition evaluating the rising edge of CLOCK.