-- Kyle McGhee
-- kmcghee@purdue.edu
-- divide_8bit.vhd

-- This module performs unsigned 8-bit fixed point division.
-- It is purely dataflow and will finish in a single clock cycle.

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity divide_8bit is
  port (
    X: in STD_LOGIC_VECTOR(7 downto 0);
    Y: in STD_LOGIC_VECTOR(7 downto 0);

    Z: out STD_LOGIC_VECTOR(14 downto 0));
end divide_8bit;

-- X:       8.0
-- Y:       8.0
-- Z = X/Y: 8.8

-- Division is a fairly complicated purely dataflow module.
-- It performs a series of checks and possible shifts and subtracts in stages.

architecture divide_8bit_arch of divide_8bit is
  constant ZERO: STD_LOGIC_VECTOR(14 downto 0) := "000000000000000";

  signal T: STD_LOGIC_VECTOR(14 downto 0);

  signal STAGE_1: UNSIGNED(14 downto 0);
  signal STAGE_2: UNSIGNED(14 downto 0);
  signal STAGE_3: UNSIGNED(14 downto 0);
  signal STAGE_4: UNSIGNED(14 downto 0);
  signal STAGE_5: UNSIGNED(14 downto 0);
  signal STAGE_6: UNSIGNED(14 downto 0);
  signal STAGE_7: UNSIGNED(14 downto 0);
  signal STAGE_8: UNSIGNED(14 downto 0);
  signal STAGE_9: UNSIGNED(14 downto 0);
  signal STAGE_10: UNSIGNED(14 downto 0);
  signal STAGE_11: UNSIGNED(14 downto 0);
  signal STAGE_12: UNSIGNED(14 downto 0);
  signal STAGE_13: UNSIGNED(14 downto 0);
  signal STAGE_14: UNSIGNED(14 downto 0);
