-- ==============================================================
-- FILE : CAMERA.VHD  -  May be modified by the USER
-- ==============================================================
--
-- This file is part of the CameraLink IP for HERON-FPGA modules.
--
-- This file can be copied into a new project and modified by the
-- user to implement their own logic.
--
-- ==============================================================
--
--  Date        : 12/06/2006
--  Author      : R. Williams - HUNT ENGINEERING
--  Description : Components for camera data capture and processing
--
-- ==============================================================
--
--  Ver     Modified By      Date      Changes
--  ---     -----------      ----      -------
--  1.0     R. Williams    12-06-06    Developed from previous
--                                     Camera Link examples.
--  3.1     R. Williams    07-09-07    Changes to CamLink_IF.vhd
--                                     to ensure correct operation
--                                     under ISE9.1.
--
-- ==============================================================



-- ==============================================================
--  Module      : FRAME_CONTROL
--  Description : Frame output control

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

-- synopsys translate_off
library UNISIM;
  use UNISIM.vcomponents.all;
-- synopsys translate_on

entity FRAME_CONTROL is
  port (
    RESET       : in  std_logic;
    PIXEL_CLOCK : in  std_logic;
    CONTINUOUS  : in  std_logic;
    DVALID_IN   : in  std_logic;
    EOL_IN      : in  std_logic;
    EOF_IN      : in  std_logic;
    DVALID_OUT  : out std_logic;
    EOL_OUT     : out std_logic;
    EOF_OUT     : out std_logic;
    LOAD        : in  std_logic;
    FRAMES      : in  std_logic_vector(3 downto 0);
    DATA_IN     : in  std_logic_vector(31 downto 0);
    DATA_OUT    : out std_logic_vector(31 downto 0)
  );
end FRAME_CONTROL;

architecture RTL of FRAME_CONTROL is

  signal count  : unsigned(3 downto 0);
  signal RUN    : std_logic;
  signal UPDATE : std_logic;
  signal ACTIVE : std_logic;

begin

  EOL_OUT <= EOL_IN AND RUN;
  EOF_OUT <= EOF_IN AND RUN;

  DVALID_OUT <= DVALID_IN AND RUN;

  DATA_OUT <= DATA_IN;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      UPDATE <= '0';
      ACTIVE <= '0';
    elsif rising_edge(PIXEL_CLOCK) then
      UPDATE <= '0';
      ACTIVE <= '0';
      if (EOF_IN='1' or (UPDATE='1' and DVALID_IN='0')) then
        UPDATE <= '1';
      end if;
      if (RUN='1' and UPDATE='1' and DVALID_IN='1') or
         (ACTIVE='1' and EOF_IN='0') then
        ACTIVE <='1';
      end if;
    end if;
  end process;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      count <= (others=>'0');
    elsif rising_edge(PIXEL_CLOCK) then
      if LOAD='1' then
        count <= unsigned(FRAMES(3 downto 0));
      else
        if (ACTIVE='1' and EOF_IN='1' and (count > 0)) then
          count <= count - 1;
        end if;
      end if;
    end if;
  end process;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      RUN <= '0';
    elsif rising_edge(PIXEL_CLOCK) then
      RUN <= '0';
      if (CONTINUOUS='1'                 and UPDATE='1' and DVALID_IN='0') or
         (CONTINUOUS='0' and (count > 0) and UPDATE='1' and DVALID_IN='0') or
         (RUN='1' and UPDATE='1' and DVALID_IN='1') or
         (RUN='1' and ACTIVE='1') then
        RUN <= '1';
      end if;
    end if;
  end process;

end RTL;


-- ==============================================================
--  Module      : AUTO_ROI
--  Description : Automatic Frame Size and Region-of-Interest Calculation

library IEEE;
  use IEEE.std_logic_1164.ALL;
  use IEEE.std_logic_unsigned.ALL;

-- synopsys translate_off
library UNISIM;
  use UNISIM.vcomponents.all;
-- synopsys translate_on

