------------------------------------------------------------------------------/
-- (c) Copyright 2013 Xilinx, Inc. All rights reserved.
--
-- This file contains confidential and proprietary information
-- of Xilinx, Inc. and is protected under U.S. and
-- international copyright and other intellectual property
-- laws.
--
-- DISCLAIMER
-- This disclaimer is not a license and does not grant any
-- rights to the materials distributed herewith. Except as
-- otherwise provided in a valid license issued to you by
-- Xilinx, and to the maximum extent permitted by applicable
-- law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
-- WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
-- AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
-- BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
-- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
-- (2) Xilinx shall not be liable (whether in contract or tort,
-- including negligence, or under any other theory of
-- liability) for any loss or damage of any kind or nature
-- related to, arising under or in connection with these
-- materials, including for any direct, or any indirect,
-- special, incidental, or consequential loss or damage
-- (including loss of data, profits, goodwill, or any type of
-- loss or damage suffered as a result of any action brought
-- by a third party) even if such damage or loss was
-- reasonably foreseeable or Xilinx had been advised of the
-- possibility of the same.
--
-- CRITICAL APPLICATIONS
-- Xilinx products are not designed or intended to be fail-
-- safe, or for use in any application requiring fail-safe
-- performance, such as life-support or safety devices or
-- systems, Class III medical devices, nuclear facilities,
-- applications related to the deployment of airbags, or any
-- other applications that could lead to death, personal
-- injury, or severe property or environmental damage
-- (individually and collectively, "Critical
-- Applications"). Customer assumes the sole risk and
-- liability of any use of Xilinx products in Critical
-- Applications, subject only to applicable laws and
-- regulations governing limitations on product liability.
--
-- THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
-- PART OF THIS FILE AT ALL TIMES.
--
--
--------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity aurora_rx_4l_64b_rx_startup_fsm is
  Generic( 
           EXAMPLE_SIMULATION       : integer :=  0;     
           GT_TYPE                  : string  := "GTP";
           EQ_MODE                  : string  := "DFE";           --RX Equalisation Mode; set to DFE or LPM
           STABLE_CLOCK_PERIOD      : integer range 4 to 250 := 8; --Period of the stable clock driving this state-machine, unit is [ns]
           RETRY_COUNTER_BITWIDTH   : integer range 2 to 8  := 8; 
           TX_QPLL_USED             : boolean := False;           -- the TX and RX Reset FSMs must
           RX_QPLL_USED             : boolean := False;           -- share these two generic values
           PHASE_ALIGNMENT_MANUAL   : boolean := True             -- Decision if a manual phase-alignment is necessary or the automatic 
                                                                  -- is enough. For single-lane applications the automatic alignment is 
                                                                  -- sufficient                         
         );     
    Port ( STABLE_CLOCK             : in  STD_LOGIC;        --Stable Clock, either a stable clock from the PCB
                                                            --or reference-clock present at startup.
           RXUSERCLK                : in  STD_LOGIC;        --RXUSERCLK as used in the design
           SOFT_RESET               : in  STD_LOGIC;        --User Reset, can be pulled any time
           RXPMARESETDONE           : in  STD_LOGIC;        
           RXOUTCLK                 : in  STD_LOGIC;    
    
           QPLLREFCLKLOST           : in  STD_LOGIC;        --QPLL Reference-clock for the GT is lost
           CPLLREFCLKLOST           : in  STD_LOGIC;        --CPLL Reference-clock for the GT is lost
           QPLLLOCK                 : in  STD_LOGIC;        --Lock Detect from the QPLL of the GT
           CPLLLOCK                 : in  STD_LOGIC;        --Lock Detect from the CPLL of the GT
           RXRESETDONE              : in  STD_LOGIC;
           MMCM_LOCK                : in  STD_LOGIC;
           RECCLK_STABLE            : in  STD_LOGIC;
           RECCLK_MONITOR_RESTART   : in  STD_LOGIC:='0';
           DATA_VALID               : in  STD_LOGIC;
           TXUSERRDY                : in  STD_LOGIC;       --TXUSERRDY from GT 
           DONT_RESET_ON_DATA_ERROR : in  STD_LOGIC;       --Used to control the Auto-Reset of FSM when Data Error is detected
           GTRXRESET                : out STD_LOGIC;
           MMCM_RESET               : out STD_LOGIC;
           QPLL_RESET               : out STD_LOGIC:='0';  --Reset QPLL (only if RX uses QPLL)
           CPLL_RESET               : out STD_LOGIC:='0';  --Reset CPLL (only if RX uses CPLL)
           RX_FSM_RESET_DONE        : out STD_LOGIC;       --Reset-sequence has sucessfully been finished.
           RXUSERRDY                : out STD_LOGIC:='0';
           RUN_PHALIGNMENT          : out STD_LOGIC;
           PHALIGNMENT_DONE         : in  STD_LOGIC; 
           RESET_PHALIGNMENT        : out STD_LOGIC:='0';           
           RXDFEAGCHOLD             : out STD_LOGIC;
           RXDFELFHOLD              : out STD_LOGIC;
           RXLPMLFHOLD              : out STD_LOGIC;
           RXLPMHFHOLD              : out STD_LOGIC;
           RETRY_COUNTER            : out STD_LOGIC_VECTOR (RETRY_COUNTER_BITWIDTH-1 downto 0):=(others=>'0')-- Number of 
                                                            -- Retries it took to get the transceiver up and running
           );
end aurora_rx_4l_64b_RX_STARTUP_FSM;

--Interdependencies:
-- * Timing depends on the frequency of the stable clock. Hence counters-sizes
--   are calculated at design-time based on the Generics
--   
-- * if either of the PLLs is reset during TX-startup, it does not need to be reset again by RX
--   => signal which PLL has been reset
-- * 



architecture RTL of aurora_rx_4l_64b_RX_STARTUP_FSM is

  component  aurora_rx_4l_64b_cdc_sync is
    generic (
        C_CDC_TYPE                  : integer range 0 to 2 := 1                 ;
                                    -- 0 is pulse synch
                                    -- 1 is level synch
                                    -- 2 is ack based level sync
        C_RESET_STATE               : integer range 0 to 1 := 0                 ;
                                    -- 0 is reset not needed 
                                    -- 1 is reset needed 
        C_SINGLE_BIT                : integer range 0 to 1 := 1                 ; 
                                    -- 0 is bus input
                                    -- 1 is single bit input
        C_FLOP_INPUT                : integer range 0 to 1 := 0                 ;
        C_VECTOR_WIDTH              : integer range 0 to 32 := 32                             ;
        C_MTBF_STAGES               : integer range 0 to 6 := 2                 
            -- Vector Data witdth
    );

    port (
        prmry_aclk                  : in  std_logic                             ;               --
        prmry_resetn                : in  std_logic                             ;               --
        prmry_in                    : in  std_logic                             ;               --
        prmry_vect_in               : in  std_logic_vector                                      --
                                        (C_VECTOR_WIDTH - 1 downto 0)           ;               --
        prmry_ack                   : out std_logic                             ;
                                                                                                --
        scndry_aclk                 : in  std_logic                             ;               --
        scndry_resetn               : in  std_logic                             ;               --
                                                                                                --
        -- Primary to Secondary Clock Crossing                                                  --
        scndry_out                  : out std_logic                             ;               --
                                                                                                --
        scndry_vect_out             : out std_logic_vector                                      --
                                        (C_VECTOR_WIDTH - 1 downto 0)                           --

    );

   end component;

  type rx_rst_fsm_type is(
    INIT, ASSERT_ALL_RESETS, WAIT_FOR_PLL_LOCK, RELEASE_PLL_RESET, VERIFY_RECCLK_STABLE,
    RELEASE_MMCM_RESET, WAIT_FOR_RXUSRCLK, WAIT_RESET_DONE, DO_PHASE_ALIGNMENT,
    MONITOR_DATA_VALID, FSM_DONE);
    
  signal rx_state : rx_rst_fsm_type := INIT;

  constant MMCM_LOCK_CNT_MAX    : integer := 1024;
  constant STARTUP_DELAY        : integer := 500;--AR43482: Transceiver needs to wait for 500 ns after configuration
  constant WAIT_CYCLES          : integer := STARTUP_DELAY / STABLE_CLOCK_PERIOD; -- Number of Clock-Cycles to wait after configuration
  constant WAIT_MAX             : integer := WAIT_CYCLES + 10;                    -- 500 ns plus some additional margin
  constant WAIT_TIMEOUT_2ms     : integer := 3000000 / STABLE_CLOCK_PERIOD;--  2 ms time-out
  constant WAIT_TLOCK_MAX       : integer :=  100000 / STABLE_CLOCK_PERIOD;--100 us time-out
  constant WAIT_TIMEOUT_500us   : integer :=  500000 / STABLE_CLOCK_PERIOD;--500 us time-out
  constant WAIT_TIMEOUT_1us     : integer :=  1000 / STABLE_CLOCK_PERIOD;  --1 us time-out
  constant WAIT_TIMEOUT_100us   : integer := 100000 / STABLE_CLOCK_PERIOD; --100 us time-out
  constant WAIT_TIME_ADAPT      : integer := (37000000 /integer(6.413))/STABLE_CLOCK_PERIOD;
  constant WAIT_TIME_MAX        : integer := 100 ; --10 us time-out
    
  signal init_wait_count        : integer range 0 to WAIT_MAX:=0;
  signal init_wait_done         : std_logic := '0';
  signal pll_reset_asserted     : std_logic := '0';
  signal rx_fsm_reset_done_int  : std_logic := '0';
  signal rx_fsm_reset_done_int_s2  : std_logic := '0';
  signal rx_fsm_reset_done_int_s3  : std_logic := '0';
   
  signal rxresetdone_s2         : std_logic := '0'; 
  signal rxresetdone_s3         : std_logic := '0'; 

  constant MAX_RETRIES          : integer := 2**RETRY_COUNTER_BITWIDTH-1; 
  signal retry_counter_int      : integer range 0 to MAX_RETRIES := 0;  
  signal time_out_counter       : integer range 0 to WAIT_TIMEOUT_2ms := 0;
  signal recclk_mon_restart_count : integer range 0 to 3:= 0;
  signal recclk_mon_count_reset   : std_logic := '0';
  
  signal reset_time_out         : std_logic := '0';
  signal time_out_2ms           : std_logic := '0';--\Flags that the various time-out points 
  signal time_tlock_max         : std_logic := '0';--|have been reached.
  signal time_out_500us         : std_logic := '0';--|
  signal time_out_1us           : std_logic := '0';--/
  signal time_out_100us         : std_logic := '0';--/
  signal check_tlock_max        : std_logic := '0';
    
  signal mmcm_lock_count        : integer range 0 to MMCM_LOCK_CNT_MAX-1:=0;
  signal mmcm_lock_int          : std_logic := '0';
  signal mmcm_lock_i            : std_logic := '0';
  signal mmcm_lock_reclocked    : std_logic := '0';
  signal gtrxreset_i            : std_logic := '0';
  signal gtrxreset_s            : std_logic := '0';
  signal mmcm_reset_i           : std_logic := '1';
  signal rxpmaresetdone_i       : std_logic := '0';
  signal txpmaresetdone_i       : std_logic := '0';
  signal rxpmaresetdone_ss      : std_logic := '0';
  signal rxpmaresetdone_sync    : std_logic ;
  signal txpmaresetdone_sync    : std_logic ;
  signal rxpmaresetdone_s       : std_logic ;
  signal rxpmaresetdone_rx_s    : std_logic ;
  signal pmaresetdone_fallingedge_detect    : std_logic ;
  signal pmaresetdone_fallingedge_detect_s    : std_logic ;
    
  signal run_phase_alignment_int: std_logic := '0';
  signal run_phase_alignment_int_s2 : std_logic := '0';
  signal run_phase_alignment_int_s3 : std_logic := '0';

  constant MAX_WAIT_BYPASS        : integer := 5000;--5000 RXUSRCLK cycles is the max time for Multi lanes designs
  signal wait_bypass_count        : integer range 0 to MAX_WAIT_BYPASS-1;
  signal time_out_wait_bypass     : std_logic := '0';
  signal time_out_wait_bypass_s2   : std_logic := '0';
  signal time_out_wait_bypass_s3   : std_logic := '0';

  signal refclk_lost              : std_logic;

  signal time_out_adapt           : std_logic := '0';   
  signal adapt_count_reset        : std_logic := '0';   
  signal adapt_count              : integer range 0 to WAIT_TIME_ADAPT-1;
  signal      data_valid_sync: std_logic := '0';
  signal      cplllock_sync: std_logic := '0';
  signal      qplllock_sync: std_logic := '0';
  signal      cplllock_prev: std_logic := '0';
  signal      qplllock_prev: std_logic := '0';
  signal      cplllock_ris_edge: std_logic := '0';
  signal      qplllock_ris_edge: std_logic := '0';
  signal      wait_time_cnt : integer range 0 to WAIT_TIME_MAX;
  signal      wait_time_done : std_logic;
begin
  --Alias section, signals used within this module mapped to output ports:
  RETRY_COUNTER     <= STD_LOGIC_VECTOR(TO_UNSIGNED(retry_counter_int,RETRY_COUNTER_BITWIDTH));
  RUN_PHALIGNMENT   <= run_phase_alignment_int;
  RX_FSM_RESET_DONE <= rx_fsm_reset_done_int_s2;
  GTRXRESET <= gtrxreset_i; 
  MMCM_RESET <= mmcm_reset_i; 
  process(STABLE_CLOCK,SOFT_RESET)
  begin
    if (SOFT_RESET = '1') then
        init_wait_done <= '0';
        init_wait_count <= 0 ;
    elsif rising_edge(STABLE_CLOCK) then
      -- The counter starts running when configuration has finished and 
      -- the clock is stable. When its maximum count-value has been reached,
      -- the 500 ns from Answer Record 43482 have been passed.
      if init_wait_count = WAIT_MAX then
        init_wait_done <= '1';
      else
        init_wait_count <= init_wait_count + 1;
      end if;
    end if;
  end process;


  adapt_wait_sim:if(EXAMPLE_SIMULATION = 1) generate
      time_out_adapt <= '1';
  end generate;

  adapt_wait_hw:if(EXAMPLE_SIMULATION = 0) generate
  process(STABLE_CLOCK)
  begin
    if rising_edge(STABLE_CLOCK) then
     if(adapt_count_reset = '1') then
        adapt_count    <= 0;
        time_out_adapt <= '0';
     elsif(adapt_count = WAIT_TIME_ADAPT -1) then
        time_out_adapt <= '1';
     else 
        adapt_count    <= adapt_count + 1;  
     end if;
    end if;
  end process;
  end generate;

 
 process(RXOUTCLK,gtrxreset_s)
 begin
  if (gtrxreset_s = '1') then
    rxpmaresetdone_i <= '0';
  elsif rising_edge(RXOUTCLK) then
    rxpmaresetdone_i <= rxpmaresetdone_rx_s;
      end if;
 end process;

gtrxreset_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 1             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3                
   )
