-- ==============================================================
-- FILE : CAMLINK_EX.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 : CameraLink Example IP
--
-- ==============================================================
--
--  Ver     Modified By      Date      Changes
--  ---     -----------      ----      -------
--  1.0     R. Williams    12-06-06    Developed from previous
--                                     Camera Link examples.
--
-- ==============================================================



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


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


entity CAMLINK_EX is
  generic (
    Use_Low_Freq_Deserialiser : boolean := TRUE
  );
  port (
    -- Clock and Reset
    RESET         : in  std_logic;
    CLOCK         : in  std_logic;
    -- CameraLink interface
    CAM_CLK       : in  std_logic;
    CAM_DATA      : in  std_logic_vector(3 downto 0);
    CAM_CTRL      : out std_logic_vector(3 downto 0);
    CAM_SER_TC    : out std_logic;
    CAM_SER_TFG   : in  std_logic;
    -- HERON Output FIFO interface
    FCLK_G        : in  std_logic;
    OUTFIFO_READY : in  std_logic_vector(5 downto 0);
    OUTFIFO_WRITE : out std_logic_vector(5 downto 0);
    OUTFIFO_D     : out std_logic_vector(31 downto 0);
    -- FIFO Full LED
    FIFO_FULL_LED : out std_logic;
    -- User Message interface
    MSG_CLK       : out std_logic;
    MSG_DIN       : in  std_logic_vector(7 downto 0);
    MSG_ADDR      : in  std_logic_vector(7 downto 0);
    MSG_WEN       : in  std_logic;
    MSG_REN       : in  std_logic;
    MSG_DONE      : in  std_logic;
    MSG_COUNT     : in  std_logic;
    MSG_CLEAR     : in  std_logic;
    MSG_READY     : out std_logic;
    MSG_SEND_MSG  : out std_logic;
    MSG_CE        : out std_logic;
    MSG_DOUT      : out std_logic_vector(7 downto 0);
    MSG_SEND_ID   : out std_logic;
    MSG_LAST_BYTE : out std_logic
  );
end CAMLINK_EX;