entity AUTO_ROI is
  port (
    RESET       : in  std_logic;
    PIXEL_CLOCK : in  std_logic;
    DVALID_IN   : in  std_logic;
    EOL_IN      : in  std_logic;
    EOF_IN      : in  std_logic;
    DATA_IN     : in  std_logic_vector(31 downto 0);
    FIRST_PIXEL : out std_logic_vector(11 downto 0);
    LAST_PIXEL  : out std_logic_vector(11 downto 0);
    FIRST_LINE  : out std_logic_vector(11 downto 0);
    LAST_LINE   : out std_logic_vector(11 downto 0);
    PIXEL_TOTAL : out std_logic_vector(11 downto 0);
    LINE_TOTAL  : out std_logic_vector(11 downto 0);
    ROI_VALID   : out std_logic
  );
end AUTO_ROI;

architecture RTL of AUTO_ROI is

  signal ROIvalid   : std_logic;
  signal FRAMEtc    : std_logic;
  signal FRAMEcount : std_logic_vector(3 downto 0);

  signal PIXELcount : std_logic_vector(11 downto 0);
  signal PIXELtotal : std_logic_vector(11 downto 0);
  signal LINEcount  : std_logic_vector(11 downto 0);
  signal LINEtotal  : std_logic_vector(11 downto 0);

  signal FIRST_A    : std_logic_vector(11 downto 0);
  signal FIRSTpixel : std_logic_vector(11 downto 0);
  signal LAST_A     : std_logic_vector(11 downto 0);
  signal LASTpixel  : std_logic_vector(11 downto 0);
  signal A          : std_logic;
  signal B          : std_logic;
  signal C          : std_logic;
  signal D          : std_logic;

  signal FIRST_B    : std_logic_vector(11 downto 0);
  signal FIRSTline  : std_logic_vector(11 downto 0);
  signal LAST_B     : std_logic_vector(11 downto 0);
  signal LASTline   : std_logic_vector(11 downto 0);
  signal E          : std_logic;
  signal F          : std_logic;
  signal G          : std_logic;
  signal H          : std_logic;

