-- ==============================================================
-- FILE : variableCoefficientImageFunctions.VHD
--          may be modified by the USER
-- ==============================================================
--
-- This file is part of the Image Processing Demo, for the HERON-
-- FPGA14 module.
--
-- This file may be modified by the users to implement their
-- own logic.
--
-- ==============================================================
--
--  Ver     Modified By      Date      Changes
--  ---     -----------      ----      -------
--  1.0     R. Williams    06-04-06    Taken from FPGA12 Example.
--
-- ==============================================================


-----------------------------------------------------------------
--                                                             --
--  Notes: By setting the synchronous generic option to        --
--  TRUE the image block will act synchronously, if it         --
--  is set to false then the block will act asynchronously.    --
--                                                             --
--  The N option sets the data width for the component.        --
--                                                             --
-----------------------------------------------------------------


--Function ADDIMAGE
library IEEE;
  use IEEE.STD_LOGIC_1164.ALL;
  use IEEE.STD_LOGIC_ARITH.ALL;
  use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ADDImage is
  generic (
    N : integer := 32
  );
  port (
    DATA_A     : in  std_logic_vector(N - 1 downto 0);
    DATA_OUT   : out std_logic_vector(N - 1 downto 0);
    DVALID_A   : in  std_logic;
    DVALID_OUT : out std_logic;
    CLOCK      : in  std_logic;
    RESET      : in  std_logic;
    EOL_IN     : in  std_logic;
    EOL_OUT    : out std_logic;
    EOF_IN     : in  std_logic;
    EOF_OUT    : out std_logic;
    REQ_PIXEL  : out std_logic;
    DATA_B     : in  std_logic_vector(N - 1 downto 0)
  );
end ADDImage;

architecture Behavioral of ADDImage is

signal DATA_A_DELAY : std_logic_vector(N - 1 downto 0);
signal DVALID_DELAY : std_logic_vector(1 downto 0);
signal EOF_DELAY    : std_logic_vector(1 downto 0);
signal EOL_DELAY    : std_logic_vector(1 downto 0);
signal TEMP_A       : std_logic_vector(N downto 0);
signal TEMP_B       : std_logic_vector(N downto 0);
signal TEMP_C       : std_logic_vector(N downto 0);
signal TEMP_D       : std_logic_vector(N - 1 downto 0);
signal TEMP_E       : std_logic_vector(N - 1 downto 0);

begin

  TEMP_A <= '0' & DATA_A_DELAY;
  TEMP_B <= '0' & DATA_B;
  TEMP_C <= TEMP_A + TEMP_B;
  TEMP_D <= (others=>'1');
  TEMP_E <= TEMP_C(N - 1 downto 0) when TEMP_C(N)='0' else TEMP_D;

  process(RESET, CLOCK)
    begin
    if RESET = '1' then
      DATA_OUT     <= (others=>'0');
      DVALID_OUT   <= '0';
      EOL_OUT      <= '0';
      EOF_OUT      <= '0';
      REQ_PIXEL    <= '0';
      DVALID_DELAY <= "00";
      EOL_DELAY    <= "00";
      EOF_DELAY    <= "00";
    elsif rising_edge(CLOCK) then
      REQ_PIXEL <= '0';
      if DVALID_A = '1' then
        REQ_PIXEL <= '1';
      end if;
      DVALID_DELAY <= DVALID_A & DVALID_DELAY(1);
      EOL_DELAY    <= EOL_IN & EOL_DELAY(1);
      EOF_DELAY    <= EOF_IN & EOF_DELAY(1);
      DVALID_OUT   <= DVALID_DELAY(0);
      EOL_OUT      <= EOL_DELAY(0);
      EOF_OUT      <= EOF_DELAY(0);
      DATA_A_DELAY <= DATA_A;
      DATA_OUT     <= TEMP_E;
    end if;
  end process;

end Behavioral;
-----------------------------------------------------------------

--Function ANDIMAGE
library IEEE;
  use IEEE.STD_LOGIC_1164.ALL;
  use IEEE.STD_LOGIC_ARITH.ALL;
  use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ANDIMAGE is
  generic (
    N : integer := 32
  );
  port (
    DATA_A     : in  std_logic_vector(N - 1 downto 0);
    DATA_OUT   : out std_logic_vector(N - 1 downto 0);
    DVALID_A   : in  std_logic;
    DVALID_OUT : out std_logic;
    CLOCK      : in  std_logic;
    RESET      : in  std_logic;
    EOL_IN     : in  std_logic;
    EOL_OUT    : out std_logic;
    EOF_IN     : in  std_logic;
    EOF_OUT    : out std_logic;
    REQ_PIXEL  : out std_logic;
    DATA_B     : in  std_logic_vector(N - 1 downto 0)
  );
