Electrical – VHDL NxM -bit parallel block multiplier

vhdl

I am trying to create schematics for a NxM -bit parallel block multiplier using generic parameters to define the size of the multiplier, and generate statements to describe the internal structure. I am having some trouble with my sums and carries and I am not able to implement what I want to do in VHDL code.

Here is what I got so far:

1-bit multiplier:

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

entity mult is  
 port (  
  a     :  in std_logic;  
  b     :  in std_logic;  
  Sin   :  in std_logic;        --sum-in  
  Cin   :  in std_logic;        --carry-in  
  Sout  :  out std_logic;       --sum-out  
  Cout  :  out std_logic        --carry-out  
);  
end mult;  

architecture mult of mult is  
  begin  

Sout <= '1' when a = '0' and b = '0' and Sin = '0' and Cin = '1' else
        '1' when a = '0' and b = '0' and Sin = '1' and Cin = '0' else
        '1' when a = '0' and b = '1' and Sin = '1' and Cin = '0' else
        '1' when a = '0' and b = '1' and Sin = '0' and Cin = '1' else
        '1' when a = '1' and b = '0' and Sin = '0' and Cin = '1' else
        '1' when a = '1' and b = '0' and Sin = '1' and Cin = '0' else
        '1' when a = '1' and b = '1' and Sin = '0' and Cin = '0' else
        '1' when a = '1' and b = '1' and Sin = '1' and Cin = '1' else
        '0';
Cout <= '1' when a = '0' and b = '0' and Sin = '1' and Cin = '1' else
        '1' when a = '0' and b = '1' and Sin = '1' and Cin = '1' else
        '1' when a = '1' and b = '0' and Sin = '1' and Cin = '1' else
        '1' when a = '1' and b = '1' and Sin = '0' and Cin = '1' else
        '1' when a = '1' and b = '1' and Sin = '1' and Cin = '0' else
        '1' when a = '1' and b = '1' and Sin = '1' and Cin = '1' else
        '0';

end mult;

Used it as a component in an NxM multiplier:

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

entity generic_mult is
        generic (bits: integer);
 port (
  a     :  in std_logic_vector(bits-1 downto 0);
  b     :  in std_logic_vector(bits-1 downto 0);
  answer:  out std_logic_vector(bits*2-1 downto 0)      --sum-out
  );
end entity generic_mult;