begin

  ROI_VALID <= ROIvalid;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      ROIvalid   <= '0';
      FRAMEcount <= (others=>'0');
    elsif rising_edge(PIXEL_CLOCK) then
      if EOF_IN='1' and FRAMEtc='0' then
        FRAMEcount <= FRAMEcount + 1;
      end if;
      if FRAMEtc='1' then
        ROIvalid <= '1';
      end if;
    end if;
  end process;

  FRAMEtc <= '1' when FRAMEcount = "1010" else '0';

  -- Count of total number of pixels in a line

  PIXEL_TOTAL <= PIXELtotal;

  process(PIXEL_CLOCK)
  begin
    if rising_edge(PIXEL_CLOCK) then
      if EOL_IN='1' then
        PIXELcount <= (others=>'0');
        PIXELtotal <= PIXELcount;
      elsif DVALID_IN='1' then
        PIXELcount <= PIXELcount + 1;
      end if;
    end if;
  end process;

  -- Count of total number of lines in a frame

  LINE_TOTAL <= LINEtotal;

  process(PIXEL_CLOCK)
  begin
    if rising_edge(PIXEL_CLOCK) then
      if EOF_IN='1' then
        LINEcount <= (others=>'0');
        LINEtotal <= LINEcount;
      elsif EOL_IN='1' then
        LINEcount <= LINEcount + 1;
      end if;
    end if;
  end process;

  -- First real pixel in a line

  FIRST_PIXEL <= FIRSTpixel;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      FIRST_A    <= (others=>'1');
      FIRSTpixel <= (others=>'1');
    elsif rising_edge(PIXEL_CLOCK) then
      if (A='0' and DVALID_IN='1' and (DATA_IN(4)='1' or DATA_IN(5)='1' or DATA_IN(6)='1' or DATA_IN(7)='1')) then
        FIRST_A <= PIXELcount;
      end if;
      if EOL_IN='1' then
        FIRSTpixel <= FIRST_A;
      end if;
    end if;
  end process;

  B <= '1' when PIXELcount = FIRSTpixel else '0';

  process(PIXEL_CLOCK)
  begin
    if rising_edge(PIXEL_CLOCK) then
      if EOL_IN='1' then
        A <= '0';
      elsif B='1' or (A='0' and DVALID_IN='1' and (DATA_IN(4)='1' or DATA_IN(5)='1' or DATA_IN(6)='1' or DATA_IN(7)='1')) then
        A <= '1';
      end if;
    end if;
  end process;

  -- Last real pixel in a line

  LAST_PIXEL <= LASTpixel;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      LAST_A    <= (others=>'0');
      LASTpixel <= (others=>'0');
    elsif rising_edge(PIXEL_CLOCK) then
      if (C='1' and DVALID_IN='1' and (DATA_IN(4)='1' or DATA_IN(5)='1' or DATA_IN(6)='1' or DATA_IN(7)='1')) then
        LAST_A <= PIXELcount;
      end if;
      if EOL_IN='1' then
        LASTpixel <= LAST_A;
      end if;
    end if;
  end process;

  D <= '1' when PIXELcount = LASTpixel else '0';

  process(PIXEL_CLOCK)
  begin
    if rising_edge(PIXEL_CLOCK) then
      if EOL_IN='1' then
        C <= '0';
      elsif D='1' then
        C <= '1';
      end if;
    end if;
  end process;

  -- First real line in a frame

  FIRST_LINE <= FIRSTline;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      FIRST_B   <= (others=>'1');
      FIRSTline <= (others=>'1');
    elsif rising_edge(PIXEL_CLOCK) then
      if (E='0' and DVALID_IN='1' and (DATA_IN(4)='1' or DATA_IN(5)='1' or DATA_IN(6)='1' or DATA_IN(7)='1')) then
        FIRST_B <= LINEcount;
      end if;
      if EOF_IN='1' then
        FIRSTline <= FIRST_B;
      end if;
    end if;
  end process;

  F <= '1' when LINEcount = FIRSTline else '0';

  process(PIXEL_CLOCK)
  begin
    if rising_edge(PIXEL_CLOCK) then
      if EOF_IN='1' then
        E <= '0';
      elsif F='1' or (E='0' and DVALID_IN='1' and (DATA_IN(4)='1' or DATA_IN(5)='1' or DATA_IN(6)='1' or DATA_IN(7)='1')) then
        E <= '1';
      end if;
    end if;
  end process;

  -- Last real line in a frame

  LAST_LINE <= LASTline;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      LAST_B   <= (others=>'0');
      LASTline <= (others=>'0');
    elsif rising_edge(PIXEL_CLOCK) then
      if (G='1' and DVALID_IN='1' and (DATA_IN(4)='1' or DATA_IN(5)='1' or DATA_IN(6)='1' or DATA_IN(7)='1')) then
        LAST_B <= LINEcount;
      end if;
      if EOF_IN='1' then
        LASTline <= LAST_B;
      end if;
    end if;
  end process;

  H <= '1' when LINEcount = LASTline else '0';

  process(PIXEL_CLOCK)
  begin
    if rising_edge(PIXEL_CLOCK) then
      if EOF_IN='1' then
        G <= '0';
      elsif H='1' then
        G <= '1';
      end if;
    end if;
  end process;

end RTL;


-- ==============================================================
--  Module      : ROI
--  Description : Region of Interest

library IEEE;
  use IEEE.std_logic_1164.ALL;
  use IEEE.std_logic_unsigned.ALL;

-- synopsys translate_off
library UNISIM;
  use UNISIM.vcomponents.all;
-- synopsys translate_on

entity ROI is
  port (
    RESET       : in  std_logic;
    PIXEL_CLOCK : in  std_logic;
    ODD_ONLY    : in  std_logic;
    DVALID_IN   : in  std_logic;
    EOL_IN      : in  std_logic;
    EOF_IN      : in  std_logic;
    DVALID_OUT  : out std_logic;
    EOL_OUT     : out std_logic;
    EOF_OUT     : out std_logic;
    START_PIXEL : in  std_logic_vector(11 downto 0);
    STOP_PIXEL  : in  std_logic_vector(11 downto 0);
    START_LINE  : in  std_logic_vector(11 downto 0);
    STOP_LINE   : in  std_logic_vector(11 downto 0);
    DATA_IN     : in  std_logic_vector(31 downto 0);
    DATA_OUT    : out std_logic_vector(31 downto 0)
  );
end ROI;

