-- MSS copyright 2013
-- Filename: DIVIDER.VHD
-- Author: Alain Zarembowitch / MSS
-- Edit date: 4/14/13
-- Revision: 0
-- Inheritance: N/A
--
-- Description:  Pipelined divider. Inputs are positive.
-- Non-restoring division algorithm, Nbits precision.
----------------------------------------------      
library IEEE;
use IEEE.std_logic_1164.all; 
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity DIVIDER is
	generic (
		NBITS: integer := 14
	);
	port (  
		CLK: in std_logic;
			-- reference clock for synchronous design

	  	--// INPUTS
		NUM: in std_logic_vector((NBITS-1) downto 0);
			-- numerator, unsigned.
		DENOM: in std_logic_vector((NBITS-1) downto 0);
			-- denominator, unsigned.
		SAMPLE_CLK_IN: in std_logic;
			-- 1 CLK-wide pulse to start the division.
			-- ignored if previous division is in progress
			
		--// OUTPUTS
		QUOTIENT: out std_logic_vector((NBITS-1) downto 0);
		REMAINDER: out std_logic_vector((NBITS-1) downto 0);
		SAMPLE_CLK_OUT: out std_logic
			-- read result at the rising edge of CLK when SAMPLE_CLK_OUT = '1'
 );
end entity;  

architecture behavioral of DIVIDER is
-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------
-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
signal CNTR: integer range 0 to (NBITS+1) := 0;
signal REG_A: std_logic_vector((NBITS-1) downto 0) := (others => '0'); 
signal REG_B: std_logic_vector((NBITS-1) downto 0) := (others => '0'); 
signal REG_P: std_logic_vector((NBITS-1) downto 0) := (others => '0'); 
signal REG_P_SHIFTED: std_logic_vector((NBITS-1) downto 0) := (others => '0'); 
signal NEW_REG_P: std_logic_vector((NBITS-1) downto 0) := (others => '0'); 
-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin   

-- state counter. Decrements from NBITS to 0 (idle/done)
CNTR_GEN_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN = '1') and (CNTR = 0) then
			-- re-arm CNTR, ignore new request if previous division is in progress
			CNTR <= NBITS+1;
		elsif(CNTR /= 0) then
			-- decrement CNTR until completion (0)
			CNTR <= CNTR - 1;
		end if;
	end if;
end process;

DIVIDE_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN = '1') and (CNTR = 0) then
			REG_P <= (others => '0');
			REG_A <= NUM;
			REG_B <= DENOM;
		elsif(CNTR > 1) then
			REG_P <= NEW_REG_P;

			-- new P is positive -> set low-order bit of A to 1, otherwise to 0
			REG_A <= REG_A((NBITS-2) downto 0) & (not NEW_REG_P(NBITS-1));
		end if;
	end if;
end process;

-- shift the register pair (P,A) one bit to the left
REG_P_SHIFTED <= REG_P((NBITS-2) downto 0) & REG_A((NBITS-1));

-- new REG_P
-- shifted P is positive -> subtract the contents of register B to P, otherwise add
NEW_REG_P <= (REG_P_SHIFTED - REG_B) when (REG_P_SHIFTED(NBITS-1) = '0') else (REG_P_SHIFTED + REG_B);

-- final step
-- If P is negative, add B to it
FINAL_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(CNTR = 1) then
			SAMPLE_CLK_OUT <= '1';
			QUOTIENT <= REG_A;
			if(REG_P(NBITS-1) = '0') then
				REMAINDER <= REG_P;
			else
				REMAINDER <= REG_P + REG_B;
			end if;
		else
			SAMPLE_CLK_OUT <= '0';
		end if;
	end if;
end process;


end architecture;
