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

entity divider is
	port (
		clk : in std_logic;
		reset : in std_logic;
		
		numerator : in signed (17 downto 0) := (others => '0');
		denominator : in signed (8 downto 0) := (others => '0');
		
		result : out signed (17 downto 0) := (others => '0');
		done : out std_logic := '0'
	);
end entity divider;

architecture rtl of divider is
begin
	process(clk, reset)
		variable counter : unsigned (4 downto 0) := (others => '0');
		variable negative : std_logic := '0';
		variable pos_numerator : signed (17 downto 0) := (others => '0');
		variable pos_denominator : signed (8 downto 0) := (others => '0');
		variable numerator_var : unsigned (25 downto 0) := (others => '0');
		variable denominator_var : unsigned (25 downto 0) := (others => '0');
		variable result_shift : signed (17 downto 0) := (others => '0');
		variable subtract_var : signed (25 downto 0) := (others => '0');
	begin
		if reset = '1' then
			negative := '0';
			pos_numerator := numerator;
			if numerator(17) = '1' then
				negative := '1';
				pos_numerator := not(numerator) + 1;
			end if;
			pos_denominator := denominator;
			if denominator(8) = '1' then
				if negative = '1' then
					negative := '0';
				else
					negative := '1';
				end if;
				pos_denominator := not(denominator) + 1;
			end if;
			numerator_var := "00000000" & unsigned(pos_numerator);
			denominator_var := "000" & unsigned(pos_denominator) & "00000000000000";
			result_shift := (others => '0');
			done <= '0';
			
			counter := "01111";
		elsif rising_edge(clk) then
			if counter /= "00000" then
				for i in 1 to 3
				loop
					subtract_var := signed(numerator_var) - signed(denominator_var);
					if subtract_var(25) = '1' then
						result_shift(17 downto 0) := result_shift(16 downto 0) & '0';
					else
						result_shift(17 downto 0) := result_shift(16 downto 0) & '1';
						numerator_var := unsigned(subtract_var);
					end if;
					denominator_var(25 downto 0) := '0' & denominator_var(25 downto 1);
				end loop;
				counter := counter - 3;
			end if;
			if counter = "00000" then
				done <= '1';
			else
				done <= '0';
			end if;
			if negative = '1' then
				result <= not(result_shift) + 1;
			else
				result <= result_shift;
			end if;
		end if;
	end process;
end rtl;