port map   
   (
     prmry_aclk      => STABLE_CLOCK                      ,
     prmry_resetn    => '1'                               ,
     prmry_in        => gtrxreset_i                       ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => RXOUTCLK                          ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => gtrxreset_s                       ,
     scndry_vect_out => open  
    );

sync_pmaresetdone_fallingedge_detect_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 1             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3                
   )
port map   
   (
     prmry_aclk      => STABLE_CLOCK                      ,
     prmry_resetn    => '1'                               ,
     prmry_in        => pmaresetdone_fallingedge_detect   ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => RXOUTCLK                          ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => pmaresetdone_fallingedge_detect_s ,
     scndry_vect_out => open  
    );

sync_rxpmaresetdone_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 1             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3  
   )
port map   
   (
     prmry_aclk      => RXOUTCLK                          ,
     prmry_resetn    => '1'                               ,
     prmry_in        => rxpmaresetdone_i                  ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => STABLE_CLOCK                      ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => rxpmaresetdone_sync               ,
     scndry_vect_out => open  
    );

sync_rxpmaresetdone_rx_s_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 0             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3                
   )
port map   
   (
     prmry_aclk      => '0'                               ,
     prmry_resetn    => '1'                               ,
     prmry_in        => RXPMARESETDONE                    ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => RXOUTCLK                          ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => rxpmaresetdone_rx_s               ,
     scndry_vect_out => open  
    );

  pmaresetdone_fallingedge_detect <= '0';
  retries_recclk_monitor:process(STABLE_CLOCK)
  begin
    --This counter monitors, how many retries the RECCLK monitor
    --runs. If during startup too many retries are necessary, the whole 
    --initialisation-process of the transceivers gets restarted.
    if rising_edge(STABLE_CLOCK) then  
      if recclk_mon_count_reset = '1' then
        recclk_mon_restart_count <= 0;
      elsif RECCLK_MONITOR_RESTART = '1' then
        if recclk_mon_restart_count = 3 then
          recclk_mon_restart_count <= 0;
        else 
          recclk_mon_restart_count <= recclk_mon_restart_count + 1;
        end if;
      end if;
    end if;
  end process;
  
  timeouts:process(STABLE_CLOCK)
  begin
    if rising_edge(STABLE_CLOCK) then
      -- One common large counter for generating three time-out signals.
      -- Intermediate time-outs are derived from calculated values, based
      -- on the period of the provided clock.
      if reset_time_out = '1' then
        time_out_counter  <= 0;
        time_out_2ms      <= '0';
        time_tlock_max    <= '0';
        time_out_500us    <= '0';
        time_out_1us      <= '0';
        time_out_100us    <= '0';
      else
        if time_out_counter = WAIT_TIMEOUT_2ms then
          time_out_2ms <= '1';
        else
          time_out_counter <= time_out_counter + 1;
        end if;
        
        if (time_out_counter > WAIT_TLOCK_MAX) and (check_tlock_max='1') then
          time_tlock_max <= '1';
        end if;
      
        if time_out_counter = WAIT_TIMEOUT_500us then
          time_out_500us <= '1';
        end if;
      
        if time_out_counter = WAIT_TIMEOUT_1us then
          time_out_1us <= '1';
        end if;

        if time_out_counter = WAIT_TIMEOUT_100us then
          time_out_100us <= '1';
        end if;

      end if;
    end if;
  end process;



  mmcm_lock_wait:process(STABLE_CLOCK)
  begin
    --The lock-signal from the MMCM is not immediately used but 
    --enabling a counter. Only when the counter hits its maximum,
    --the MMCM is considered as "really" locked. 
    --The counter avoids that the FSM already starts on only a 
    --coarse lock of the MMCM (=toggling of the LOCK-signal).
    if rising_edge(STABLE_CLOCK) then
      if mmcm_lock_i = '0' then
        mmcm_lock_count <= 0;
        mmcm_lock_reclocked   <= '0';
      else       
        if mmcm_lock_count < MMCM_LOCK_CNT_MAX - 1 then
          mmcm_lock_count <= mmcm_lock_count + 1;
        else
          mmcm_lock_reclocked <= '1';
        end if;
      end if;
    end if;
  end process;
  

  -- Clock Domain Crossing