end ANDIMAGE;


architecture Behavioral of ANDIMAGE is

  signal DATA_TEMP    : std_logic_vector(N - 1 downto 0);
  signal DATA_A_DELAY : std_logic_vector(N - 1 downto 0);
  signal DVALID_DELAY : std_logic_vector(1 downto 0);
  signal EOF_DELAY    : std_logic_vector(1 downto 0);
  signal EOL_DELAY    : std_logic_vector(1 downto 0);

begin

  DATA_TEMP <= DATA_A_DELAY and DATA_B;

  process(RESET, CLOCK)
  begin
    if RESET = '1' then
      DATA_OUT     <= (others=>'0');
      DVALID_OUT   <= '0';
      EOL_OUT      <= '0';
      EOF_OUT      <= '0';
      REQ_PIXEL    <= '0';
      DVALID_DELAY <= "00";
      EOL_DELAY    <= "00";
      EOF_DELAY    <= "00";
    elsif rising_edge(CLOCK) then
      REQ_PIXEL <= '0';
      if DVALID_A = '1' then
        REQ_PIXEL <= '1';
      end if;
      DVALID_DELAY <= DVALID_A & DVALID_DELAY(1);
      EOL_DELAY    <= EOL_IN & EOL_DELAY(1);
      EOF_DELAY    <= EOF_IN & EOF_DELAY(1);
      DVALID_OUT   <= DVALID_DELAY(0);
      EOL_OUT      <= EOL_DELAY(0);
      EOF_OUT      <= EOF_DELAY(0);
      DATA_A_DELAY <= DATA_A;
      DATA_OUT     <= DATA_TEMP;
    end if;
  end process;

end Behavioral;
-----------------------------------------------------------------

--Function ORImage
library IEEE;
  use IEEE.STD_LOGIC_1164.ALL;
  use IEEE.STD_LOGIC_ARITH.ALL;
  use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ORImage is
  generic (
    N : integer := 32
  );
  port (
    DATA_A     : in  std_logic_vector(N - 1 downto 0);
    DATA_OUT   : out std_logic_vector(N - 1 downto 0);
    DVALID_A   : in  std_logic;
    DVALID_OUT : out std_logic;
    CLOCK      : in  std_logic;
    RESET      : in  std_logic;
    EOL_IN     : in  std_logic;
    EOL_OUT    : out std_logic;
    EOF_IN     : in  std_logic;
    EOF_OUT    : out std_logic;
    REQ_PIXEL  : out std_logic;
    DATA_B     : in  std_logic_vector(N - 1 downto 0)
  );
end ORImage;


architecture Behavioral of ORImage is

signal DATA_TEMP    : std_logic_vector(N - 1 downto 0);
signal DATA_A_DELAY : std_logic_vector(N - 1 downto 0);
signal DVALID_DELAY : std_logic_vector(1 downto 0);
signal EOF_DELAY    : std_logic_vector(1 downto 0);
signal EOL_DELAY    : std_logic_vector(1 downto 0);

begin

  DATA_TEMP <= DATA_A_DELAY or DATA_B;

  process(RESET, CLOCK)
  begin
    if RESET = '1' then
      DATA_OUT     <= (others=>'0');
      DVALID_OUT   <= '0';
      EOL_OUT      <= '0';
      EOF_OUT      <= '0';
      REQ_PIXEL    <= '0';
      DVALID_DELAY <= "00";
      EOL_DELAY    <= "00";
      EOF_DELAY    <= "00";
    elsif rising_edge(CLOCK) then
      REQ_PIXEL <= '0';
      if DVALID_A = '1' then
        REQ_PIXEL <= '1';
      end if;
      DVALID_DELAY <= DVALID_A & DVALID_DELAY(1);
      EOL_DELAY    <= EOL_IN & EOL_DELAY(1);
      EOF_DELAY    <= EOF_IN & EOF_DELAY(1);
      DVALID_OUT   <= DVALID_DELAY(0);
      EOL_OUT      <= EOL_DELAY(0);
      EOF_OUT      <= EOF_DELAY(0);
      DATA_A_DELAY <= DATA_A;
      DATA_OUT     <= DATA_TEMP;
    end if;
  end process;

end Behavioral;
-----------------------------------------------------------------

