Search code examples
vhdl

Can't add std_logic to unsigned


I'm making a program to count all the 1's from a std_logic_vector, the out from the program should be a std_logic_vector too. The vector size is based on a generic number. To do the count, i'm using a for generate and adding the 1's to an unsigned signal, but it's not working. Here is the error from the ide: Line 27. unsigned can not have such operands with returned type UNSIGNED.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_arith.all;
use IEEE.NUMERIC_STD.ALL;

entity proj2_1 is
     GENERIC (N: INTEGER := 8); -- SIZE OF THE VECTOR
    Port ( VTIN : in  STD_LOGIC_VECTOR (N-1 downto 0);
           VTOUT : out  STD_LOGIC_VECTOR (N-1 downto 0);
              cont: buffer unsigned  (N-1 downto 0) );
end proj2_1;
architecture Behavioral of proj2_1 is
begin
    gen: FOR i IN VTIN' RANGE GENERATE  
    BEGIN
        cont <= cont + ( unsigned (VTIN(i)));
    END GENERATE;
    VTOUT <= std_logic_vector(cont);
end Behavioral;

Solution

  • First there should be no declaration of unsigned visible due to conflicts between packages std_logic_arith and numeric_std. Use one or the other (numeric_std is part of the VHDL standard).

    Second the element type of VTIN is std_logic or std_ulogic depending on the VHDL revision which isn't compatible with the array type/subtype std_logic_vector. That means type conversion isn't legal.

    Next a concurrent signal assignment is elaborated into a process which implies a driver for the longest static prefix (here cont). Having VTIN'LENGTH processes with generate 'X's, the values will be resolved, the driver outputs are shorted.

    Instead of a generate statement use a process with a variable used to count '1's in a sequential loop statement with a for iteration scheme. The variable is used because the value of signal cont isn't updated until the process suspends. You assign the variable value to cont after the loop statement. After the process suspends, the value of cont will be available to use in the assignment to VTOUT. std_logic_arith can added a std_logic value to a std_logic_vector as can numeric_std in -2008 (otherwise unsigned(""& VTIN(i)) converts std_logic to unsigned. You could also implement a subprogram.

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    -- use ieee.std_logic_arith.all;
    use IEEE.NUMERIC_STD.ALL;
    
    entity proj2_1 is
         GENERIC (N: INTEGER := 8); -- SIZE OF THE VECTOR
        Port ( VTIN : in  STD_LOGIC_VECTOR (N-1 downto 0);
               VTOUT : out  STD_LOGIC_VECTOR (N-1 downto 0);
                  cont: buffer unsigned  (N-1 downto 0) );
    end entity proj2_1;
    architecture behavioral of proj2_1 is
    begin
        -- gen: FOR i IN VTIN' RANGE GENERATE
        -- BEGIN
        --     cont <= cont + ( unsigned (VTIN(i)));
        -- END GENERATE;
    
    SEQUENTIAL_LOOP_NOT_GENERATE_STATEMENT:
        process (VTIN)
        variable ones: unsigned(VTOUT'RANGE);
        begin
            ones := (others => '0'); -- zero
            for i in VTIN'RANGE loop
                ones := ones + unsigned'("" & VTIN(i));
            end loop;
            VTOUT <= std_logic_vector (cont + ones);
        end process;
    end architecture behavioral;
    

    A generate statement is a concurrent statement which elaborates to a block statement for every value of the generate parameter containing the concurrent statement which has a process statement equivalent. A process statement has a driver for each signal assigned in it's sequence of statements. One driver versus lots of drivers.

    With package numeric std you could also declare the variable (here ones) as an integer (natural). numeric_std supports the addition of natural range integers to unsigned values.

    Notice there's nothing that defines an initial value for port cont which has a mode of buffer, essentially an output that be read internally. The default initial value will be (others => 'U')from the left most value of the enumerated type std_ulogic. Either the original intent is wrong (count all the 1's from a std_logic_vector" or more likely you actually one the population count of '1's in VTIN.

    The latter requires a change:

    architecture behavioral of proj2_1 is
    begin
    SEQUENTIAL_LOOP_NOT_GENERATE_STATEMENT:
        process (VTIN)
        variable ones: unsigned(VTOUT'RANGE);
        begin
            ones := (others => '0'); -- zero
            for i in VTIN'RANGE loop
                ones := ones + unsigned'("" & VTIN(i));
            end loop;
            -- VTOUT <= std_logic_vector (cont + ones);
            VTOUT <= std_logic_vector (ones);
            cont <= ones;
        end process;
    end architecture behavioral;
    

    that doesn't reflect the original code but doesn't accumulate across new values of VTIN and is synthesis eligible.

    The integer variable version of the population count of '1's could look like

    architecture integer_variable of proj2_1 is
    begin
    SEQUENTIAL_LOOP_NOT_GENERATE_STATEMENT:
        process (VTIN)
        variable ones: natural;
        begin
            ones := 0;
            for i in VTIN'RANGE loop
                if TO_BIT(VTIN(i)) = '1' then
                    ones := ones + 1;
                end if;
            end loop;
            VTOUT <= std_logic_vector (to_unsigned(ones, VTOUT'length));
            cont <= to_unsigned(ones, VTOUT'length); -- and both outputs don't make sense
        end process;
    end architecture integer_variable;
    

    where adding an integer value doesn't propagate meta values from VTIN during addition.