architecture RTL of ROI is

  component PIXEL
    port (
      PIXEL_CLOCK : in  std_logic;
      PIXEL_COUNT : in  std_logic;
      LINE_RESET  : in  std_logic;
      ODD_ONLY    : in  std_logic;
      START       : in  std_logic_vector(11 downto 0);
      STOP        : in  std_logic_vector(11 downto 0);
      PIXEL_START : out std_logic;
      PIXEL_STOP  : out std_logic
    );
  end component;

  component LINE
    port (
      LINE_CLOCK  : in  std_logic;
      LINE_COUNT  : in  std_logic;
      FRAME_RESET : in  std_logic;
      ODD_ONLY    : in  std_logic;
      START       : in  std_logic_vector(11 downto 0);
      STOP        : in  std_logic_vector(11 downto 0);
      LINE_START  : out std_logic;
      LINE_STOP   : out std_logic
    );
  end component;

  signal PIXEL_START : std_logic;
  signal PIXEL_STOP  : std_logic;
  signal LINE_START  : std_logic;
  signal LINE_STOP   : std_logic;

begin

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      DVALID_OUT <= '0';
    elsif rising_edge(PIXEL_CLOCK) then
      DVALID_OUT <= '0';
      if DVALID_IN='1' and PIXEL_START='1' and PIXEL_STOP='1' and
         LINE_START='1' and LINE_STOP='1' then
        DVALID_OUT <= '1';
      end if;
    end if;
  end process;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      EOL_OUT <= '0';
    elsif rising_edge(PIXEL_CLOCK) then
      EOL_OUT <= '0';
      if EOL_IN='1' and LINE_START='1' and LINE_STOP='1' then
        EOL_OUT <= '1';
      end if;
    end if;
  end process;

  process(PIXEL_CLOCK)
  begin
    if rising_edge(PIXEL_CLOCK) then
      EOF_OUT  <= EOF_IN;
      DATA_OUT <= DATA_IN;
    end if;
  end process;

  iPIXEL : PIXEL
    port map (
      PIXEL_CLOCK => PIXEL_CLOCK,
      PIXEL_COUNT => DVALID_IN,
      LINE_RESET  => EOL_IN,
      ODD_ONLY    => ODD_ONLY,
      START       => START_PIXEL,
      STOP        => STOP_PIXEL,
      PIXEL_START => PIXEL_START,
      PIXEL_STOP  => PIXEL_STOP );

  iLINE : LINE
    port map (
      LINE_CLOCK  => PIXEL_CLOCK,
      LINE_COUNT  => EOL_IN,
      FRAME_RESET => EOF_IN,
      ODD_ONLY    => ODD_ONLY,
      START       => START_LINE,
      STOP        => STOP_LINE,
      LINE_START  => LINE_START,
      LINE_STOP   => LINE_STOP );

end RTL;


-- ==============================================================
--  Module      : PIXEL
--  Description : Pixels per line control

library IEEE;
  use IEEE.std_logic_1164.ALL;
  use IEEE.std_logic_unsigned.ALL;

-- synopsys translate_off
library UNISIM;
  use UNISIM.vcomponents.all;
-- synopsys translate_on

entity PIXEL is
  port (
    PIXEL_CLOCK : in  std_logic;
    PIXEL_COUNT : in  std_logic;
    LINE_RESET  : in  std_logic;
    ODD_ONLY    : in  std_logic;
    START       : in  std_logic_vector(11 downto 0);
    STOP        : in  std_logic_vector(11 downto 0);
    PIXEL_START : out std_logic;
    PIXEL_STOP  : out std_logic
  );
end PIXEL;

architecture RTL of PIXEL is

  component COMP12 is
    port (
      CLOCK  : in  std_logic;
      CE     : in  std_logic;
      RESET  : in  std_logic;
      A      : in  std_logic_vector(11 downto 0);
      B      : in  std_logic_vector(11 downto 0);
      A_GE_B : out std_logic;
      A_LE_B : out std_logic
    );
  end component;

  signal PIXEL      : std_logic_vector(11 downto 0);
  signal PXL_SELECT : std_logic;
  signal A_GE_B     : std_logic;
  signal CE         : std_logic;

