-------------------------------------------------------------------------------
--
-- Project name: JESD204b Receiver core 
--
-- (C) Copyright 2017 DFC Design, s.r.o., Brno, Czech Republic
-- Author: Marek Kvas (m.kvas@dfcdesign.cz)
--
-------------------------------------------------------------------------------
--
-- This is top level module for JESD204b receiver core. The purpose
-- of this core is to receive data from ADC converters.
--
-- The core depends on Xilinx's JESD204B PHY core that encapsulates 
-- transceivers.
--
-- Output interface consists of wide data bus - 32 bit per each lane -
-- and set of signals that mark starts and ends of frames and multi-frames.
-- These marks are needed to map raw data into samples properly.
--
-- Generics:
-- g_lane_count - number of input lanes. Output AXI size depends on it.
-- 
-- g_scrambler_included - is scrambling is never used, setting this to false
--       may save some resources. If true scrambling can be enabled disabled
--       by input.

-- g_lmfc_buffer_size - maxim number of octets to be stored in elastic buffer
--       per lane. It is equal to the maximum multiframe length acceptable.
--       It must be power of 2 and at least 32.
--
-- Ports:
--    CLK - core clock. Both input and output data buses run at this clock.
--          it is lane_serial_clock/40. Sysref is sampled on this clock either
--    RST - synchronous reset of the whole core.
--    CFG_SCRAMBLING_EN - if 1 data are considered to be scrambled.
--    CFG_SYSREF_POLARITY - If 1, sysref is sampled on rising edge. 
--                          If 0 on falling.
--    CFG_SYSREF_EN - If 1 LMFC is adjusted on all SYSREF events. If 0,
--          LMFC is adjusted only on the first SYSREF event after reset.
--    CFG_SYSREF_ALLRESYNC - If 1 SYSREF is required on resync. If 0 LMFC is not
--          adjusted on resync and old synchronization is kept.
--    CFG_F - number of octets per frame. Range F is 1 - 256. CFG_F = F - 1.
--    CFG_K - number of frames per multiframe. range K = 1 - 32, CFG_K = K - 1.
--          
--
-------------------------------------------------------------------------------


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity jesd204b_rx is 
   generic (
      g_lane_count         : integer range 1 to 16;
      g_stat_cnt_length    : integer := 16;
      g_scrambler_incl     : boolean := true;
      g_lmfc_buffer_size   : integer := 1024
           );
   port (
      CLK                  : in  std_logic;
      RST                  : in  std_logic;
   
      -- JESD204B control signals
      SYNC                 : out std_logic;
      SYSREF               : in  std_logic;

      -- Connection to PHY (RX transceivers)
      PHY_DATA             : in  std_logic_vector(g_lane_count * 32 -1 downto 0);
      PHY_CHARISK          : in  std_logic_vector(g_lane_count * 4 - 1 downto 0);
      PHY_DISPERR          : in  std_logic_vector(g_lane_count * 4 - 1 downto 0);
      PHY_NOTINTABLE       : in  std_logic_vector(g_lane_count * 4 - 1 downto 0);
      PHY_COMMA_ALIGN_EN   : out std_logic_vector(g_lane_count - 1 downto 0);
      
      -- Output AXI4-Stream integrface
      OUT_M_AXIS_TVALID    : out std_logic;
      OUT_M_AXIS_TDATA     : out std_logic_vector(g_lane_count * 32 -1 downto 0);
      OUT_SOF              : out std_logic_vector(3 downto 0);
      OUT_EOF              : out std_logic_vector(3 downto 0);
      OUT_SOMF             : out std_logic_vector(3 downto 0);
      OUT_EOMF             : out std_logic_vector(3 downto 0);
      OUT_BYTE_ERR         : out std_logic_vector(g_lane_count * 4 - 1 downto 0);
      OUT_ILAS_CFG_DATA    : out std_logic_vector(g_lane_count*16*8 -1 downto 0);
      OUT_ILAS_CFG_DONE    : out std_logic_vector(g_lane_count - 1 downto 0);
      
      
      CFG_F                : in  std_logic_vector(7 downto 0);
      CFG_K                : in  std_logic_vector(4 downto 0);
      CFG_FxK              : in  std_logic_vector(10 downto 0);
      CFG_SUBCLASS         : in  std_logic_vector(1 downto 0);
      CFG_ERR_REPORT_EN    : in  std_logic;
      CFG_REINIT_EN        : in  std_logic;
      CFG_ILAS             : in  std_logic;
      CFG_SCRAMBLING_EN    : in  std_logic;
      CFG_SYSREF_DELAY     : in  std_logic_vector(3 downto 0);
      CFG_SYSREF_ALLRESYNC : in  std_logic;
      CFG_SYSREF_POLARITY  : in  std_logic;
   
      STAT_SYSREF_SEEN     : out std_logic;
      STAT_SYNC_OK         : out std_logic;
      STAT_ERR_LMFC_SYNC   : out std_logic;
      STAT_ERR_LMFC_DIFF   : out std_logic_vector(10 downto 0);
      
      LANE_STATUS          : out std_logic_vector(g_lane_count * 8 - 1
                                                                downto 0);
      MON_RST              : in  std_logic;
      LANE_MON_PHYS_ERR_CNT      : out std_logic_vector(
                         g_lane_count * g_stat_cnt_length - 1 downto 0);
      LANE_MON_PHYS_ERR_RES_CNT  : out std_logic_vector(
                         g_lane_count * g_stat_cnt_length - 1 downto 0);
      LANE_MON_ALIGN_F_ERR_CNT   : out std_logic_vector(
                         g_lane_count * g_stat_cnt_length - 1 downto 0);
      LANE_MON_ALIGN_MF_ERR_CNT  : out std_logic_vector(
                         g_lane_count * g_stat_cnt_length - 1 downto 0);
      LANE_MON_REPLACE_F_CNT     : out std_logic_vector(
                         g_lane_count * g_stat_cnt_length - 1 downto 0);
      LANE_MON_REPLACE_A_CNT     : out std_logic_vector(
                         g_lane_count * g_stat_cnt_length - 1 downto 0);
      LANE_MON_UNKNOWN_K_CNT     : out std_logic_vector(
                         g_lane_count * g_stat_cnt_length - 1 downto 0);
      LANE_MON_ILAS_ERR_CNT      : out std_logic_vector(
                           g_lane_count * g_stat_cnt_length - 1 downto 0);

      -- Debugging LMF outputs
      LMFC_OUT                   : out std_logic;
      LMFC_PREC_OUT              : out std_logic_vector(3 downto 0)
      
        );