architecture RTL of CAMLINK_EX is

  component CLINK
    generic (
      LFreq_Deserialiser : boolean := TRUE
    );
    port (
      RESET       : in  std_logic;
      CAM_CLK     : in  std_logic;
      CAM_DATA    : in  std_logic_vector(3 downto 0);
      POLARITY    : in  std_logic;
      USE_DVAL    : in  std_logic;
      BIT_SEL     : in  std_logic_vector(1 downto 0);
      PIXEL_CLOCK : out std_logic;
      DVALID_OUT  : out std_logic;
      EOL_OUT     : out std_logic;
      EOF_OUT     : out std_logic;
      DATA_OUT    : out std_logic_vector(31 downto 0);
      ACTIVE      : out std_logic_vector(3 downto 0)
    );
  end component;

  component AUTO_ROI
    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 component;

  component ROI
    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 component;

  component FRAME_CONTROL
    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 component;

  component PACK_SYNC
    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 component;

  component CAMLINK_HSB
    port (
      RESET       : in  std_logic;
      CLOCK       : in  std_logic;
      PIXEL_CLOCK : in  std_logic;
      DIN         : in  std_logic_vector(7 downto 0);
      ADDR        : in  std_logic_vector(7 downto 0);
      WEN         : in  std_logic;
      REN         : in  std_logic;
      DONE        : in  std_logic;
      COUNT       : in  std_logic;
      CLEAR       : in  std_logic;
      READY       : out std_logic;
      SEND_MSG    : out std_logic;
      CE          : out std_logic;
      DOUT        : out std_logic_vector(7 downto 0);
      SEND_ID     : out std_logic;
      LAST_BYTE   : out std_logic;
      M4_X_8      : out std_logic;
      M2_X_16     : out std_logic;
      M1_X_32     : out std_logic;
      BIT_SEL     : out std_logic_vector(1 downto 0);
      CONTINUOUS  : out std_logic;
      ODD_ONLY    : out std_logic;
      LOAD        : out std_logic;
      FRAMES      : out std_logic_vector(3 downto 0);
      AUTO_RES    : out std_logic;
      POLARITY    : out std_logic;
      USE_DVAL    : out std_logic;
      CAM_INPUTS  : out std_logic_vector(3 downto 0);
      START_PIXEL : out std_logic_vector(11 downto 0);
      STOP_PIXEL  : out std_logic_vector(11 downto 0);
      START_LINE  : out std_logic_vector(11 downto 0);
      STOP_LINE   : out std_logic_vector(11 downto 0);
      OUTFIFO_SEL : out std_logic_vector(5 downto 0);
      TX          : out std_logic;
      RX          : in  std_logic;
      PIXEL_TOTAL : in  std_logic_vector(11 downto 0);
      LINE_TOTAL  : in  std_logic_vector(11 downto 0);
      FIRST_PIXEL : in  std_logic_vector(11 downto 0);
      LAST_PIXEL  : in  std_logic_vector(11 downto 0);
      FIRST_LINE  : in  std_logic_vector(11 downto 0);
      LAST_LINE   : in  std_logic_vector(11 downto 0);
      ACTIVE      : in  std_logic_vector(3 downto 0);
      ROI_VALID   : in  std_logic
    );
  end component;

  component fifo511x32
    port (
      din    : in  std_logic_vector(31 downto 0);
      wr_en  : in  std_logic;
      wr_clk : in  std_logic;
      rd_en  : in  std_logic;
      rd_clk : in  std_logic;
      ainit  : in  std_logic;
      dout   : out std_logic_vector(31 downto 0);
      full   : out std_logic;
      empty  : out std_logic
    );
  end component;

  -- BUFG primitive
  component BUFG
    port(
      I : in  std_logic;
      O : out std_logic
    );
  end component;

  -- Clocks
  signal HSB_CLK     : std_logic;  -- HSB clock source
  signal HSB_CLOCK   : std_logic;  -- HSB clock
  signal PIXEL_CLOCK : std_logic;  -- Pixel Clock

  -- Data mode
  signal M4_X_8      : std_logic;
  signal M2_X_16     : std_logic;
  signal M1_X_32     : std_logic;
  signal BIT_SEL     : std_logic_vector(1 downto 0);

  -- Connections from areascan input to region of interest (ROI)
  signal DVALID_A    : std_logic;
  signal EOL_A       : std_logic;
  signal EOF_A       : std_logic;
  signal DATA_A      : std_logic_vector(31 downto 0);

  -- Connections from region of interest (ROI) to frame control
  signal DVALID_B    : std_logic;
  signal EOL_B       : std_logic;
  signal EOF_B       : std_logic;
  signal DATA_B      : std_logic_vector(31 downto 0);

  -- Connections from frame control to output packing and synchronisation
  signal DVALID_C    : std_logic;
  signal EOL_C       : std_logic;
  signal EOF_C       : std_logic;
  signal DATA_C      : std_logic_vector(31 downto 0);

  -- Connections from output packing and synchronisation to 511x32 FIFO
  signal DVALID_D    : std_logic;
  signal DATA_D      : std_logic_vector(31 downto 0);

  -- FIFO transfer
  signal FIFO_RD     : std_logic;
  signal FIFO_WR     : std_logic;
  signal FIFO_EF     : std_logic;
  signal FIFO_FF     : std_logic;
  signal FF_WR       : std_logic;
  signal READY       : std_logic;
  signal OUTFIFO_SEL : std_logic_vector(5 downto 0);

  -- General control and setup
  signal CAM_TC      : std_logic;
  signal LOAD        : std_logic;
  signal FRAMES      : std_logic_vector(3 downto 0);
  signal CONTINUOUS  : std_logic;
  signal ODD_ONLY    : std_logic;
  signal AUTO_RES    : std_logic;
  signal POLARITY    : std_logic;
  signal USE_DVAL    : std_logic;
  signal CAM_INPUTS  : std_logic_vector(3 downto 0);

  -- ROI pixels-per-line and lines-per-frame
  signal START_PIXEL : std_logic_vector(11 downto 0);
  signal STOP_PIXEL  : std_logic_vector(11 downto 0);
  signal START_LINE  : std_logic_vector(11 downto 0);
  signal STOP_LINE   : std_logic_vector(11 downto 0);

  -- AUTO-REGION OF INTEREST Information
  signal FIRST_PIXEL : std_logic_vector(11 downto 0);
  signal LAST_PIXEL  : std_logic_vector(11 downto 0);
  signal FIRST_LINE  : std_logic_vector(11 downto 0);
  signal LAST_LINE   : std_logic_vector(11 downto 0);
  signal PIXEL_TOTAL : std_logic_vector(11 downto 0);
  signal LINE_TOTAL  : std_logic_vector(11 downto 0);
  signal ACTIVE      : std_logic_vector(3 downto 0);
  signal ROI_VALID   : std_logic;