--Function XORKImage
library IEEE;
  use IEEE.STD_LOGIC_1164.ALL;
  use IEEE.STD_LOGIC_ARITH.ALL;
  use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity XORImage is
  generic (
    N : integer := 32
  );
  port (
    DATA_A     : in  std_logic_vector(N - 1 downto 0);
    DATA_OUT   : out std_logic_vector(N - 1 downto 0);
    DVALID_A   : in  std_logic;
    DVALID_OUT : out std_logic;
    CLOCK      : in  std_logic;
    RESET      : in  std_logic;
    EOL_IN     : in  std_logic;
    EOL_OUT    : out std_logic;
    EOF_IN     : in  std_logic;
    EOF_OUT    : out std_logic;
    REQ_PIXEL  : out std_logic;
    DATA_B     : in  std_logic_vector(N - 1 downto 0)
  );
end XORImage;

architecture Behavioral of XORImage is

signal DATA_TEMP    : std_logic_vector(N - 1 downto 0);
signal DATA_A_DELAY : std_logic_vector(N - 1 downto 0);
signal DVALID_DELAY : std_logic_vector(1 downto 0);
signal EOF_DELAY    : std_logic_vector(1 downto 0);
signal EOL_DELAY    : std_logic_vector(1 downto 0);

begin

  DATA_TEMP <= DATA_A_DELAY xor DATA_B;

  process(RESET, CLOCK)
  begin
    if RESET = '1' then
      DATA_OUT     <= (others=>'0');
      DVALID_OUT   <= '0';
      EOL_OUT      <= '0';
      EOF_OUT      <= '0';
      REQ_PIXEL    <= '0';
      DVALID_DELAY <= "00";
      EOL_DELAY    <= "00";
      EOF_DELAY    <= "00";
    elsif rising_edge(CLOCK) then
      REQ_PIXEL <= '0';
      if DVALID_A = '1' then
        REQ_PIXEL <= '1';
      end if;
      DVALID_DELAY <= DVALID_A & DVALID_DELAY(1);
      EOL_DELAY    <= EOL_IN & EOL_DELAY(1);
      EOF_DELAY    <= EOF_IN & EOF_DELAY(1);
      DVALID_OUT   <= DVALID_DELAY(0);
      EOL_OUT      <= EOL_DELAY(0);
      EOF_OUT      <= EOF_DELAY(0);
      DATA_A_DELAY <= DATA_A;
      DATA_OUT     <= DATA_TEMP;
    end if;
  end process;

end Behavioral;
-----------------------------------------------------------------

--Function SUBImage
library IEEE;
  use IEEE.STD_LOGIC_1164.ALL;
  use IEEE.STD_LOGIC_ARITH.ALL;
  use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity SUBImage is
  generic (
    StopAtZero : boolean := True;
    N          : integer := 32
  );
  port (
    DATA_A     : in  std_logic_vector(N - 1 downto 0);
    DATA_OUT   : out std_logic_vector(N - 1 downto 0);
    DVALID_A   : in  std_logic;
    DVALID_OUT : out std_logic;
    CLOCK      : in  std_logic;
    RESET      : in  std_logic;
    EOL_IN     : in  std_logic;
    EOL_OUT    : out std_logic;
    EOF_IN     : in  std_logic;
    EOF_OUT    : out std_logic;
    REQ_PIXEL  : out std_logic;
    DATA_B     : in  std_logic_vector(N - 1 downto 0));
end SUBImage;

architecture Behavioral of SUBImage is

signal DATA_TEMP    : std_logic_vector(N - 1 downto 0);
signal DATA_A_DELAY : std_logic_vector(N - 1 downto 0);
signal DVALID_DELAY : std_logic_vector(1 downto 0);
signal EOF_DELAY    : std_logic_vector(1 downto 0);
signal EOL_DELAY    : std_logic_vector(1 downto 0);

