----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    12:53:25 11/19/2008 
-- Design Name: 
-- Module Name:    divider - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-- DIV_WIDTH is width of binary divisor and dividend. ITER_REG_WIDTH is register width constant
-- of register used in multiple iterations carried out by state machine. It needs to be 
-- wide enough to hold the value DIV_WIDTH+1. start is an input triggering the start of the 
-- division operation. dvsr, dvnd are DIV_WIDTH bits wide for divisor and dividend. ready is
-- output signal indicating another division operation can be carried out. done_tick is
-- one clock cycle wide pulse indicating division is complete. quo and rmd are quotient
-- and remainder of division
entity Divider is
   generic(
      DIV_WIDTH: integer:= 8;
      ITER_REG_WIDTH: integer:= 4
   );
   port(
      clk, reset: in std_logic;
      start: in std_logic;
      dvsr, dvnd: in std_logic_vector(DIV_WIDTH-1 downto 0);
      ready, done_tick: out std_logic;
      quo, rmd: out std_logic_vector(DIV_WIDTH-1 downto 0)
   );
end Divider;

architecture beh of Divider is
   type state_type is (idle, op, last, done);
   signal state_reg, state_next: state_type;

-- dividend register + left extended 0's
   signal rh_reg, rh_next: unsigned(DIV_WIDTH-1 downto 0);
   signal rl_reg, rl_next: std_logic_vector(DIV_WIDTH-1 downto 0);

-- signal to represent output of data path operation that passes or subtracts
   signal rh_tmp: unsigned(DIV_WIDTH-1 downto 0);

-- divisor register
   signal d_reg, d_next: unsigned(DIV_WIDTH-1 downto 0);

-- iteration register
   signal n_reg, n_next: unsigned(ITER_REG_WIDTH-1 downto 0);

-- quotient bit for each iteration
   signal q_bit: std_logic;
   begin

-- state and register logic
   process(clk, reset)
      begin
      if (reset = '1') then
         state_reg <= idle;
         rh_reg <= (others => '0');
         rl_reg <= (others => '0');
         d_reg <= (others => '0');
         n_reg <= (others => '0');
      elsif (clk'event and clk = '1') then
         state_reg <= state_next;
         rh_reg <= rh_next;
         rl_reg <= rl_next;
         d_reg <= d_next;
         n_reg <= n_next;
      end if; 
   end process;

-- Combo logic for state machine, iteration cnter and shift operations in data path
   process(state_reg, n_reg, rh_reg, rl_reg, d_reg, start, dvsr, dvnd, q_bit, 
      rh_tmp, n_next)
      begin
      ready <= '0';
      done_tick <= '0';
      state_next <= state_reg;
      rh_next <= rh_reg;
      rl_next <= rl_reg;
      d_next <= d_reg;
      n_next <= n_reg;

      case state_reg is
         when idle =>

-- set output 'ready' in idle state -- otherwise, we are carrying out division
            ready <= '1';
            if (start = '1') then

-- latch dividend -- rh hold '0's. Quotient will be shifted into rl.
               rh_next <= (others => '0');
               rl_next <= dvnd;

-- latch divisor 
               d_next <= unsigned(dvsr);

-- loop counter initialized to the value (DIV_WIDTH+1), e.g., 9
               n_next <= to_unsigned(DIV_WIDTH+1, ITER_REG_WIDTH);

-- start division
               state_next <= op;
            end if;

         when op =>

-- shift rh and rl left one position
            rl_next <= rl_reg(DIV_WIDTH-2 downto 0) & q_bit;

-- rh_tmp is determined below as 'rh_reg' or 'rh_reg minus divisor'
            rh_next <= rh_tmp(DIV_WIDTH-2 downto 0) & rl_reg(DIV_WIDTH-1);
            n_next <= n_reg - 1;

-- Last iteration is special
            if (n_next = 1) then
               state_next <= last;
            end if;

-- don't shift rh_next on last iteration
         when last =>
            rl_next <= rl_reg(DIV_WIDTH-2 downto 0) & q_bit;
            rh_next <= rh_tmp;
            state_next <= done;

         when done =>
            state_next <= idle;
            done_tick <= '1';
      end case;
   end process;

-- subtract data path operations
   process (rh_reg, d_reg)
      begin

-- if portion of dividend is greater than or equal to divisor, subtract it and set
-- q_bit to 1
      if (rh_reg >= d_reg) then
         rh_tmp <= rh_reg - d_reg;
         q_bit <= '1';

-- else perserve rh_reg
      else
         rh_tmp <= rh_reg;
         q_bit <= '0';
      end if;
   end process;

-- assign quotient and remainder to output
   quo <= rl_reg;
   rmd <= std_logic_vector(rh_reg); 
end beh;