begin
  T(14) <= '1' when (UNSIGNED(X & ZERO(14 downto 8)) >= UNSIGNED(Y(0) & ZERO(14 downto 1))) and (Y(7 downto 1) = ZERO(7 downto 1)) else '0';

  T(13) <= '1' when (STAGE_1  >= UNSIGNED(Y(1 downto 0) & ZERO(14 downto 2))) and (Y(7 downto 2) = ZERO(7 downto 2)) else '0';
  T(12) <= '1' when (STAGE_2  >= UNSIGNED(Y(2 downto 0) & ZERO(14 downto 3))) and (Y(7 downto 3) = ZERO(7 downto 3)) else '0';
  T(11) <= '1' when (STAGE_3  >= UNSIGNED(Y(3 downto 0) & ZERO(14 downto 4))) and (Y(7 downto 4) = ZERO(7 downto 4)) else '0';
  T(10) <= '1' when (STAGE_4  >= UNSIGNED(Y(4 downto 0) & ZERO(14 downto 5))) and (Y(7 downto 5) = ZERO(7 downto 5)) else '0';
  T( 9) <= '1' when (STAGE_5  >= UNSIGNED(Y(5 downto 0) & ZERO(14 downto 6))) and (Y(7 downto 6) = ZERO(7 downto 6)) else '0';

  T( 8) <= '1' when (STAGE_6  >= UNSIGNED(Y(6 downto 0) & ZERO(14 downto 7))) and (Y(7) = ZERO(7)) else '0';
  T( 7) <= '1' when (STAGE_7  >= UNSIGNED(Y & ZERO(14 downto 8))) else '0';
  T( 6) <= '1' when (STAGE_8  >= UNSIGNED(ZERO(0) & Y & ZERO(14 downto 9))) else '0';-- and (Y(7 downto 1) /= ZERO(7 downto 1)) else '0';

  T( 5) <= '1' when (STAGE_9  >= UNSIGNED(ZERO(1 downto 0) & Y & ZERO(14 downto 10))) else '0';-- and (Y(7 downto 2) /= ZERO(7 downto 2)) else '0';
  T( 4) <= '1' when (STAGE_10 >= UNSIGNED(ZERO(2 downto 0) & Y & ZERO(14 downto 11))) else '0';-- and (Y(7 downto 3) /= ZERO(7 downto 3)) else '0';
  T( 3) <= '1' when (STAGE_11 >= UNSIGNED(ZERO(3 downto 0) & Y & ZERO(14 downto 12))) else '0';-- and (Y(7 downto 4) /= ZERO(7 downto 4)) else '0';
  T( 2) <= '1' when (STAGE_12 >= UNSIGNED(ZERO(4 downto 0) & Y & ZERO(14 downto 13))) else '0';-- and (Y(7 downto 5) /= ZERO(7 downto 5)) else '0';
  T( 1) <= '1' when (STAGE_13 >= UNSIGNED(ZERO(5 downto 0) & Y & ZERO(14))) else '0';-- and (Y(7 downto 6) /= ZERO(7 downto 6)) else '0';
  T( 0) <= '1' when (STAGE_14 >= UNSIGNED(ZERO(6 downto 0) & Y)) else '0';-- and (Y(7) /= ZERO(7)) else '0';

  STAGE_1  <= (UNSIGNED(X & ZERO(14 downto 8)) - UNSIGNED(Y(0) & ZERO(14 downto 1))) when (T(14) = '1') else UNSIGNED(X & ZERO(14 downto 8));

  STAGE_2  <= (STAGE_1 - UNSIGNED(Y(1 downto 0) & ZERO(14 downto 2))) when (T(13) = '1') else STAGE_1;
  STAGE_3  <= (STAGE_2 - UNSIGNED(Y(2 downto 0) & ZERO(14 downto 3))) when (T(12) = '1') else STAGE_2;
  STAGE_4  <= (STAGE_3 - UNSIGNED(Y(3 downto 0) & ZERO(14 downto 4))) when (T(11) = '1') else STAGE_3;
  STAGE_5  <= (STAGE_4 - UNSIGNED(Y(4 downto 0) & ZERO(14 downto 5))) when (T(10) = '1') else STAGE_4;
  STAGE_6  <= (STAGE_5 - UNSIGNED(Y(5 downto 0) & ZERO(14 downto 6))) when (T(9) = '1') else STAGE_5;

  STAGE_7  <= (STAGE_6 - UNSIGNED(Y(6 downto 0) & ZERO(14 downto 7))) when (T(8) = '1') else STAGE_6;
  STAGE_8  <= (STAGE_7 - UNSIGNED(Y & ZERO(14 downto 8))) when (T(7) = '1') else STAGE_7;
  STAGE_9  <= (STAGE_8 - UNSIGNED(ZERO(0) & Y & ZERO(14 downto 9))) when (T(6) = '1') else STAGE_8;

  STAGE_10 <= (STAGE_9 - UNSIGNED(ZERO(1 downto 0) & Y & ZERO(14 downto 10))) when (T(5) = '1') else STAGE_9;
  STAGE_11 <= (STAGE_10 - UNSIGNED(ZERO(2 downto 0) & Y & ZERO(14 downto 11))) when (T(4) = '1') else STAGE_10;
  STAGE_12 <= (STAGE_11 - UNSIGNED(ZERO(3 downto 0) & Y & ZERO(14 downto 12))) when (T(3) = '1') else STAGE_11;
  STAGE_13 <= (STAGE_12 - UNSIGNED(ZERO(4 downto 0) & Y & ZERO(14 downto 13))) when (T(2) = '1') else STAGE_12;
  STAGE_14 <= (STAGE_13 - UNSIGNED(ZERO(5 downto 0) & Y & ZERO(14))) when (T(1) = '1') else STAGE_13;

  -- The result is the last (middle) 8 bits
  Z <= T;
end divide_8bit_arch;
