library BITLIB;
use BITLIB.bit_pack.all;

entity FMUL is
   port (CLK, St: in bit;
		 F1,E1,F2,E2: in bit_vector(3 downto 0);
		 F: out bit_vector(6 downto 0);
		 V, done:out bit);
end FMUL; 

architecture FMULB of FMUL is
signal A, B, C: bit_vector(3 downto 0);			--fraction registers
signal X, Y: bit_vector(4 downto 0);			--exponent registers
signal Load, Adx, Mdone, SM8, RSF, LSF, NC: bit;
signal AdSh, Sh, Cm: bit;
signal PS1, NS1: integer range 0 to 3;		-- present and next state 
signal State, Nextstate: integer range 0 to 4;-- mulitplier control state
alias M: bit is B(0);
constant one:bit_vector(4 downto 0):="00001";
constant neg_one:bit_vector(4 downto 0):="11111";
begin
main_control: process 
  begin
	Load <= '0'; Adx <= '0';					--clear control signals 
	SM8 <= '0'; RSF <= '0'; LSF <= '0';
	case PS1 is
		when 0 =>  done<='0'; V<='0';     			--clear outputs
			if St = '1' then Load <= '1'; NS1 <= 1; F <= "0000000";
			end if;   
		when 1 =>  Adx <= '1'; NS1 <= 2;
		when 2 => 
			  if Mdone = '1' then        			--wait for multiply 
				if A = "0000" then				--zero fraction 
					SM8 <= '1';
				elsif A = "0100" and B = "0000" then 	--fraction overflow  
					RSF <= '1';        			--shift AB right   
				elsif A(2) = A(1) then   			--test for unnormalized
				  LSF <= '1';           			--shift AB left     
				end if;  
				NS1 <= 3;              
			  end if;
		when 3 =>                        			--test for exp overflow
			  if X(4) /= X(3) then V <= '1'; else V <= '0'; end if;  
			  done <= '1';
			  F <= A(2 downto 0) & B;				--output fraction
			  if ST = '0' then NS1<=0; end if;
	end case;
	wait until rising_edge(CLK);
		PS1 <= NS1;
	wait for 0 ns;						--wait for state change
  end process main_control;
mul2c: process							--2's complement multiply
	begin
	AdSh <= '0'; Sh <= '0'; Cm <= '0';			--clear control signals
	case State is
	  when 0=>  Mdone <= '0';        				--start multiply
		if Adx='1' then             
		  if M = '1' then AdSh <= '1'; else Sh <= '1'; end if;
		  Nextstate <= 1;       
		end if;
	  when 1 | 2  =>                 				--add/shift state
		if M = '1' then AdSh <= '1'; else Sh <= '1'; end if;
		Nextstate <= State + 1;
	  when 3  => 
		if M = '1' then Cm <= '1'; AdSh <= '1'; else Sh <='1'; end if;
		Nextstate <= 4;
	  when 4 =>
		Mdone <= '1';  Nextstate <= 0;
	end case;
	wait until rising_edge(CLK);
	State <= Nextstate;
	wait for 0 ns;                     			--wait for state change
  end process mul2c;

  update: process 						--update registers
  variable addout: bit_vector(4 downto 0); 
  begin
	wait until rising_edge(CLK);
	if Cm = '0' then addout := add4(A,C,'0');
	  else addout := add4(A, not C,'1'); end if;	--add 2's comp. of C
	if Load = '1' then  X <= E1(3)&E1; Y <= E2(3)&E2; 
	  A <= "0000"; B <= F2; C <= F1; end if;
	if ADX = '1' then addvec(X,Y,'0',X,NC,5); end if;
	if SM8 = '1' then  X <= "11000"; end if;
	if RSF = '1' then  A <= '0'&A(3 downto 1); 
	  B <= A(0)&B(3 downto 1);
	  addvec(X,one,'0',X,NC,5); end if;   			-- increment X
	if LSF = '1' then
	  A <= A(2 downto 0)&B(3); B <= B(2 downto 0)&'0';
	  addvec(X,neg_one,'0',X,NC,5); end if;    		-- decrement X
	if AdSh = '1' then
	  A <= (C(3) xor Cm) & addout(3 downto 1);		-- load shifted adder
	  B <= addout(0) & B(3 downto 1); end if;		-- output into A & B
	if Sh = '1' then
	  A <= A(3) & A(3 downto 1);				-- right shift A & B
	  B <= A(0) & B(3 downto 1);				-- with sign extend
	end if; 
  end process update;
end FMULB;