sync_run_phase_alignment_int_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 1             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3                
   )
port map   
   (
     prmry_aclk      => STABLE_CLOCK                      ,
     prmry_resetn    => '1'                               ,
     prmry_in        => run_phase_alignment_int           ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => RXUSERCLK                         ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => run_phase_alignment_int_s2        ,
     scndry_vect_out => open  
    );

sync_rx_fsm_reset_done_int_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 1             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3                
   )
port map   
   (
     prmry_aclk      => STABLE_CLOCK                      ,
     prmry_resetn    => '1'                               ,
     prmry_in        => rx_fsm_reset_done_int             ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => RXUSERCLK                         ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => rx_fsm_reset_done_int_s2          ,
     scndry_vect_out => open  
    );

  process(RXUSERCLK)
  begin
    if rising_edge(RXUSERCLK) then
      run_phase_alignment_int_s3   <=  run_phase_alignment_int_s2;

      rx_fsm_reset_done_int_s3     <=  rx_fsm_reset_done_int_s2;
    end if;
  end process;

sync_RXRESETDONE_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 1             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3   
   )
port map   
   (
     prmry_aclk      => RXUSERCLK                         ,
     prmry_resetn    => '1'                               ,
     prmry_in        => RXRESETDONE                       ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => STABLE_CLOCK                      ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => rxresetdone_s2                    ,
     scndry_vect_out => open  
    );