begin

  PIXEL_START <= A_GE_B AND PXL_SELECT;

  CE <= PIXEL_COUNT OR LINE_RESET;

  iCMP0 : COMP12
    port map (
      CLOCK  => PIXEL_CLOCK,
      CE     => CE,
      RESET  => LINE_RESET,
      A      => PIXEL,
      B      => START,
      A_GE_B => A_GE_B,
      A_LE_B => open );

  iCMP1 : COMP12
    port map (
      CLOCK  => PIXEL_CLOCK,
      CE     => CE,
      RESET  => LINE_RESET,
      A      => PIXEL,
      B      => STOP,
      A_GE_B => open,
      A_LE_B => PIXEL_STOP );

  -- 12 bit pixel counter
  process(LINE_RESET, PIXEL_CLOCK)
  begin
    if LINE_RESET='1' then
      PIXEL <= (others=>'0');
    elsif rising_edge(PIXEL_CLOCK) then
      if CE='1' then
        PIXEL <= PIXEL + 1;
      end if;
    end if;
  end process;

  process(PIXEL_CLOCK)
  begin
    if rising_edge(PIXEL_CLOCK) then
      if CE='1' then
        PXL_SELECT <= '1';
        if (ODD_ONLY='1' AND PXL_SELECT='1' AND A_GE_B='1' AND LINE_RESET='0') then
          PXL_SELECT <= '0';
        end if;
      end if;
    end if;
  end process;

end RTL;


-- ==============================================================
--  Module      : LINE
--  Description : Lines per frame control

library IEEE;
  use IEEE.std_logic_1164.ALL;
  use IEEE.std_logic_unsigned.ALL;

-- synopsys translate_off
library UNISIM;
  use UNISIM.vcomponents.all;
-- synopsys translate_on

entity LINE is
  port (
    LINE_CLOCK  : in  std_logic;
    LINE_COUNT  : in  std_logic;
    FRAME_RESET : in  std_logic;
    ODD_ONLY    : in  std_logic;
    START       : in  std_logic_vector(11 downto 0);
    STOP        : in  std_logic_vector(11 downto 0);
    LINE_START  : out std_logic;
    LINE_STOP   : out std_logic
  );
end LINE;


architecture RTL of LINE is

  component COMP12 is
    port (
      CLOCK  : in  std_logic;
      CE     : in  std_logic;
      RESET  : in  std_logic;
      A      : in  std_logic_vector(11 downto 0);
      B      : in  std_logic_vector(11 downto 0);
      A_GE_B : out std_logic;
      A_LE_B : out std_logic
    );
  end component;

  signal LINE        : std_logic_vector(11 downto 0);
  signal LINE_SELECT : std_logic;
  signal A_GE_B      : std_logic;
  signal CE          : std_logic;

begin

  CE <= LINE_COUNT OR FRAME_RESET;

  LINE_START <= A_GE_B AND LINE_SELECT;

  iCMP0 : COMP12
    port map (
      CLOCK  => LINE_CLOCK,
      CE     => CE,
      RESET  => FRAME_RESET,
      A      => LINE,
      B      => START,
      A_GE_B => A_GE_B,
      A_LE_B => open );

  iCMP1 : COMP12
    port map (
      CLOCK  => LINE_CLOCK,
      CE     => CE,
      RESET  => FRAME_RESET,
      A      => LINE,
      B      => STOP,
      A_GE_B => open,
      A_LE_B => LINE_STOP );

  -- 12 bit line counter
  process(FRAME_RESET, LINE_CLOCK)
  begin
    if FRAME_RESET='1' then
      LINE <= (others=>'0');
    elsif rising_edge(LINE_CLOCK) then
      if CE='1' then
        LINE <= LINE + 1;
      end if;
    end if;
  end process;

  process(LINE_CLOCK)
  begin
    if rising_edge(LINE_CLOCK) then
      if CE='1' then
        LINE_SELECT <= '1';
        if (ODD_ONLY='1' AND LINE_SELECT='1' AND A_GE_B='1' AND FRAME_RESET='0') then
          LINE_SELECT <= '0';
        end if;
      end if;
    end if;
  end process;

end RTL;