begin

  -------------------------------------------------------------
  -- Camera Link component : input of camera-link data and
  -- control information

  CAM_CTRL <= CAM_INPUTS;

  iCLINK : CLINK
    generic map (
      LFreq_Deserialiser => Use_Low_Freq_Deserialiser )
    port map (
      RESET       => RESET,
      CAM_CLK     => CAM_CLK,
      CAM_DATA    => CAM_DATA,
      POLARITY    => POLARITY,
      USE_DVAL    => USE_DVAL,
      BIT_SEL     => BIT_SEL,
      PIXEL_CLOCK => PIXEL_CLOCK,
      DVALID_OUT  => DVALID_A,
      EOL_OUT     => EOL_A,
      EOF_OUT     => EOF_A,
      DATA_OUT    => DATA_A,
      ACTIVE      => ACTIVE );

  -------------------------------------------------------------
  -- AUTO_ROI component : automatic region of interest detection

  iAUTO_ROI : AUTO_ROI
    port map (
      RESET       => AUTO_RES,
      PIXEL_CLOCK => PIXEL_CLOCK,
      DVALID_IN   => DVALID_A,
      EOL_IN      => EOL_A,
      EOF_IN      => EOF_A,
      DATA_IN     => DATA_A,
      FIRST_PIXEL => FIRST_PIXEL,
      LAST_PIXEL  => LAST_PIXEL,
      FIRST_LINE  => FIRST_LINE,
      LAST_LINE   => LAST_LINE,
      PIXEL_TOTAL => PIXEL_TOTAL,
      LINE_TOTAL  => LINE_TOTAL,
      ROI_VALID   => ROI_VALID );

  -------------------------------------------------------------
  -- ROI component : region of interest applied to data stream
  -- output from the CLINK component

  iROI : ROI
    port map (
      RESET       => RESET,
      PIXEL_CLOCK => PIXEL_CLOCK,
      ODD_ONLY    => ODD_ONLY,
      DVALID_IN   => DVALID_A,
      EOL_IN      => EOL_A,
      EOF_IN      => EOF_A,
      DVALID_OUT  => DVALID_B,
      EOL_OUT     => EOL_B,
      EOF_OUT     => EOF_B,
      START_PIXEL => START_PIXEL,
      STOP_PIXEL  => STOP_PIXEL,
      START_LINE  => START_LINE,
      STOP_LINE   => STOP_LINE,
      DATA_IN     => DATA_A,
      DATA_OUT    => DATA_B );

  -------------------------------------------------------------
  -- FRAME_CONTROL component : frame output control applied to
  -- data stream output from the ROI component

  iFRAME_CONTROL : FRAME_CONTROL
    port map (
      RESET       => RESET,
      PIXEL_CLOCK => PIXEL_CLOCK,
      CONTINUOUS  => CONTINUOUS,
      DVALID_IN   => DVALID_B,
      EOL_IN      => EOL_B,
      EOF_IN      => EOF_B,
      DVALID_OUT  => DVALID_C,
      EOL_OUT     => EOL_C,
      EOF_OUT     => EOF_C,
      LOAD        => LOAD,
      FRAMES      => FRAMES,
      DATA_IN     => DATA_B,
      DATA_OUT    => DATA_C );

  -------------------------------------------------------------
  -- PACK_SYNC component : data packing and synchronisation
  -- markers for output to the HERON FIFOs (via a 511x32 FIFO
  -- inside the FPGA). Applied to data from the FRAME_CONTROL
  -- component

  iPACK_SYNC : PACK_SYNC
    port map (
      RESET         => RESET,
      PIXEL_CLOCK   => PIXEL_CLOCK,
      M4_X_8        => M4_X_8,
      M2_X_16       => M2_X_16,
      M1_X_32       => M1_X_32,
      DVALID_IN     => DVALID_C,
      EOL_IN        => EOL_C,
      EOF_IN        => EOF_C,
      DVALID_OUT    => DVALID_D,
      DATA_IN       => DATA_C,
      DATA_OUT      => DATA_D );

  -------------------------------------------------------------
  -- fifo511x32 component : COREGEN FIFO, 32-bits wide and 511
  -- words deep

  iFIFO511X32 : fifo511x32
    port map (
      din    => DATA_D,
      wr_en  => FIFO_WR,
      wr_clk => PIXEL_CLOCK,
      rd_en  => FIFO_RD,
      rd_clk => FCLK_G,
      ainit  => RESET,
      dout   => OUTFIFO_D,
      full   => FIFO_FF,
      empty  => FIFO_EF );

  FIFO_FULL_LED <= (NOT FIFO_FF);

  -------------------------------------------------------------
  -- Data transfer control from the COREGEN FIFO to the HERON
  -- Output FIFO

  FIFO_WR <= DVALID_D AND (NOT FIFO_FF);

  FIFO_RD <= (NOT FIFO_EF) AND READY;

  READY <= (OUTFIFO_READY(0) AND OUTFIFO_SEL(0)) OR
           (OUTFIFO_READY(1) AND OUTFIFO_SEL(1)) OR
           (OUTFIFO_READY(2) AND OUTFIFO_SEL(2)) OR
           (OUTFIFO_READY(3) AND OUTFIFO_SEL(3)) OR
           (OUTFIFO_READY(4) AND OUTFIFO_SEL(4)) OR
           (OUTFIFO_READY(5) AND OUTFIFO_SEL(5));

  process (RESET, FCLK_G)
  begin
    if RESET='1' then
      FF_WR <= '0';
    elsif rising_edge(FCLK_G) then
      FF_WR <= '0';
      if FIFO_EF='0' and READY='1' then  -- enable write
        FF_WR <= '1';
      end if;
    end if;
  end process;

  OUTFIFO_WRITE(0) <= FF_WR AND OUTFIFO_SEL(0);
  OUTFIFO_WRITE(1) <= FF_WR AND OUTFIFO_SEL(1);
  OUTFIFO_WRITE(2) <= FF_WR AND OUTFIFO_SEL(2);
  OUTFIFO_WRITE(3) <= FF_WR AND OUTFIFO_SEL(3);
  OUTFIFO_WRITE(4) <= FF_WR AND OUTFIFO_SEL(4);
  OUTFIFO_WRITE(5) <= FF_WR AND OUTFIFO_SEL(5);

  -------------------------------------------------------------
  -- Serial Bus

  HSB_bufg : bufg port map(i => HSB_CLK, o => HSB_CLOCK);

  MSG_CLK <= HSB_CLOCK;  -- clock for Message Interface

  process (CLOCK)
  begin
    if rising_edge(CLOCK) then
      HSB_CLK <= NOT HSB_CLK;
    end if;
  end process;

  iCAMLINK_HSB : CAMLINK_HSB
    port map (
      RESET       => RESET,
      CLOCK       => HSB_CLOCK,
      PIXEL_CLOCK => PIXEL_CLOCK,
      DIN         => MSG_DIN,
      ADDR        => MSG_ADDR,
      WEN         => MSG_WEN,
      REN         => MSG_REN,
      DONE        => MSG_DONE,
      COUNT       => MSG_COUNT,
      CLEAR       => MSG_CLEAR,
      READY       => MSG_READY,
      SEND_MSG    => MSG_SEND_MSG,
      CE          => MSG_CE,
      DOUT        => MSG_DOUT,
      SEND_ID     => MSG_SEND_ID,
      LAST_BYTE   => MSG_LAST_BYTE,
      M4_X_8      => M4_X_8,
      M2_X_16     => M2_X_16,
      M1_X_32     => M1_X_32,
      BIT_SEL     => BIT_SEL,
      CONTINUOUS  => CONTINUOUS,
      ODD_ONLY    => ODD_ONLY,
      LOAD        => LOAD,
      FRAMES      => FRAMES,
      AUTO_RES    => AUTO_RES,
      POLARITY    => POLARITY,
      USE_DVAL    => USE_DVAL,
      CAM_INPUTS  => CAM_INPUTS,
      START_PIXEL => START_PIXEL,
      STOP_PIXEL  => STOP_PIXEL,
      START_LINE  => START_LINE,
      STOP_LINE   => STOP_LINE,
      OUTFIFO_SEL => OUTFIFO_SEL,
      TX          => CAM_TC,
      RX          => CAM_SER_TFG,
      PIXEL_TOTAL => PIXEL_TOTAL,
      LINE_TOTAL  => LINE_TOTAL,
      FIRST_PIXEL => FIRST_PIXEL,
      LAST_PIXEL  => LAST_PIXEL,
      FIRST_LINE  => FIRST_LINE,
      LAST_LINE   => LAST_LINE,
      ACTIVE      => ACTIVE,
      ROI_VALID   => ROI_VALID );

  CAM_SER_TC     <= CAM_TC;

end RTL;