sync_time_out_wait_bypass_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 1             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3    
   )
port map   
   (
     prmry_aclk      => RXUSERCLK                         ,
     prmry_resetn    => '1'                               ,
     prmry_in        => time_out_wait_bypass              ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => STABLE_CLOCK                      ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => time_out_wait_bypass_s2           ,
     scndry_vect_out => open  
    );

sync_mmcm_lock_reclocked_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 0             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3    
   )
port map   
   (
     prmry_aclk      => '0'                               ,
     prmry_resetn    => '1'                               ,
     prmry_in        => MMCM_LOCK                         ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => STABLE_CLOCK                      ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => mmcm_lock_i                       ,
     scndry_vect_out => open  
    );

  data_valid_sync <= DATA_VALID;

  process(STABLE_CLOCK)
  begin
    if rising_edge(STABLE_CLOCK) then
       rxresetdone_s3     <= rxresetdone_s2;

       time_out_wait_bypass_s3 <=  time_out_wait_bypass_s2;

       cplllock_prev           <=  cplllock_sync;
       qplllock_prev           <=  qplllock_sync;
    end if;
  end process;

sync_CPLLLOCK_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 0             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3  
   )
port map   
   (
     prmry_aclk      => '0'                               ,
     prmry_resetn    => '1'                               ,
     prmry_in        => CPLLLOCK                          ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => STABLE_CLOCK                      ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => cplllock_sync                     ,
     scndry_vect_out => open  
    );

