Search code examples
vhdlmultiplicationdigital-logic

Confusion in VHDL code


I am trying to implement a recoding logic for a 32 bit multiplier in VHDL. Besides, the input bit vector (x_in) to be recoded, it has one extra input "one". The intent is when "one" is '1' the output should be x_in else if "one" is '0', it should be twice x_in. And if "neg" is high then the output has to be inverted. Here is my VHDL code:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

package sum_vector_pkg is
    type partial_sum_array is array (0 to 15) of std_logic_vector(32 downto 0);
end package;

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
use work.sum_vector_pkg.all;
use work.test.all;

entity multipleGenerator is 
    generic(
           constant WIDTH : integer := 32
    );
    port(
        x_in      : in std_logic_vector(WIDTH - 1 downto 0);
        one       : in std_logic_vector(WIDTH/2 - 1 downto 0);
        multiple  : out partial_sum_array
    );
end entity multipleGenerator;

architecture logic of multipleGenerator is
    signal sum  : std_logic_vector(WIDTH downto 0);

begin
    gen : for i in 0 to WIDTH/2 - 1 generate
        process (one,sum,x_in) is begin
            case one(i) is
                when '0' => sum <= x_in & '0'; -- twice x_in
                when '1' => sum <= '0' & x_in; -- same as x_in
                when others => sum <= x"00000000" &'0';
            end case;
            multiple(i) <= sum;
            report "The sum is " & toString(sum) & " one(i) is " & toString(one(i)) & " x_in is " & toString(x_in);
        end process;
    end generate;
end architecture logic;

I am running it with the following testbench:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use work.sum_vector_pkg.all;

entity tb_multipleGenerator is

end entity tb_multipleGenerator;

architecture logic of tb_multipleGenerator is

    component multipleGenerator
        generic(
           constant WIDTH : integer := 32
        );
        port(
            x_in      : in std_logic_vector(31 downto 0);
            one       : in std_logic_vector(15 downto 0);
            multiple  : out partial_sum_array
        );
    end component;

    signal x_tb        : std_logic_vector(31 downto 0);
    signal one_tb      : std_logic_vector(15 downto 0);
    signal multiple_tb : partial_sum_array;

begin
    process begin
        x_tb <= x"00000000";
        one_tb <= x"0000";
        wait for 200 ns;
        x_tb <= x"00001111";
        one_tb <= x"0011";
        wait;
    end process;

    u_mult: multipleGenerator
        generic map (
           WIDTH => 32
        )
        port map (
            x_in     => x_tb,   
            one      => one_tb,
            multiple => multiple_tb
        );
end architecture logic;

To check the output I am using the following package:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

package test is
    function toString(v : std_logic_vector) return string;
    function toString(b : std_logic) return string;
end package;

package body test is 
    function toString(b : std_logic) return string is
        variable str : string(1 to 3);
        begin
            str := std_logic'image(b);
            return "" & str(2);
    end toString;

    function toString(v : std_logic_vector) return string is
        variable str    : string(1 to 1);
        variable strOut : string(1 to v'length);
        begin
            for i in 1 to v'length  loop
                str := toString(v(i-1));
                strOut(v'length - i + 1) := str(1);
            end loop;
            return strOut;
    end toString;
end test;

When I run the above code I get 'X' in the output. Here is the sample output:

    Time: 200 ns  Iteration: 2  Region: /tb_multiplegenerator/u_mult/gen(12)
# ** Note: The sum is 0000000000000000000XX00XX00XX00XX one(i) is 0 x_in is 00000000000000000001000100010001
#    Time: 200 ns  Iteration: 2  Region: /tb_multiplegenerator/u_mult/gen(13)
# ** Note: The sum is 0000000000000000000XX00XX00XX00XX one(i) is 0 x_in is 00000000000000000001000100010001
#    Time: 200 ns  Iteration: 2  Region: /tb_multiplegenerator/u_mult/gen(14)
# ** Note: The sum is 0000000000000000000XX00XX00XX00XX one(i) is 0 x_in is 00000000000000000001000100010001
#    Time: 200 ns  Iteration: 2  Region: /tb_multiplegenerator/u_mult/gen(15)

Could someone please explain why this code is not working?


Solution

  • The problem is already in your multipleGenerator entity. You define the signal sum, which you keep reusing in your generate statement. However, these assignments happen in parallel in VHDL. So in effect, you are assigning sum with 16 drivers!

    But you don't need sum actually.

    Cleaning up your code (and making it vhdl 2008)

    std_logic_vector_vector_pkg.vhd:

    library ieee;
    use ieee.std_logic_1164.all;
    
    package std_logic_vector_vector_pkg is
        type std_logic_vector_vector is array (natural range <>) of std_logic_vector;
    end package;
    

    converter_pkg.vhd

    library ieee;
    use ieee.std_logic_1164.all;
    
    package converter_pkg is
        function to_string(slv : std_logic_vector) return string;
    end package;
    
    package body converter_pkg is
        function to_string(slv : std_logic_vector) return string is
            variable output : string(1 to slv'length) := (others => 'X');
            variable i_o : positive := 1;
        begin
            for i_s in slv'high downto slv'low loop
                output(i_o) := std_logic'image(slv(i_s))(2);
                i_o := i_o + 1;
            end loop;
            return output;
        end function;
    end package body;
    

    multipleGenerator.vhd

    library ieee;
    use ieee.std_logic_1164.all;
    use work.std_logic_vector_vector_pkg.all;
    use work.converter_pkg.all;
    
    entity multipleGenerator is 
        generic(
            WIDTH : integer := 32
        );
        port(
            x_in      : in std_logic_vector(WIDTH - 1 downto 0);
            one       : in std_logic_vector(WIDTH/2 - 1 downto 0);
            multiple  : out std_logic_vector_vector(0 to WIDTH/2 - 1)(WIDTH downto 0)
        );
    end entity;
    
    architecture rtl of multipleGenerator is
    begin
        gen : for i in 0 to WIDTH/2 - 1 generate
            multiple(i) <= '0' & x_in when one(i)='1' else x_in & '0';
        end generate;
    
        process(one)
        begin
            for i in 0 to WIDTH/2 - 1 loop 
                report "The sum is " & to_string(multiple(i)) &
                    " one(" & integer'image(i) & ") is " & std_logic'image(one(i)) &
                    " x_in is " & to_string(x_in);
            end loop;
        end process;
    end architecture;
    

    multipleGenerator_tb.vhd

    library ieee;
    use ieee.std_logic_1164.all;
    use work.std_logic_vector_vector_pkg.all;
    
    entity multipleGenerator_tb is end entity;
    
    architecture behavioral of multipleGenerator_tb is
        signal b        : std_logic_vector(31 downto 0);
        signal one      : std_logic_vector(15 downto 0);
        signal multiple : std_logic_vector_vector(0 to one'length-1)(x'length downto 0);
    begin
        process
        begin
            x <= (others => '0');
            one <= (others => '0');
            wait for 200 ns;
            x <= x"00001111";
            one <= x"0011";
            wait;
        end process;
    
        u_mult: entity work.multipleGenerator
            generic map (
                WIDTH => x'length
            )
            port map (
                x_in     => x,   
                one      => one,
                multiple => multiple
            );
    end architecture;