end entity;



architecture synthesis of jesd204b_rx is

   function sl(i : integer; vec : std_logic_vector) return std_logic_vector is
      variable res : std_logic_vector((i+1)*vec'length - 1 downto i*vec'length);
   begin
      res := (others => '0');
      return res;
   end function;

   function sl(i : integer; len : integer) return std_logic_vector is
      variable res : std_logic_vector((i+1)*len - 1 downto i*len);
   begin
      res := (others => '0');
      return res;
   end function;


   signal out_m_axis_tvalid_vec  : std_logic_vector(g_lane_count -1 downto 0);
   signal out_sof_vec            : std_logic_vector(
                                 g_lane_count * OUT_SOF'length-1 downto 0);
   signal out_eof_vec            : std_logic_vector(
                                 g_lane_count * OUT_EOF'length-1 downto 0);
   signal out_somf_vec           : std_logic_vector(
                                 g_lane_count * OUT_SOMF'length-1 downto 0);
   signal out_eomf_vec           : std_logic_vector(
                                 g_lane_count * OUT_EOMF'length-1 downto 0);
   signal out_byte_err_vec       : std_logic_vector(
                                 g_lane_count * OUT_EOMF'length-1 downto 0);                                 

   signal ctl_reinit             : std_logic;
   signal ctl_cgs_done           : std_logic_vector(g_lane_count - 1 downto 0);
   signal ctl_reinit_req         : std_logic_vector(g_lane_count - 1 downto 0);
   signal ctl_err_report_req     : std_logic_vector(g_lane_count - 1 downto 0);
   signal ctl_ifa_done           : std_logic_vector(g_lane_count - 1 downto 0);
   signal ctl_release_data       : std_logic;
   signal ctl_ilas_err           : std_logic_vector(g_lane_count - 1 downto 0);
   signal ctl_err_overflow       : std_logic_vector(g_lane_count - 1 downto 0);
   signal ctl_data_ready         : std_logic_vector(g_lane_count - 1 downto 0);


begin


   lanes_gen : for i in 0 to g_lane_count - 1 generate
      jesd204b_rx_lane_inst : entity work.jesd204b_rx_lane
      generic map (
         g_stat_cnt_length    => g_stat_cnt_length,
         g_scrambler_incl     => g_scrambler_incl,
         g_lmfc_buffer_size   => g_lmfc_buffer_size
                  )
      port map (
         CLK                  => CLK,
         RST                  => RST,
      
         -- JESD204B control signals
         CTL_REINIT           => ctl_reinit,
         CTL_CGS_DONE         => ctl_cgs_done(i),
         CTL_REINIT_REQ       => ctl_reinit_req(i),
         CTL_ERR_REPORT_REQ   => ctl_err_report_req(i),
         CTL_IFA_DONE         => ctl_ifa_done(i),
         CTL_RELEASE_DATA     => ctl_release_data,
         CTL_ILAS_ERR         => ctl_ilas_err(i),
         CTL_ERR_OVERFLOW     => ctl_err_overflow(i),
         CTL_DATA_READY       => ctl_data_ready(i),
   
         -- Connection to PHY (RX transceivers)
         PHY_DATA             => PHY_DATA(sl(i, PHY_DATA'length/g_lane_count)'range),
         PHY_CHARISK          => PHY_CHARISK(sl(i, PHY_CHARISK'length/g_lane_count)'range),
         PHY_DISPERR          => PHY_DISPERR(sl(i, PHY_DISPERR'length/g_lane_count)'range),
         PHY_NOTINTABLE       => PHY_NOTINTABLE(sl(i, PHY_NOTINTABLE'length/g_lane_count)'range),
         PHY_COMMA_ALIGN_EN   => PHY_COMMA_ALIGN_EN(i),
         
         -- Output AXI4-Stream interface
         OUT_M_AXIS_TVALID    => out_m_axis_tvalid_vec(i),
         OUT_M_AXIS_TDATA     => OUT_M_AXIS_TDATA(
                              sl(i, OUT_M_AXIS_TDATA'length/g_lane_count)'range),
         OUT_SOF              => out_sof_vec(sl(i, OUT_SOF'length)'range),
         OUT_EOF              => out_eof_vec(sl(i, OUT_EOF'length)'range),
         OUT_SOMF             => out_somf_vec(sl(i, OUT_SOMF'length)'range),
         OUT_EOMF             => out_eomf_vec(sl(i, OUT_EOMF'length)'range),
         OUT_BYTE_ERR         => out_byte_err_vec(
                              sl(i, OUT_BYTE_ERR'length/g_lane_count)'range),
         OUT_ILAS_CFG_DATA    => OUT_ILAS_CFG_DATA(
                             sl(i, OUT_ILAS_CFG_DATA'length/g_lane_count)'range),
         OUT_ILAS_CFG_DONE    => OUT_ILAS_CFG_DONE(i),
         
         -- Configurations
         CFG_SCRAMBLING_EN    => CFG_SCRAMBLING_EN,
   
         -- Both contain K/F -1 value as 0 is meaningless
         -- FxK is helper value - number of bytes in multiframe (exact no -1)
         CFG_F                => CFG_F,
         --CFG_K                => CFG_K,
         CFG_FxK              => CFG_FxK,
   
         CFG_ILAS             => CFG_ILAS,
   
         -- Monitoring - error, statistics
         MON_RST              => MON_RST,
         MON_PHYS_ERR_CNT     => LANE_MON_PHYS_ERR_CNT(sl(i, g_stat_cnt_length)'range),
         MON_PHYS_ERR_RES_CNT => LANE_MON_PHYS_ERR_RES_CNT(sl(i, g_stat_cnt_length)'range),
         MON_ALIGN_F_ERR_CNT  => LANE_MON_ALIGN_F_ERR_CNT(sl(i, g_stat_cnt_length)'range),
         MON_ALIGN_MF_ERR_CNT => LANE_MON_ALIGN_MF_ERR_CNT(sl(i, g_stat_cnt_length)'range),
         MON_REPLACE_F_CNT    => LANE_MON_REPLACE_F_CNT(sl(i, g_stat_cnt_length)'range),
         MON_REPLACE_A_CNT    => LANE_MON_REPLACE_A_CNT(sl(i, g_stat_cnt_length)'range),
         MON_UNKNOWN_K_CNT    => LANE_MON_UNKNOWN_K_CNT(sl(i, g_stat_cnt_length)'range),
         MON_ILAS_ERR_CNT     => LANE_MON_ILAS_ERR_CNT(sl(i, g_stat_cnt_length)'range)
                  );
   
   end generate;

   jesd204b_lmfc_inst : entity work.jesd204b_lmfc
   generic map (
      g_lane_count         => g_lane_count,
      g_stat_cnt_length    => g_stat_cnt_length
           )
   port map (
      CLK                  => CLK,
      RST                  => RST,
   
      -- Lane control signals
      CTL_REINIT           => ctl_reinit,
      CTL_CGS_DONE         => ctl_cgs_done,
      CTL_REINIT_REQ       => ctl_reinit_req,
      CTL_ERR_REPORT_REQ   => ctl_err_report_req,
      CTL_IFA_DONE         => ctl_ifa_done,
      CTL_RELEASE_DATA     => ctl_release_data,
      CTL_DATA_READY       => ctl_data_ready,

      -- External device control
      SYNC                 => SYNC,
      SYSREF               => SYSREF,

      -- Protocol parameters
      CFG_FxK              => CFG_FxK,
      CFG_F                => CFG_F,
      CFG_SUBCLASS         => CFG_SUBCLASS,
      CFG_SYSREF_DELAY     => CFG_SYSREF_DELAY,
      CFG_SYSREF_ALLRESYNC => CFG_SYSREF_ALLRESYNC,
      CFG_SYSREF_POLARITY  => CFG_SYSREF_POLARITY,
      CFG_REINIT_EN        => CFG_REINIT_EN,
      CFG_ERR_REPORT_EN    => CFG_ERR_REPORT_EN,

      -- Status signals
      STAT_SYSREF_SEEN     => STAT_SYSREF_SEEN,
      STAT_SYNC_OK         => STAT_SYNC_OK,

      STAT_ERR_LMFC_SYNC   => STAT_ERR_LMFC_SYNC,
      STAT_ERR_LMFC_DIFF   => STAT_ERR_LMFC_DIFF,

      -- Debugging signals
      LMFC_OUT             => LMFC_OUT,
      LMFC_PREC_OUT        => LMFC_PREC_OUT
        );


   -- Outputs assignment
   OUT_M_AXIS_TVALID <= out_m_axis_tvalid_vec(0);
   OUT_SOF           <= out_sof_vec(sl(0, OUT_SOF'length)'range);
   OUT_EOF           <= out_eof_vec(sl(0, OUT_SOF'length)'range);
   OUT_SOMF          <= out_somf_vec(sl(0, OUT_SOF'length)'range);
   OUT_EOMF          <= out_eomf_vec(sl(0, OUT_SOF'length)'range);
   


end architecture;