-- ==============================================================
--  Module      : COMP12
--  Description : 12-bit comparator

library IEEE;
  use IEEE.std_logic_1164.ALL;
  use IEEE.std_logic_unsigned.ALL;

-- synopsys translate_off
library UNISIM;
  use UNISIM.vcomponents.all;
-- synopsys translate_on

entity COMP12 is
  port (
    CLOCK  : in  std_logic;
    CE     : in  std_logic;
    RESET  : in  std_logic;
    A      : in  std_logic_vector(11 downto 0);
    B      : in  std_logic_vector(11 downto 0);
    A_GE_B : out std_logic;
    A_LE_B : out std_logic
  );
end COMP12;

architecture RTL of COMP12 is

  signal A_EQ_B : std_logic;
  signal G_OR_E : std_logic;
  signal L_OR_E : std_logic;
  signal A_GT_B : std_logic;
  signal A_LT_B : std_logic;

begin

  A_GE_B <= G_OR_E;
  A_LE_B <= L_OR_E;

  A_EQ_B <= '1' when A = B else '0';

  G_OR_E <= A_EQ_B OR A_GT_B;
  L_OR_E <= A_EQ_B OR A_LT_B;

  process(CLOCK)
  begin
    if rising_edge(CLOCK) then
      if CE='1' then
        A_GT_B <= '0';
        A_LT_B <= '1';
        if  (G_OR_E='1' AND RESET='0') then
          A_GT_B <= '1';
        end if;
        if ((A_EQ_B='1' AND RESET='0')  OR
            (A_LT_B='0' AND RESET='0')) then
          A_LT_B <= '0';
        end if;
      end if;
    end if;
  end process;

end RTL;


-- ==============================================================
--  Module      : PACK_SYNC
--  Description : Data packing and synchronisation

library IEEE;
  use IEEE.std_logic_1164.ALL;

-- synopsys translate_off
library UNISIM;
  use UNISIM.vcomponents.all;
-- synopsys translate_on

entity PACK_SYNC is
  port (
    RESET       : in  std_logic;
    PIXEL_CLOCK : in  std_logic;
    M4_X_8      : in  std_logic;
    M2_X_16     : in  std_logic;
    M1_X_32     : in  std_logic;
    DVALID_IN   : in  std_logic;
    EOL_IN      : in  std_logic;
    EOF_IN      : in  std_logic;
    DVALID_OUT  : out std_logic;
    DATA_IN     : in  std_logic_vector(31 downto 0);
    DATA_OUT    : out std_logic_vector(31 downto 0)
  );
end PACK_SYNC;

architecture RTL of PACK_SYNC is

  signal S        : std_logic_vector(1 downto 0);
  signal CE       : std_logic;
  signal EN       : std_logic;
  signal SYNC     : std_logic;
  signal SYNC_DEL : std_logic;
  signal SEL_A    : std_logic;
  signal SEL_B    : std_logic;
  signal SEL_C    : std_logic;
  signal SEL_D    : std_logic;
  signal REG_A    : std_logic;
  signal REG_B    : std_logic;
  signal REG_C    : std_logic;
  signal REG_D    : std_logic;
  signal CLR_A    : std_logic;
  signal CLR_B    : std_logic;
  signal CLR_C    : std_logic;
  signal CLR_D    : std_logic;
  signal MUX_A    : std_logic_vector(7 downto 0);
  signal MUX_B    : std_logic_vector(7 downto 0);
  signal MUX_C    : std_logic_vector(7 downto 0);
  signal MUX_D    : std_logic_vector(7 downto 0);
  signal ADJUST   : std_logic_vector(7 downto 0);
  signal FR_SYNC  : std_logic_vector(7 downto 0);
  signal REG_DATA : std_logic_vector(31 downto 0);

