-------------------------------------------------------------------------
--  MULTIPLICAÇÃO POR SOMAS SUCESSIVAS E DIVISÃO POR SUBTRAÇÕES SUCESSIVAS
--
--	Multiplicador:
--  	Mcando, Mcador		- Multiplicando e Multiplicador, de N bits
--  	start, endop 		- Início e fim da operação de multiplicação
--  	produto      		- Resultado, com 2N bits
--
--	Divisor:
--  	dividendo,divisor	- Dividendo e Divisor, de N bits
--  	start, endop 		- Início e fim de operação de divisão
--  	quociente,resto		- Resultados, cada um com N bits
--
--  05/07/2018 (Ney) - Inicialização de sinais
--			externos, para evitar que fiquem indefinidos
--  16/06/2020 (Ney) - Bugs corrigidos
--			Mudada a lógica interna do multiplicador e do divisor para 
--			viabilizar resetá-los junto com o reset de processador externo.
--			Isto exigiu inicializar os registradores RegP e RegB em ambos
--			módulos apenas ao sair do estado inicializa e não ao entrar 
--			neste.
--	19/10/2022 (Ney) - Nomes dos módulos mudados para multiplier e divider
--			- Alguns nomes de sinais foram mudados para inglês para manter
--			a coerência, sobretudo na interface dos módulos de mult/div	
-------------------------------------------------------------------------

-----------------------------------------------------------------------
--  MÓDULO DE MULTIPLICAÇÃO
-----------------------------------------------------------------------
library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Std_Logic_unsigned.all;

entity multiplier is
	generic(N: integer := 32);
	port( clock,start:	in  std_logic; 
		Mcand:				in  std_logic_vector((N-1) downto 0);
		Mplier:				in  std_logic_vector((N-1) downto 0);
		endop:				out std_logic;
		product:			out std_logic_vector(2*N-1 downto 0));
end;

architecture multiplier of multiplier is   
	type State_type is (initialize, shift, add, finish, endm);
	signal EA: State_type;
	signal regP :	std_logic_vector( N*2 downto 0); 
	signal regB :	std_logic_vector( N   downto 0);
	signal count:	integer;

begin
	--
	-- registradores regP, regB, produto, endop e contador de execução
	--
	process(start, clock)
	begin
		if (start='0' and EA=initialize) then 
			-- Inicializa-se os registradores na saída do estado
			-- e não na entrada
			regP( N*2 downto N)	<= (others=>'0');
			regP( N-1 downto 0) 	<= Mplier;         
			regB					<= '0' & Mcand;
			count					<= 1;
			endop					<= '0';
			product 				<= (others=>'0');
		elsif clock'event and clock='1' then
			if EA=add and regP(0)='1' then
				regP(N*2 downto N) <= regP(N*2 downto N) + regB;
			elsif EA=shift then
				regP <= '0' & regP(N*2 downto 1);
				count <= count + 1;
			elsif EA=finish then
				product	<= regP( N*2-1 downto 0);
				endop	<= '1';
			elsif EA=endm then
				endop <= '0';
			end if;
		end if;       
	end process;

	-- Máquina de Estados para controlar a multiplicação
	process (start, clock)
	begin
		if start='1' then
			EA <= initialize;
		elsif clock'event and clock='1' then  
			case EA is
				when initialize	=>   EA <= add;   
				when add		=>  EA <= shift;
				when shift		=>  if count=N then 
										EA <= finish; 
									else 
										EA <= add;
									end if;             
				-- estado finish  só serve para gerar o pulso em endop  
				when finish		=>	EA <= endm;
				when endm		=>	EA <= endm;    
			end case;
		end if;
	end process;

end multiplier;

-----------------------------------------------------------------------
--  MÓDULO DE DIVISÃO
-----------------------------------------------------------------------
library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Std_Logic_unsigned.all;

entity divider is
	generic(N: integer := 32);
	port( clock,start :		in  std_logic;
		dividend:			in  std_logic_vector( (N-1) downto 0);
		divisor:			in  std_logic_vector( (N-1) downto 0); 
		endop :				out std_logic;
		quotient :			out std_logic_vector( N-1 downto 0);
		remainder :			out std_logic_vector( N-1 downto 0));
end;

architecture divider of divider is   
	type State_type is (initialize, shift, addsub, finish, endd);
	signal EA :			State_type;
	signal regP :		std_logic_vector(N*2 downto 0); 
	signal regB :		std_logic_vector(N   downto 0);
	signal difference :	std_logic_vector(N  downto 0);
	signal count:		integer;

begin
	difference <=  regP( N*2 downto N) -  regB( N downto 0);   

	process(start, clock)
	begin    
		if (start='0' and EA=initialize) then
			-- Inicializa-se os registradores na saída do estado
			-- e não na entrada
			regP(N*2 downto N)	<= (others=>'0');
			regP(N-1 downto 0)	<= dividend;
			regB				<= '0' & divisor;
			count				<= 1;
			endop				<= '0';
			remainder			<= (others=>'0');
			quotient			<= (others=>'0');
		elsif clock'event and clock='1' then
			if EA=shift then
				regP <= regP(N*2-1 downto 0) & regP(N*2);
			elsif EA=addsub then  
				if difference(N)='1' then  
					regP(0)<='0';
				else
					regP(0)<='1';
					regP(N*2 downto N) <= difference;
				end if;
				count <= count + 1;
			elsif EA=finish then
				remainder	<= regP(N*2-1 downto N);
				quotient 	<= regP(N-1   downto 0);
				endop		<= '1';
			elsif EA=endd then
					endop <= '0';
			end if;
		end if;
	end process;
	
	-------------------------------------------------
	-- Máquina de Estados para controlar a divisão
	-------------------------------------------------
	process (start, clock)
		begin
			if start='1'then
				EA <= initialize;
			elsif clock'event and clock='1' then  
				case EA is
					when initialize => EA <= shift; 
					when shift		=> EA <= addsub;
					when addsub		=> if count=N then 
											EA <= finish; 
										else 
											EA <= shift;  
										end if;
					-- estado termina só serve para gerar o pulso em endop  
					when finish		=> EA <= endd;
					when endd		=> EA <= endd;
				end case; 
			end if;
	end process;

end divider;
