134 lines
5.8 KiB
VHDL
134 lines
5.8 KiB
VHDL
library IEEE;
|
|
use IEEE.std_logic_1164.all;
|
|
use IEEE.numeric_std.all;
|
|
entity float_add is
|
|
port(A : in std_logic_vector(31 downto 0);
|
|
B : in std_logic_vector(31 downto 0);
|
|
clk : in std_logic;
|
|
reset : in std_logic;
|
|
start : in std_logic;
|
|
done : out std_logic;
|
|
sum : out std_logic_vector(31 downto 0)
|
|
);
|
|
end float_add;
|
|
|
|
architecture mixed of float_add is
|
|
type ST is (WAIT_STATE, ALIGN_STATE, ADDITION_STATE, NORMALIZE_STATE, OUTPUT_STATE);
|
|
signal state : ST := WAIT_STATE;
|
|
|
|
---Internal Signals latched from the inputs
|
|
signal A_mantissa, B_mantissa : std_logic_vector (24 downto 0);
|
|
signal A_exp, B_exp : std_logic_vector (8 downto 0);
|
|
signal A_sgn, B_sgn : std_logic;
|
|
|
|
--Internal signals for Output
|
|
signal sum_exp: std_logic_vector (8 downto 0);
|
|
signal sum_mantissa : std_logic_vector (24 downto 0);
|
|
signal sum_sgn : std_logic;
|
|
|
|
begin
|
|
|
|
Control_Unit : process (clk, reset) is
|
|
variable diff : signed(8 downto 0);
|
|
begin
|
|
if(reset = '1') then
|
|
state <= WAIT_STATE; --start in wait state
|
|
done <= '0';
|
|
elsif rising_edge(clk) then
|
|
case state is
|
|
when WAIT_STATE =>
|
|
if (start = '1') then --wait till start request startes high
|
|
A_sgn <= A(31);
|
|
A_exp <= '0' & A(30 downto 23); --One bit is added for signed subtraction
|
|
A_mantissa <= "01" & A(22 downto 0); --Two bits are added extra, one for leading 1 and other one for storing carry
|
|
B_sgn <= B(31);
|
|
B_exp <= '0' & B(30 downto 23);
|
|
B_mantissa <= "01" & B(22 downto 0);
|
|
state <= ALIGN_STATE;
|
|
else
|
|
state <= WAIT_STATE;
|
|
end if;
|
|
when ALIGN_STATE => --Compare exponent and align it
|
|
--If any num is greater by 2**24, we skip the addition.
|
|
if unsigned(A_exp) > unsigned(B_exp) then
|
|
--B needs downshifting
|
|
diff := signed(A_exp) - signed(B_exp); --Small Alu
|
|
if diff > 23 then
|
|
sum_mantissa <= A_mantissa; --B insignificant relative to A
|
|
sum_exp <= A_exp;
|
|
sum_sgn <= A_sgn;
|
|
state <= OUTPUT_STATE; --start latch A as output
|
|
else
|
|
--downshift B to equilabrate B_exp to A_exp
|
|
sum_exp <= A_exp;
|
|
B_mantissa(24-to_integer(diff) downto 0) <= B_mantissa(24 downto to_integer(diff));
|
|
B_mantissa(24 downto 25-to_integer(diff)) <= (others => '0');
|
|
state <= ADDITION_STATE;
|
|
end if;
|
|
elsif unsigned(A_exp) < unsigned(B_exp) then --A_exp < B_exp. A needs downshifting
|
|
diff := signed(B_exp) - signed(A_exp); -- Small Alu
|
|
if diff > 23 then
|
|
sum_mantissa <= B_mantissa; --A insignificant relative to B
|
|
sum_sgn <= B_sgn;
|
|
sum_exp <= B_exp;
|
|
state <= OUTPUT_STATE; --start latch B as output
|
|
else
|
|
--downshift A to equilabrate A_exp to B_exp
|
|
sum_exp <= B_exp;
|
|
A_mantissa(24-to_integer(diff) downto 0) <= A_mantissa(24 downto to_integer(diff));
|
|
A_mantissa(24 downto 25-to_integer(diff)) <= (others => '0');
|
|
state <= ADDITION_STATE;
|
|
end if;
|
|
else -- Both exponent is equal. No need to mantissa shift
|
|
sum_exp <= A_exp;
|
|
state <= ADDITION_STATE;
|
|
end if;
|
|
when ADDITION_STATE => --Mantissa addition
|
|
state <= NORMALIZE_STATE;
|
|
if (A_sgn xor B_sgn) = '0' then --signs are the same. Just add them
|
|
sum_mantissa <= std_logic_vector((unsigned(A_mantissa) + unsigned(B_mantissa))); --Big Alu
|
|
sum_sgn <= A_sgn; --both nums have same sign
|
|
--Else subtract smaller from larger and use sign of larger
|
|
elsif unsigned(A_mantissa) >= unsigned(B_mantissa) then
|
|
sum_mantissa <= std_logic_vector((unsigned(A_mantissa) - unsigned(B_mantissa))); --Big Alu
|
|
sum_sgn <= A_sgn;
|
|
else
|
|
sum_mantissa <= std_logic_vector((unsigned(B_mantissa) - unsigned(A_mantissa))); --Big Alu
|
|
sum_sgn <= B_sgn;
|
|
end if;
|
|
|
|
when NORMALIZE_STATE => --Normalization.
|
|
if unsigned(sum_mantissa) = TO_UNSIGNED(0, 25) then
|
|
--The sum is 0
|
|
sum_mantissa <= (others => '0');
|
|
sum_exp <= (others => '0');
|
|
state <= OUTPUT_STATE;
|
|
elsif(sum_mantissa(24) = '1') then --If sum overflowed we downshift and are done.
|
|
sum_mantissa <= '0' & sum_mantissa(24 downto 1); --shift the 1 down
|
|
sum_exp <= std_logic_vector((unsigned(sum_exp)+ 1));
|
|
state <= OUTPUT_STATE;
|
|
elsif(sum_mantissa(23) = '0') then --in this case we need to upshift
|
|
--This iterates the normalization shifts, thus can take many clocks.
|
|
sum_mantissa <= sum_mantissa(23 downto 0) & '0';
|
|
sum_exp <= std_logic_vector((unsigned(sum_exp)-1));
|
|
state<= NORMALIZE_STATE; --keep shifting till leading 1 appears
|
|
else
|
|
state <= OUTPUT_STATE; --leading 1 already there. Latch output
|
|
end if;
|
|
when OUTPUT_STATE =>
|
|
sum(22 downto 0) <= sum_mantissa(22 downto 0);
|
|
sum(30 downto 23) <= sum_exp(7 downto 0);
|
|
sum(31) <= sum_sgn;
|
|
done <= '1'; -- signal done
|
|
if (start = '0') then -- stay in the state till request ends i.e start is low
|
|
done <= '0';
|
|
state <= WAIT_STATE;
|
|
end if;
|
|
when others =>
|
|
state <= WAIT_STATE; --Just in case.
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
end mixed;
|