begin

  CE <= DVALID_IN OR EOL_IN;

  REG_A <= DVALID_IN AND (NOT S(1)) AND (NOT S(0));

  REG_B <= (DVALID_IN AND (NOT M4_X_8) AND (NOT S(1)) AND (NOT S(0))) OR
           (DVALID_IN AND      M4_X_8  AND (NOT S(1)) AND      S(0) ) OR
           (   EOL_IN AND      M4_X_8  AND (NOT S(1)) AND      S(0) );

  REG_C <= (DVALID_IN AND M1_X_32 AND (NOT S(1)) AND (NOT S(0))) OR
           (DVALID_IN AND M2_X_16 AND (NOT S(1)) AND      S(0) ) OR
           (DVALID_IN AND M4_X_8  AND      S(1)  AND (NOT S(0))) OR
           (   EOL_IN AND M4_X_8  AND (NOT S(1)) AND      S(0) ) OR
           (   EOL_IN AND M4_X_8  AND      S(1)  AND (NOT S(0))) OR
           (   EOL_IN AND M2_X_16 AND (NOT S(1)) AND      S(0) );

  REG_D <= (DVALID_IN AND M1_X_32 AND (NOT S(1)) AND (NOT S(0))) OR
           (DVALID_IN AND M2_X_16 AND (NOT S(1)) AND      S(0) ) OR
           (DVALID_IN AND M4_X_8  AND      S(1)  AND      S(0) ) OR
           (   EOL_IN AND M4_X_8  AND (NOT S(1)) AND      S(0) ) OR
           (   EOL_IN AND M4_X_8  AND      S(1)  AND (NOT S(0))) OR
           (   EOL_IN AND M4_X_8  AND      S(1)  AND      S(0) ) OR
           (   EOL_IN AND M2_X_16 AND (NOT S(1)) AND      S(0) );

  SEL_A <= (NOT M4_X_8);
  SEL_B <= M1_X_32;
  SEL_C <= M1_X_32;
  SEL_D <= M2_X_16;

  process(PIXEL_CLOCK)
  begin
    if rising_edge(PIXEL_CLOCK) then
      CLR_A <= '0';
      CLR_B <= '0';
      CLR_C <= '0';
      CLR_D <= '0';
      if RESET='1' or (SYNC='1' and SYNC_DEL='0') then
        CLR_A <= '1';
      end if;
      if RESET='1' or (SYNC='1' and SYNC_DEL='0') or
         (EOL_IN='1' and M4_X_8='1' and S(1)='0' and S(0)='1') then
        CLR_B <= '1';
      end if;
      if RESET='1' or (SYNC='1' and SYNC_DEL='0') or
         (EOL_IN='1' and M4_X_8='1'  and S(1)='0' and S(0)='1') or 
         (EOL_IN='1' and M4_X_8='1'  and S(1)='1' and S(0)='0') or
         (EOL_IN='1' and M2_X_16='1' and S(1)='0' and S(0)='1') then
        CLR_C <= '1';
      end if;
      if RESET='1' or (SYNC='1' and SYNC_DEL='0') or
         (EOL_IN='1' and M4_X_8='1'  and S(1)='0' and S(0)='1') or
         (EOL_IN='1' and M4_X_8='1'  and S(1)='1' and S(0)='0') or
         (EOL_IN='1' and M4_X_8='1'  and S(1)='1' and S(0)='1') or
         (EOL_IN='1' and M2_X_16='1' and S(1)='0' and S(0)='1') then
        CLR_D <= '1';
      end if;
    end if;
  end process;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      S  <= (others=>'0'); 
      EN <= '0';
    elsif rising_edge(PIXEL_CLOCK) then
      EN <= REG_D;
      if CE='1' then
        S <= (others=>'0');
        if (S="00" and M1_X_32='0' and EOL_IN='0') or
           (S="10"                 and EOL_IN='0') then
          S(0) <= '1';
        end if;
        if (S="01" and  M4_X_8='1' and EOL_IN='0') or
           (S="10"                 and EOL_IN='0') then
          S(1) <= '1';
        end if;
      end if;
    end if;
  end process;

  process(RESET, PIXEL_CLOCK)
  begin
    if RESET='1' then
      SYNC     <= '0';
      SYNC_DEL <= '0';
    elsif rising_edge(PIXEL_CLOCK) then
      SYNC     <= '0';
      SYNC_DEL <= SYNC;
      if EOL_IN='1' or (SYNC='1' and DVALID_IN='0' and EOF_IN='0') then
        SYNC <= '1';
      end if;
    end if;
  end process;

  DVALID_OUT <= (EN OR (SYNC AND DVALID_IN) OR (SYNC AND EOF_IN));

  -- Frame sync value (FFh)
  FR_SYNC <= EOF_IN & EOF_IN & EOF_IN & EOF_IN & 
             EOF_IN & EOF_IN & EOF_IN & EOF_IN;

  -- Prevent the values 00h and FFh for the bottom data byte
  ADJUST(0) <= ( (NOT DATA_IN(1)) AND (NOT DATA_IN(2)) AND
                 (NOT DATA_IN(3)) AND (NOT DATA_IN(4)) AND
                 (NOT DATA_IN(5)) AND (NOT DATA_IN(6)) AND
                 (NOT DATA_IN(7)) )
              OR (DATA_IN(0) AND (NOT (DATA_IN(1) AND DATA_IN(2)
                                   AND DATA_IN(3) AND DATA_IN(4)
                                   AND DATA_IN(5) AND DATA_IN(6)
                                   AND DATA_IN(7) ))); 
  ADJUST(1) <= DATA_IN(1);
  ADJUST(2) <= DATA_IN(2);
  ADJUST(3) <= DATA_IN(3);
  ADJUST(4) <= DATA_IN(4);
  ADJUST(5) <= DATA_IN(5);
  ADJUST(6) <= DATA_IN(6);
  ADJUST(7) <= DATA_IN(7);

  process(SEL_A, ADJUST, DATA_IN(15 downto 8))
  begin
    case SEL_A is
      when '0'    => MUX_A <= ADJUST;
      when others => MUX_A <= DATA_IN(15 downto 8);
    end case;
  end process;

  process(SEL_B, ADJUST, DATA_IN(23 downto 16))
  begin
    case SEL_B is
      when '0'    => MUX_B <= ADJUST;
      when others => MUX_B <= DATA_IN(23 downto 16);
    end case;
  end process;

  process(SEL_C, ADJUST, DATA_IN(31 downto 24))
  begin
    case SEL_C is
      when '0'    => MUX_C <= ADJUST;
      when others => MUX_C <= DATA_IN(31 downto 24);
    end case;
  end process;

  process(SEL_D, MUX_C, DATA_IN(15 downto 8))
  begin
    case SEL_D is
      when '0'    => MUX_D <= MUX_C;
      when others => MUX_D <= DATA_IN(15 downto 8);
    end case;
  end process;

  process(CLR_A, PIXEL_CLOCK)
  begin
    if CLR_A='1' then
      REG_DATA(7 downto 0) <= (others=>'0');
    elsif rising_edge(PIXEL_CLOCK) then
      if REG_A='1' then
        REG_DATA(7  downto  0) <= ADJUST;
      end if;
    end if;
  end process;

  process(CLR_B, PIXEL_CLOCK)
  begin
    if CLR_B='1' then
      REG_DATA(15 downto 8) <= (others=>'0');
    elsif rising_edge(PIXEL_CLOCK) then
      if REG_B='1' then
        REG_DATA(15 downto  8) <= MUX_A;
      end if;
    end if;
  end process;

  process(CLR_C, PIXEL_CLOCK)
  begin
    if CLR_C='1' then
      REG_DATA(23 downto 16) <= (others=>'0');
    elsif rising_edge(PIXEL_CLOCK) then
      if REG_C='1' then
        REG_DATA(23 downto 16) <= MUX_B;
      end if;
    end if;
  end process;

  process(CLR_D, PIXEL_CLOCK)
  begin
    if CLR_D='1' then
      REG_DATA(31 downto 24) <= (others=>'0');
    elsif rising_edge(PIXEL_CLOCK) then
      if REG_D='1' then
        REG_DATA(31 downto 24) <= MUX_D;
      end if;
    end if;
  end process;

  DATA_OUT( 7 downto  0) <= REG_DATA( 7 downto  0) OR FR_SYNC;
  DATA_OUT(15 downto  8) <= REG_DATA(15 downto  8) OR FR_SYNC;
  DATA_OUT(23 downto 16) <= REG_DATA(23 downto 16) OR FR_SYNC;
  DATA_OUT(31 downto 24) <= REG_DATA(31 downto 24) OR FR_SYNC;

end RTL;