architecture behavioral of generic_mult is

 component mult is
  port (
    a    :  in std_logic;
    b    :  in std_logic;
    Sin  :  in std_logic;       --sum-in
    Cin  :  in std_logic;       --carry-in
    Sout :  out std_logic;      --sum-out
    Cout :  out std_logic       --carry-out
  );
 end component;

        type mem_word  is array (0 to bits) of std_logic_vector(bits downto 0);

        signal  carry_internal : mem_word;
        signal  sum_internal : mem_word;

  begin
    this_is_label: for N in 1 to bits generate --Im sorry, my labels are horrible :(
        this_is_label3: for M in 0 to bits-1 generate

            this_is_label2: mult
          port map (
            a => a(N-1),
            b => b(M),
            Cin => carry_internal(M)(N),
            Cout => carry_internal(M+1)(N),
            Sin => sum_internal(M)(N),
            Sout => sum_internal(M+1)(N-1)
        );
    end generate;
end generate;
    labellll: for N in 0 to bits-1 generate
        sum_internal(N+1)(N) <= carry_internal(N)(N);
    carry_internal(0) <= (others => '0');
    sum_internal(0)   <= (others => '0');

    answer(bits*2-1) <= carry_internal(bits)(bits);
    answer(bits downto 0) <= sum_internal(bits);
    end generate;
end behavioral;

And a testbench for it:

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

entity NM_mult_tb is
end NM_mult_tb;

architecture behavioral of NM_mult_tb is
    component generic_mult

        generic (bits: integer := 4);
 port (
  a     :  in std_logic_vector(bits-1 downto 0);
  b     :  in std_logic_vector(bits-1 downto 0);
  answer:  out std_logic_vector(bits*2-1 downto 0)      --sum-out
  );
    end component;
   --declaring inputs and initializing them
        signal a  :  std_logic_vector(3 downto 0) :="0101";
        signal b  :  std_logic_vector(3 downto 0) :="1010";
        signal Sin:  std_logic_vector(3 downto 0) :="0000";
        signal Cin:  std_logic := '0';
   --declaring outputs and initializing them
        signal answer :  std_logic_vector(7 downto 0);  --sum-out
        signal correct:  std_logic;                     --carry-out

BEGIN
    -- Instantiating the Design Under Test (DUT)
   dut: generic_mult
        GENERIC MAP (4)
        PORT MAP (
          a => a,
          b => b,
         answer => answer
        );

   -- Stimulus process
    correct <= '1' when to_integer(unsigned(a))*to_integer(unsigned(b)) = 
to_integer(unsigned(answer)) else '0';
  stim_proc: process
   begin
        wait for 1 ns;
        a <= a + 1;
        if a = "0" then b <= b + 1; end if;
  end process;

END;

When I simulate it I see that there is something wrong with carry-ins and sum-ins and outs and my answer has undefined bits in it:

(I am not allowed to embedded images on this post before I have 10 reputation so here is a link to the image:) https://i.stack.imgur.com/y4ED9.png

enter image description here

If you have read my post this far, thank you very much for your attention. If someone could find the time to help me out with my problem I would be very grateful!

Sincerely,
A confused VHDL beginner

Best Answer

Here's how I would work it. Code first:

mult.vhd

library ieee;  
use ieee.std_logic_1164.all;  

entity mult is  
port ( a     :  in std_logic;  
       b     :  in std_logic;  
       pin   :  in std_logic;    -- product in  
       cin   :  in std_logic;    -- carry in  
       pout  :  out std_logic;   -- product out
       cout  :  out std_logic ); -- carry out  
end mult;  

architecture mult of mult is
begin  
    pout <= (a and b) xor cin xor pin;
    cout <= (a and b and cin) or (a and b and pin) or (cin and pin);
end mult;

generic_mult.vhd

library ieee;
use ieee.std_logic_1164.all;

entity generic_mult is
generic (N: integer; M: integer);
port ( a    :  in  std_logic_vector(N-1 downto 0);
       b    :  in  std_logic_vector(M-1 downto 0);
       prod :  out std_logic_vector(M+N-1 downto 0) );
end entity generic_mult;

architecture behavioral of generic_mult is

-- Components
component mult is
port (
    a    :  in std_logic;
    b    :  in std_logic;
    pin  :  in std_logic;
    cin  :  in std_logic;
    pout :  out std_logic;
    cout :  out std_logic );
end component;

-- Signals
type mem_word is array (0 to M-1) of std_logic_vector(N-1 downto 0);
signal cin  : mem_word;
signal cout : mem_word;
signal pin  : mem_word;
signal pout : mem_word;

begin

    m_loop: for i in 0 to M-1 generate
        n_loop: for j in 0 to N-1 generate
            mult_inst : mult
            port map (
                a    => a(j),
                b    => b(i),
                pin  => pin(i)(j),
                cin  => cin(i)(j),
                pout => pout(i)(j),
                cout => cout(i)(j) );
        end generate;
    end generate;

    cin_init: for j in 0 to N-1 generate 
        cin(0)(j) <= '0'; 
    end generate;

    cin_mloop: for i in 1 to M-1 generate
        cin_nloop: for j in 0 to N-2 generate 
            cin(i)(j) <= pout(i-1)(j+1); 
        end generate;
        cin(i)(N-1) <= cout(i-1)(N-1);
    end generate;

    pin_mloop: for i in 0 to M-1 generate 
        pin(i)(0) <= '0'; 
        pin_nloop: for j in 1 to N-1 generate 
            pin(i)(j) <= cout(i)(j-1); 
        end generate;
    end generate;

    prod_loop: for j in 0 to M-1 generate
        prod(j) <= pout(j)(0);
    end generate;

    prod(M+N-2 downto M) <= pout(M-1)(N-1 downto 1);
    prod(M+N-1) <= cout(M-1)(N-1);

end behavioral;

simulation

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

entity NM_mult_tb is
end NM_mult_tb;

architecture behavioral of NM_mult_tb is

component generic_mult
generic (M: integer := 4; N: integer := 4);
    port (
        a    :  in  std_logic_vector(M-1 downto 0);
        b    :  in  std_logic_vector(N-1 downto 0);
        prod :  out std_logic_vector(M+N-1 downto 0) );
end component;

-- signals
signal a       : std_logic_vector(3 downto 0) :="0101";
signal b       : std_logic_vector(3 downto 0) :="1010";
signal answer  : std_logic_vector(7 downto 0);
signal correct : std_logic;

begin
    -- Instantiating the Design Under Test (DUT)
    dut: generic_mult
    generic map (
        M => 4,
        N => 4 )
    port map (
        a    => a,
        b    => b,
        prod => answer );

    -- Stimulus process
    stim_proc: process
    begin
        wait for 1 ns;
        a <= a + 1;
        if a = "0" then
            b <= b + 1;
        end if;
    end process;

    -- Check results
    correct <= '1' when to_integer(unsigned(a))*to_integer(unsigned(b)) = 
    to_integer(unsigned(answer)) else '0';

end behavioral;

Simulation

The first thing I did was to simplify the mult entity. And since it is implemented as a 1-bit multiplier, I changed the signal names.

For generic_mult, I found it much easier to split your carry_internal and sum_internal buses to separate in/out buses. It removed a lot of the confusion. From there, it's not too difficult - as I think you'll see from the code.

Lastly, I changed your

generic (bits: integer);

to

generic (N: integer; M: integer);

to allow for MxN widths.

Related Topic