begin

  DATA_TEMP <= DATA_A_DELAY - DATA_B;

  process(RESET, CLOCK)
    begin
    if RESET = '1' then
      DATA_OUT     <= (others=>'0');
      DVALID_OUT   <= '0';
      EOL_OUT      <= '0';
      EOF_OUT      <= '0';
      REQ_PIXEL    <= '0';
      DVALID_DELAY <= "00";
      EOL_DELAY    <= "00";
      EOF_DELAY    <= "00";
    elsif rising_edge(CLOCK) then
      REQ_PIXEL <= '0';
      if DVALID_A = '1' then
        REQ_PIXEL <= '1';
      end if;
      DVALID_DELAY <= DVALID_A & DVALID_DELAY(1);
      EOL_DELAY    <= EOL_IN & EOL_DELAY(1);
      EOF_DELAY    <= EOF_IN & EOF_DELAY(1);
      DVALID_OUT   <= DVALID_DELAY(0);
      EOL_OUT      <= EOL_DELAY(0);
      EOF_OUT      <= EOF_DELAY(0);
      DATA_A_DELAY <= DATA_A;
      if StopAtZero = True then
        if DATA_A_DELAY >= DATA_B then
          DATA_OUT <= DATA_TEMP;
        else
          DATA_OUT <= (others=>'0');
        end if;
      else
        DATA_OUT <= DATA_TEMP;
      end if;
    end if;
  end process;
end Behavioral;
-----------------------------------------------------------------

--Function MPYImage
library IEEE;
  use IEEE.STD_LOGIC_1164.ALL;
  use IEEE.STD_LOGIC_ARITH.ALL;
  use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity MPYImage is
  generic (
    N : integer := 18
  );
  port (
    DATA_A     : in  std_logic_vector(N - 1 downto 0);
    DATA_OUT   : out std_logic_vector(N - 1 downto 0);
    DVALID_A   : in  std_logic;
    DVALID_OUT : out std_logic;
    CLOCK      : in  std_logic;
    RESET      : in  std_logic;
    EOL_IN     : in  std_logic;
    EOL_OUT    : out std_logic;
    EOF_IN     : in  std_logic;
    EOF_OUT    : out std_logic;
    REQ_PIXEL  : out std_logic;
    DATA_B     : in  std_logic_vector(N - 1 downto 0)
  );
end MPYImage;

architecture Behavioral of MPYImage is

signal DATA_IN_A    : std_logic_vector(N - 1 downto 0);
signal DATA_A_DELAY : std_logic_vector(N - 1 downto 0);
signal DATA_IN_B    : std_logic_vector(N - 1 downto 0);
signal DATA_TEMP    : signed((N * 2) - 1 downto 0);
signal DVALID_DELAY : std_logic_vector(5 downto 0);
signal EOL_DELAY    : std_logic_vector(5 downto 0);
signal EOF_DELAY    : std_logic_vector(5 downto 0);

signal TEMP_B       : std_logic_vector(N downto 0);
signal TEMP_C       : std_logic_vector(N downto 0);
signal DATA_A_OUT   : signed((N * 2)- 1 downto 0);
signal DATA_B_OUT   : std_logic_vector((N * 2) - 1 downto 0);
signal DATA_C_OUT   : std_logic_vector((N * 2) - 1 downto 0);
signal DATA_D_OUT   : std_logic_vector((N * 2) - 1 downto 0);
signal DATA_E_OUT   : std_logic_vector((N * 2) - 1 downto 0);
signal DATA_F_OUT   : std_logic_vector(47 downto 0);
signal DATA_G_OUT   : std_logic_vector(63 downto 0);

component multi24x24
  port (
    clk : in  std_logic;
    a   : in  std_logic_vector(23 downto 0);
    b   : in  std_logic_vector(23 downto 0);
    q   : out std_logic_vector(47 downto 0));
end component;

component multi32x32
  port (
    clk : in  std_logic;
    a   : in  std_logic_vector(31 downto 0);
    b   : in  std_logic_vector(31 downto 0);
    q   : out std_logic_vector(63 downto 0));
end component;

begin

