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:
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
So, for doing arithmetic you only need one arithmetic library: numeric_std
. Don't use std_logic_arith
because it is not standardized, so behavior can differ between implementations.
Then std_logic_unsigned
could be risky. Jim Lewis explains here that its could be a good idea to use it, but I think that you should not. Better to use integer
, unsigned
and signed
data types for all comparisons.
mult
What you are implementing is lookup-tables. Combinatorial logic statements. This is not arithmetic, so no arithmetic libraries are needed.
However, you could simplify the code. Let's take this description ar reference.
The 1x1 multiplier can be defined using logic operators (based on a full adder described here):
architecture rtl of mult is
signal FA_a, FA_b : std_logic;
begin
FA_a <= Sin;
FA_b <= a AND b;
Sout <= FA_a XOR FA_b XOR Cin;
Cout <= (FA_a AND FA_b) OR (Cin AND (FA_a XOR FA_b));
end architecture;
Or just skip this all and use the addition operator, which does the logic for you.
architecture rtl of mult is
use ieee.numeric_std.all;
signal FA_a, FA_b, FA_Cin : unsigned(1 downto 0) := (others => '0');
signal FA_out : unsigned(1 downto 0);
begin
FA_a(0) <= Sin;
FA_b(0) <= a AND b;
FA_Cin(0) <= Cin;
FA_out <= FA_a + FA_b + FA_Cin;
Sout <= FA_out(0);
Cout <= FA_out(1);
end architecture;
generic_mult
First off, your multiplier is MxM, not MxN. Next you complain about your labels in the comments... would take just as much effort to change them ;).
Regarding your implementation, you are assigning signals multiple times in the labellll
generate block. It should be:
labellll: for N in 0 to bits-1 generate
sum_internal(N+1)(N) <= carry_internal(N)(N);
end generate;
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);
but this is not the biggest problem, as it can be resolved.
The problem you do have, has to do with multiple drivers. In this_is_label2
you have the line:
Sout => sum_internal(M+1)(N-1)
And in labellll
you have the line:
sum_internal(N+1)(N) <= carry_internal(N)(N);
Two statements, which are both assigning a value to sum_internal
. If both 1
and 0
are assigned, this will resolve to X
.
But this is not necesary, because it is the result of an error in your design. Please see my link again to see how you should implement the multiplier. I'm not going to do it for you (it's not that difficult and probably your homework. You don't learn anything if other people do your homework for you. ;) )
You're combining unsigned
arithmetic (to_integer(unsigned(a))*to_integer(unsigned(b))
) with std_logic_vector
arithmetic (a <= a + 1;
). Don't do that. Preferably only use unsigned
.
As stated by pev.hall, you could just simplify everything and use the multiplication operator from the numeric_std
package.
entity generic_mult is
generic (
M: positive;
N: positive
);
port (
a : in std_logic_vector(M-1 downto 0);
b : in std_logic_vector(N-1 downto 0);
answer : out std_logic_vector(M+N-1 downto 0)
);
end entity;
architecture rtl of generic_mult is
use ieee.numeric_std.all;
begin
answer <= std_logic_vector(unsigned(a)*unsigned(b));
end architecture;