sync_QPLLLOCK_cdc_sync : aurora_rx_4l_64b_cdc_sync
generic map
   (
     c_cdc_type      => 1             ,   
     c_flop_input    => 0             ,  
     c_reset_state   => 0             ,  
     c_single_bit    => 1             ,  
     c_vector_width  => 2             ,  
     c_mtbf_stages   => 3   
   )
port map   
   (
     prmry_aclk      => '0'                               ,
     prmry_resetn    => '1'                               ,
     prmry_in        => QPLLLOCK                          ,
     prmry_vect_in   => "00"                              ,
     scndry_aclk     => STABLE_CLOCK                      ,
     scndry_resetn   => '1'                               ,
     prmry_ack       => open                              ,
     scndry_out      => qplllock_sync                     ,
     scndry_vect_out => open  
    );



  process (STABLE_CLOCK)
  begin
    if rising_edge(STABLE_CLOCK) then
     if(SOFT_RESET = '1' ) then
       cplllock_ris_edge <= '0';
     elsif((cplllock_prev = '0') and (cplllock_sync = '1')) then
       cplllock_ris_edge <= '1';
     elsif(rx_state = ASSERT_ALL_RESETS or rx_state = RELEASE_PLL_RESET) then
       cplllock_ris_edge <= cplllock_ris_edge;
     else 
       cplllock_ris_edge <= '0';
     end if;
    end if;
  end process;

  process (STABLE_CLOCK)
  begin
    if rising_edge(STABLE_CLOCK) then
     if(SOFT_RESET = '1' ) then
       qplllock_ris_edge <= '0';
     elsif((qplllock_prev = '0') and (qplllock_sync = '1')) then
       qplllock_ris_edge <= '1';
     elsif(rx_state = ASSERT_ALL_RESETS or rx_state = RELEASE_PLL_RESET) then
       qplllock_ris_edge <= qplllock_ris_edge;
     else 
       qplllock_ris_edge <= '0';
     end if;
    end if;
  end process;


  timeout_buffer_bypass:process(RXUSERCLK)
  begin
    if rising_edge(RXUSERCLK) then
      if run_phase_alignment_int_s3 = '0' then
        wait_bypass_count     <= 0;
        time_out_wait_bypass  <= '0';
      elsif (run_phase_alignment_int_s3 = '1') and (rx_fsm_reset_done_int_s3 = '0') then
        if wait_bypass_count = MAX_WAIT_BYPASS - 1 then
          time_out_wait_bypass <= '1';
        else
          wait_bypass_count <= wait_bypass_count + 1;
        end if;
      end if;
    end if;
  end process;

   refclk_lost <= '1' when ((RX_QPLL_USED and QPLLREFCLKLOST='1') or (not RX_QPLL_USED and CPLLREFCLKLOST='1')) else '0';



  timeout_max:process(STABLE_CLOCK)
  begin
    if rising_edge(STABLE_CLOCK) then
        if((rx_state = ASSERT_ALL_RESETS) or
          (rx_state = RELEASE_MMCM_RESET)) then
            wait_time_cnt <= WAIT_TIME_MAX;
        elsif (wait_time_cnt > 0 ) then
            wait_time_cnt <= wait_time_cnt - 1;
          end if;
       end if;
   end process;

  wait_time_done <= '1' when (wait_time_cnt = 0) else '0';
 
  --FSM for resetting the GTX/GTH/GTP in the 7-series. 
  --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  --
  -- Following steps are performed:
  -- 1) After configuration wait for approximately 500 ns as specified in 
  --    answer-record 43482
  -- 2) Assert all resets on the GT and on an MMCM potentially connected. 
  --    After that wait until a reference-clock has been detected.
  -- 3) Release the reset to the GT and wait until the GT-PLL has locked.
  -- 4) Release the MMCM-reset and wait until the MMCM has signalled lock.
  --    Also get info from the TX-side which PLL has been reset.
  -- 5) Wait for the RESET_DONE-signal from the GT.
  -- 6) Signal to start the phase-alignment procedure and wait for it to 
  --    finish.
  -- 7) Reset-sequence has successfully run through. Signal this to the 
  --    rest of the design by asserting RX_FSM_RESET_DONE.
  
  reset_fsm:process(STABLE_CLOCK)
  begin
    if rising_edge(STABLE_CLOCK) then
      if (SOFT_RESET = '1' ) then
      --if (SOFT_RESET = '1' or (not(rx_state = INIT) and not(rx_state = ASSERT_ALL_RESETS) and refclk_lost = '1')) then
        rx_state                <= INIT;
        RXUSERRDY               <= '0';
        gtrxreset_i             <= '0';
        mmcm_reset_i            <= '1';
        rx_fsm_reset_done_int   <= '0';
        QPLL_RESET              <= '0';
        CPLL_RESET              <= '0';
        pll_reset_asserted      <= '0';
        reset_time_out          <= '1';
        retry_counter_int       <=  0;
        run_phase_alignment_int <= '0';
        check_tlock_max         <= '0';
        RESET_PHALIGNMENT       <= '1';
        recclk_mon_count_reset  <= '1';
        adapt_count_reset       <= '1';
        RXDFEAGCHOLD            <= '0';
        RXDFELFHOLD             <= '0';
        RXLPMLFHOLD             <= '0';
        RXLPMHFHOLD             <= '0';

      else
        
        case rx_state is
          when INIT => 
            --Initial state after configuration. This state will be left after
            --approx. 500 ns and not be re-entered. 
            if init_wait_done = '1' then
              rx_state  <= ASSERT_ALL_RESETS;
            end if;
            
          when ASSERT_ALL_RESETS => 
            --This is the state into which the FSM will always jump back if any
            --time-outs will occur. 
            --The number of retries is reported on the output RETRY_COUNTER. In 
            --case the transceiver never comes up for some reason, this machine 
            --will still continue its best and rerun until the FPGA is turned off
            --or the transceivers come up correctly.
             if RX_QPLL_USED then
              if pll_reset_asserted = '0' then
                QPLL_RESET          <= '1';
                pll_reset_asserted  <= '1';
              else
                QPLL_RESET          <= '0';
              end if;
            else
              if pll_reset_asserted = '0' then
                CPLL_RESET <= '1';
                pll_reset_asserted  <= '1';
              else
                CPLL_RESET          <= '0';
              end if;  
            end if;                  


            RXUSERRDY               <= '0';
            gtrxreset_i             <= '1';
            mmcm_reset_i            <= '1';
            run_phase_alignment_int <= '0';    
            RESET_PHALIGNMENT       <= '1';
            check_tlock_max         <= '0';
            recclk_mon_count_reset  <= '1';
            adapt_count_reset       <= '1';
            

            if (RX_QPLL_USED  and (qplllock_sync = '0') and pll_reset_asserted = '1') or
               (not RX_QPLL_USED  and (cplllock_sync = '0') and pll_reset_asserted = '1') then
              rx_state  <= WAIT_FOR_PLL_LOCK;
              reset_time_out          <= '1';
            end if;           
           
          when  WAIT_FOR_PLL_LOCK =>
              if(wait_time_done = '1') then
                 rx_state        <=  RELEASE_PLL_RESET;  
            end if;
 
          when RELEASE_PLL_RESET => 
            --PLL-Reset of the GTX gets released and the time-out counter
            --starts running.
            pll_reset_asserted  <= '0';
            reset_time_out  <= '0';
            
            if (RX_QPLL_USED     and not TX_QPLL_USED and (qplllock_sync = '1')) or
               (not RX_QPLL_USED and TX_QPLL_USED     and (cplllock_sync = '1')) then
              rx_state                <= VERIFY_RECCLK_STABLE;
              reset_time_out          <= '1';
              recclk_mon_count_reset  <= '0';
              adapt_count_reset       <= '0';
            elsif (RX_QPLL_USED and (qplllock_sync = '1')) or
                  (not RX_QPLL_USED and (cplllock_sync = '1')) then
              rx_state                <= VERIFY_RECCLK_STABLE;
              reset_time_out          <= '1';
              recclk_mon_count_reset  <= '0';
              adapt_count_reset       <= '0';
            end if;
            
            if time_out_2ms = '1' then
              if retry_counter_int = MAX_RETRIES then
                -- If too many retries are performed compared to what is specified in 
                -- the generic, the counter simply wraps around.
                retry_counter_int <= 0;
              else
                retry_counter_int <= retry_counter_int + 1;
              end if;
              rx_state            <= ASSERT_ALL_RESETS; 
            end if;           

          when VERIFY_RECCLK_STABLE =>
            --reset_time_out  <= '0';
            --Time-out counter is not released in this state as here the FSM
            --does not wait for a certain period of time but checks on the number
            --of retries in the RECCLK monitor 
            gtrxreset_i <= '0';
            if RECCLK_STABLE = '1' then
              rx_state        <= RELEASE_MMCM_RESET;
              reset_time_out  <= '1';
              
            end if;          

            if recclk_mon_restart_count = 2 then
              --If two retries are performed in the RECCLK monitor
              --the whole initialisation-sequence gets restarted.
              if retry_counter_int = MAX_RETRIES then
                -- If too many retries are performed compared to what is specified in 
                -- the generic, the counter simply wraps around.
                retry_counter_int <= 0;
              else
                retry_counter_int <= retry_counter_int + 1;
              end if;
              rx_state            <= ASSERT_ALL_RESETS; 
            end if;            
          
          when RELEASE_MMCM_RESET => 
            --Release of the MMCM-reset. Waiting for the MMCM to lock.
            check_tlock_max <= '1';
            
            mmcm_reset_i <= '0';
            reset_time_out  <= '0';
         
            if mmcm_lock_reclocked = '1' then
              rx_state <= WAIT_FOR_RXUSRCLK;
              reset_time_out  <= '1';
            end if;          
            
            if (time_tlock_max = '1' and reset_time_out = '0' )then
              if retry_counter_int = MAX_RETRIES then
                -- If too many retries are performed compared to what is specified in 
                -- the generic, the counter simply wraps around.
                retry_counter_int <= 0;
              else
                retry_counter_int <= retry_counter_int + 1;
              end if;
              rx_state            <= ASSERT_ALL_RESETS; 
            end if;            
 
           when WAIT_FOR_RXUSRCLK =>
              if wait_time_done = '1' then
               rx_state <=  WAIT_RESET_DONE;  
            end if;
           
          when WAIT_RESET_DONE => 
            --When TXOUTCLK is the source for RXUSRCLK, RXUSERRDY depends on TXUSERRDY
            --If RXOUTCLK is the source for RXUSRCLK, TXUSERRDY can be tied to '1'
            if TXUSERRDY = '1' then
               RXUSERRDY <= '1';
            end if;
            reset_time_out  <= '0';
            if rxresetdone_s3 = '1' then
              rx_state        <= DO_PHASE_ALIGNMENT; 
              reset_time_out  <= '1';
            end if;          

            if time_out_2ms = '1' and reset_time_out = '0' then
              if retry_counter_int = MAX_RETRIES then
                -- If too many retries are performed compared to what is specified in 
                -- the generic, the counter simply wraps around.
                retry_counter_int <= 0;
              else
                retry_counter_int <= retry_counter_int + 1;
              end if;
              rx_state            <= ASSERT_ALL_RESETS; 
            end if;            
          
          when DO_PHASE_ALIGNMENT => 
            --The direct handling of the signals for the Phase Alignment is done outside
            --this state-machine. 
            RESET_PHALIGNMENT       <= '0';
            run_phase_alignment_int <= '1';
            reset_time_out          <= '0';
            
            if PHALIGNMENT_DONE = '1' then
              rx_state        <= MONITOR_DATA_VALID;
              reset_time_out  <= '1';
            end if;
            
            if time_out_wait_bypass_s3 = '1' then
              if retry_counter_int = MAX_RETRIES then
                -- If too many retries are performed compared to what is specified in 
                -- the generic, the counter simply wraps around.
                retry_counter_int <= 0;
              else
                retry_counter_int <=  retry_counter_int + 1;
              end if;
              rx_state            <= ASSERT_ALL_RESETS; 
            end if;           
          
          when MONITOR_DATA_VALID => 
              reset_time_out  <= '0';

              if(time_out_100us = '1' and data_valid_sync ='0' and DONT_RESET_ON_DATA_ERROR = '0' and reset_time_out = '0')  then
                 rx_state              <= ASSERT_ALL_RESETS; 
                 rx_fsm_reset_done_int <= '0';
              elsif (data_valid_sync = '1') then
                 rx_state              <= FSM_DONE; 
                 rx_fsm_reset_done_int <= '0';
                 reset_time_out        <= '1';
              end if;
 
         when FSM_DONE =>
            reset_time_out  <= '0';
            if data_valid_sync = '0' then
               rx_fsm_reset_done_int <= '0';
               reset_time_out        <= '1';
               rx_state              <= MONITOR_DATA_VALID;
            elsif(time_out_1us = '1' and reset_time_out = '0')  then
               rx_fsm_reset_done_int <= '1';
            end if;

                  RXDFEAGCHOLD  <=  '0';
                  RXDFELFHOLD   <=  '0';
                  RXLPMHFHOLD   <=  '0';
                  RXLPMLFHOLD   <=  '0';
           when OTHERS => 
              rx_state                <= INIT;
        end case;
      end if;
    end if;
  end process;

end RTL;