SyncMult18x18 : if (N <= 17) generate

  TEMP_B <= '0' & DATA_IN_A;
  TEMP_C <= '0' & DATA_IN_B;

  DATA_A_OUT <= signed(TEMP_B) * signed(TEMP_C);

  DATA_D_OUT((N * 2) - 1 downto N + 1) <= (others=>'0');
  DATA_D_OUT(N) <= '1';
  DATA_D_OUT(N - 1 downto 0) <= (others=>'0');

  DATA_E_OUT((N * 2) - 1 downto N) <= (others=>'0');
  DATA_E_OUT(N - 1 downto 0) <= (others=>'1');

  DATA_B_OUT <= std_logic_vector(unsigned(DATA_A_OUT));
  DATA_C_OUT <= DATA_B_OUT when DATA_B_OUT < DATA_D_OUT else DATA_E_OUT;

  process(CLOCK, RESET)
  begin
    if RESET = '1' then
      REQ_PIXEL    <= '0';
      DATA_IN_A    <= (others=>'0');
      DATA_IN_B    <= (others=>'0');
      EOF_DELAY    <= (others=>'0');
      EOL_DELAY    <= (others=>'0');
      DVALID_DELAY <=(others=>'0');
      DATA_TEMP    <= (others=>'0');
    elsif rising_edge(CLOCK) then
      REQ_PIXEL <= '0';
      if DVALID_A='1' then
        REQ_PIXEL <= '1';
      end if;
      DATA_A_DELAY             <= DATA_A;
      DATA_IN_B                <= DATA_B;
      EOF_DELAY(2 downto 0)    <= EOF_IN & EOF_DELAY(2 downto 1); 
      EOL_DELAY(2 downto 0)    <= EOL_IN & EOL_DELAY(2 downto 1); 
      DVALID_DELAY(2 downto 0) <= DVALID_A & DVALID_DELAY (2 downto 1);
      DATA_IN_A                <= DATA_A_DELAY;
      DATA_OUT                 <= DATA_C_OUT(N - 1 downto 0);
      EOF_OUT                  <= EOF_DELAY(0);
      EOL_OUT                  <= EOL_DELAY(0); 
      DVALID_OUT               <= DVALID_DELAY(0);
    end if;
  end process;
end generate;

SyncMult24x24 : if(N <=24 and N > 17) generate

  TEMP_B <= '0' & DATA_A;
  TEMP_C <= '0' & DATA_B;

  i24x24multi : multi24x24
    port map (
      clk => CLOCK,
      a   => TEMP_C,
      b   => TEMP_B,
      q   => DATA_F_OUT );

  DATA_D_OUT((N * 2) - 1 downto N + 1) <= (others=>'0');
  DATA_D_OUT(N) <= '1';
  DATA_D_OUT(N - 1 downto 0) <= (others=>'0');

  DATA_E_OUT((N * 2) - 1 downto N) <= (others=>'0');
  DATA_E_OUT(N - 1 downto 0) <= (others=>'1');

  DATA_B_OUT <= DATA_F_OUT((N * 2) - 1 downto 0);
  DATA_C_OUT <= DATA_B_OUT when DATA_B_OUT < DATA_D_OUT else DATA_E_OUT;

  DATA_OUT   <= DATA_C_OUT(N - 1 downto 0);

  process(CLOCK)
  begin
    if rising_edge(CLOCK) then
      REQ_PIXEL <= '0';
      if DVALID_A='1' then
        REQ_PIXEL <= '1';
      end if;
      DVALID_DELAY <= DVALID_A & DVALID_DELAY(5 downto 1);
      EOF_DELAY    <= EOF_IN & EOF_DELAY(5 downto 1);
      EOL_DELAY    <= EOL_IN & EOL_DELAY(5 downto 1);
      DVALID_OUT   <= DVALID_DELAY(0);
      EOL_OUT      <= EOL_DELAY(0);
      EOF_OUT      <= EOF_DELAY(0);
    end if;
  end process;
end generate;

SyncMult32x32 : if(N <=31 and N > 23) generate

  TEMP_B <= '0' & DATA_A;
  TEMP_C <= '0' & DATA_B;

  i32x32multi : multi32x32
    port map (
      clk => CLOCK,
      a   => TEMP_C,
      b   => TEMP_B,
      q   => DATA_G_OUT );

  DATA_D_OUT((N * 2) - 1 downto N + 1) <= (others=>'0');
  DATA_D_OUT(N) <= '1';
  DATA_D_OUT(N - 1 downto 0) <= (others=>'0');

  DATA_E_OUT((N * 2) - 1 downto N) <= (others=>'0');
  DATA_E_OUT(N - 1 downto 0) <= (others=>'1');

  DATA_B_OUT <= DATA_G_OUT((N * 2) - 1 downto 0);
  DATA_C_OUT <= DATA_B_OUT when DATA_B_OUT < DATA_D_OUT else DATA_E_OUT;

  DATA_OUT   <= DATA_C_OUT(N - 1 downto 0);

  process(CLOCK)
  begin
    if rising_edge(CLOCK) then
      DVALID_DELAY <= DVALID_A & DVALID_DELAY(5 downto 1);
      EOF_DELAY    <= EOF_IN & EOF_DELAY(5 downto 1);
      EOL_DELAY    <= EOL_IN & EOL_DELAY(5 downto 1);
      DVALID_OUT   <= DVALID_DELAY(0);
      EOL_OUT      <= EOL_DELAY(0);
      EOF_OUT      <= EOF_DELAY(0);
    end if;
  end process;
end generate;

end Behavioral;

