-------------------------------------------------------------------------------
-- Title      : Deterministic Xilinx GTP wrapper - Spartan-6 top module
-- Project    : White Rabbit Switch
-------------------------------------------------------------------------------
-- File       : wr_gtp_phy_spartan6.vhd
-- Author     : Tomasz Wlostowski
-- Company    : CERN BE-CO-HT
-- Created    : 2010-11-18
-- Last update: 2011-11-05
-- Platform   : FPGA-generic
-- Standard   : VHDL'93
-------------------------------------------------------------------------------
-- Description: Dual channel wrapper for Xilinx Spartan-6 GTP adapted for
-- deterministic delays at 1.25 Gbps.
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 CERN / Tomasz Wlostowski
--
-- This source file is free software; you can redistribute it   
-- and/or modify it under the terms of the GNU Lesser General   
-- Public License as published by the Free Software Foundation; 
-- either version 2.1 of the License, or (at your option) any   
-- later version.                                               
--
-- This source is distributed in the hope that it will be       
-- useful, but WITHOUT ANY WARRANTY; without even the implied   
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      
-- PURPOSE.  See the GNU Lesser General Public License for more 
-- details.                                                     
--
-- You should have received a copy of the GNU Lesser General    
-- Public License along with this source; if not, download it   
-- from http://www.gnu.org/licenses/lgpl-2.1.html
-- 
--
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author    Description
-- 2010-11-18  0.4      twlostow  Initial release
-- 2011-02-07  0.5      twlostow  Verified on Spartan6 GTP (single channel only)
-- 2011-05-15  0.6      twlostow  Added reference clock output
-------------------------------------------------------------------------------

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

library unisim;
use unisim.all;

library work;
use work.gencores_pkg.all;
use work.disparity_gen_pkg.all;


entity wr_gxb_arriaii is

  generic (
    -- set to non-zero value to speed up the simulation by reducing some delays
    g_simulation         : integer := 1;
    g_ch0_use_refclk_out : boolean := false;
    g_ch1_use_refclk_out : boolean := false;
    g_ch0_refclk_input   : integer := 0;
    g_ch1_refclk_input   : integer := 0;
    g_force_disparity    : integer := 0
    );

  port (
    cal_blk_clk : in std_logic;
		
    -- Port 0

    -- TX path, synchronous to ch0_ref_clk_i
    ch0_ref_clk_i : in  std_logic;
    ch0_ref_clk_o : out std_logic;

    -- data input (8 bits, not 8b10b-encoded)
    ch0_tx_data_i : in std_logic_vector(7 downto 0);

    -- 1 when tx_data_i contains a control code, 0 when it's a data byte
    ch0_tx_k_i : in std_logic;

    -- disparity of the currently transmitted 8b10b code (1 = plus, 0 = minus).
    -- Necessary for the PCS to generate proper frame termination sequences.
    ch0_tx_disparity_o : out std_logic;

    -- Encoding error indication (1 = error, 0 = no error)
    ch0_tx_enc_err_o : out std_logic;


    -- RX path, synchronous to ch0_rx_rbclk_o.

    -- RX recovered clock
    ch0_rx_rbclk_o : out std_logic;

    -- 8b10b-decoded data output. The data output must be kept invalid before
    -- the transceiver is locked on the incoming signal to prevent the EP from
    -- detecting a false carrier.
    ch0_rx_data_o : out std_logic_vector(7 downto 0);

    -- 1 when the byte on rx_data_o is a control code
    ch0_rx_k_o : out std_logic;

    -- encoding error indication
    ch0_rx_enc_err_o : out std_logic;

    -- RX bitslide indication, indicating the delay of the RX path of the
    -- transceiver (in UIs). Must be valid when ch0_rx_data_o is valid.
    ch0_rx_bitslide_o : out std_logic_vector(3 downto 0);

    -- reset input, active hi
    ch0_rst_i : in std_logic;

    -- local loopback enable (Tx->Rx), active hi
    ch0_loopen_i : in std_logic;

-- Port 1
    ch1_ref_clk_i : in std_logic;

    ch1_ref_clk_o      : out std_logic;
    ch1_tx_data_i      : in  std_logic_vector(7 downto 0) := "00000000";
    ch1_tx_k_i         : in  std_logic                    := '0';
    ch1_tx_disparity_o : out std_logic;
    ch1_tx_enc_err_o   : out std_logic;

    ch1_rx_data_o     : out std_logic_vector(7 downto 0);
    ch1_rx_rbclk_o    : out std_logic;
    ch1_rx_k_o        : out std_logic;
    ch1_rx_enc_err_o  : out std_logic;
    ch1_rx_bitslide_o : out std_logic_vector(3 downto 0);

    ch1_rst_i    : in std_logic := '0';
    ch1_loopen_i : in std_logic := '0';

-- Serial I/O

    pad_txn0_o : out std_logic;
    pad_txp0_o : out std_logic;

    pad_rxn0_i : in std_logic := '0';
    pad_rxp0_i : in std_logic := '0';

    pad_txn1_o : out std_logic;
    pad_txp1_o : out std_logic;

    pad_rxn1_i : in std_logic := '0';
    pad_rxp1_i : in std_logic := '0';

    reconfig_clk : in std_logic
    );


end wr_gxb_arriaii;

architecture rtl of wr_gxb_arriaii is

   component  gxb_wr_alt4gxb IS 
	 GENERIC 
	 (
		starting_channel_number	:	NATURAL := 0
	 );
	 PORT 
	 ( 
		 cal_blk_clk	:		IN  STD_LOGIC := '0';
		 pll_inclk	:		IN  STD_LOGIC := '0';
		 pll_powerdown	:		IN  STD_LOGIC_VECTOR (0 DOWNTO 0) := (OTHERS => '0');
		 reconfig_clk	:		IN  STD_LOGIC := '0';
		 reconfig_fromgxb:		OUT  STD_LOGIC_VECTOR (16 DOWNTO 0);
		 reconfig_togxb	:		IN  STD_LOGIC_VECTOR (3 DOWNTO 0) := (OTHERS => 'Z');
		 rx_analogreset	:		IN  STD_LOGIC_VECTOR (0 DOWNTO 0) := (OTHERS => '0');
		 rx_bitslip	:		IN  STD_LOGIC_VECTOR (0 DOWNTO 0) := (OTHERS => '0');
		 rx_bitslipboundaryselectout:	OUT  STD_LOGIC_VECTOR (4 DOWNTO 0);
		 rx_clkout	:		OUT  STD_LOGIC_VECTOR (0 DOWNTO 0);
		 rx_ctrldetect	:		OUT  STD_LOGIC_VECTOR (0 DOWNTO 0);
		 rx_datain	:		IN  STD_LOGIC_VECTOR (0 DOWNTO 0) := (OTHERS => 'Z');
		 rx_dataout	:		OUT  STD_LOGIC_VECTOR (7 DOWNTO 0);
		 rx_digitalreset:		IN  STD_LOGIC_VECTOR (0 DOWNTO 0) := (OTHERS => '0');
		 rx_errdetect	:		OUT  STD_LOGIC_VECTOR (0 DOWNTO 0);
		 rx_freqlocked	:		OUT  STD_LOGIC_VECTOR (0 DOWNTO 0);
		 rx_patterndetect:		OUT  STD_LOGIC_VECTOR (0 DOWNTO 0);
		 rx_runningdisp	:		OUT  STD_LOGIC_VECTOR (0 DOWNTO 0);
		 rx_seriallpbken:		IN  STD_LOGIC_VECTOR (0 DOWNTO 0) := (OTHERS => '0');
		 tx_bitslipboundaryselect:	IN  STD_LOGIC_VECTOR (4 DOWNTO 0) := (OTHERS => '0');
		 tx_clkout	:		OUT  STD_LOGIC_VECTOR (0 DOWNTO 0);
		 tx_ctrlenable	:		IN  STD_LOGIC_VECTOR (0 DOWNTO 0) := (OTHERS => '0');
		 tx_datain	:		IN  STD_LOGIC_VECTOR (7 DOWNTO 0) := (OTHERS => '0');
		 tx_dataout	:		OUT  STD_LOGIC_VECTOR (0 DOWNTO 0);
		 tx_digitalreset:		IN  STD_LOGIC_VECTOR (0 DOWNTO 0) := (OTHERS => '0')
	 ); 
 END component;

component altgx_reconf
	PORT
	(
		reconfig_clk		: IN STD_LOGIC ;
		reconfig_fromgxb		: IN STD_LOGIC_VECTOR (16 DOWNTO 0);
		busy		: OUT STD_LOGIC ;
		reconfig_togxb		: OUT STD_LOGIC_VECTOR (3 DOWNTO 0)
	);
end component;

  component BUFG
    port (
      O : out std_ulogic;
      I : in  std_ulogic);
  end component;

  component BUFIO2
    generic (
      DIVIDE_BYPASS : boolean := true;
      DIVIDE        : integer := 1;
      I_INVERT      : boolean := false;
      USE_DOUBLER   : boolean := false);
    port (
      DIVCLK       : out std_ulogic;
      IOCLK        : out std_ulogic;
      SERDESSTROBE : out std_ulogic;
      I            : in  std_ulogic);
  end component;

  component gtp_phase_align
    generic(
      g_simulation : integer);
    port (
      gtp_rst_i                   : in  std_logic;
      gtp_tx_clk_i                : in  std_logic;
      gtp_tx_en_pma_phase_align_o : out std_logic;
      gtp_tx_pma_set_phase_o      : out std_logic;
      align_en_i                  : in  std_logic;
      align_done_o                : out std_logic);
  end component;

  component gtp_bitslide
    generic(
      g_simulation : integer;
      g_target     : string := "spartan6");
    port (
      gtp_rst_i                : in  std_logic;
      gtp_rx_clk_i             : in  std_logic;
      gtp_rx_comma_det_i       : in  std_logic;
      gtp_rx_byte_is_aligned_i : in  std_logic;
      serdes_ready_i           : in  std_logic;
      gtp_rx_slide_o           : out std_logic;
      gtp_rx_cdr_rst_o         : out std_logic;
      bitslide_o               : out std_logic_vector(4 downto 0);
      synced_o                 : out std_logic);
  end component;

  signal ch0_gtp_reset        : std_logic;
  signal ch0_gtp_loopback     : std_logic_vector(2 downto 0) := "000";
  signal ch0_gtp_reset_done   : std_logic;
  signal ch0_gtp_pll_lockdet  : std_logic;
  signal ch0_tx_pma_set_phase : std_logic                    := '0';

  signal ch0_tx_rundisp_vec : std_logic_vector(3 downto 0);

  signal ch0_tx_en_pma_phase_align : std_logic := '0';

  signal ch0_rx_data_int                : std_logic_vector(7 downto 0);
  signal ch0_rx_k_int                   : std_logic;
  signal ch0_rx_disperr, ch0_rx_invcode : std_logic;

  signal ch0_rx_byte_is_aligned : std_logic;
  signal ch0_rx_comma_det       : std_logic;
  signal ch0_rx_cdr_rst         : std_logic := '0';
  signal ch0_rx_rec_clk_pad     : std_logic;
  signal ch0_rx_rec_clk         : std_logic;
  signal ch0_rx_divclk          : std_logic;
  signal ch0_rx_slide           : std_logic := '0';

  signal ch0_gtp_locked : std_logic;
  signal ch0_align_done : std_logic;
  signal ch0_rx_synced  : std_logic;

  signal ch0_gtp_clkout_int                                : std_logic_vector(1 downto 0);
  signal ch0_rx_enable_output, ch0_rx_enable_output_synced : std_logic;


  signal ch1_gtp_reset        : std_logic;
  signal ch1_gtp_loopback     : std_logic_vector(2 downto 0) := "000";
  signal ch1_gtp_reset_done   : std_logic;
  signal ch1_gtp_pll_lockdet  : std_logic;
  signal ch1_tx_pma_set_phase : std_logic                    := '0';

  signal ch1_tx_rundisp_vec : std_logic_vector(3 downto 0);

  signal ch1_tx_en_pma_phase_align : std_logic := '0';

  signal ch1_rx_data_int                : std_logic_vector(7 downto 0);
  signal ch1_rx_k_int                   : std_logic;
  signal ch1_rx_disperr, ch1_rx_invcode : std_logic;

  signal ch1_rx_byte_is_aligned : std_logic;
  signal ch1_rx_comma_det       : std_logic;
  signal ch1_rx_cdr_rst         : std_logic := '0';
  signal ch1_rx_rec_clk_pad     : std_logic;
  signal ch1_rx_rec_clk         : std_logic;
  signal ch1_rx_divclk          : std_logic;
  signal ch1_rx_slide           : std_logic := '0';

  signal ch1_gtp_locked : std_logic;
  signal ch1_align_done : std_logic;
  signal ch1_rx_synced  : std_logic;

  signal ch1_gtp_clkout_int                                : std_logic_vector(1 downto 0);
  signal ch1_rx_enable_output, ch1_rx_enable_output_synced : std_logic;

  signal ch0_rst_synced    : std_logic;
  signal ch0_rst_d0        : std_logic;
  signal ch0_reset_counter : unsigned(9 downto 0);

  signal ch1_rst_synced    : std_logic;
  signal ch1_rst_d0        : std_logic;
  signal ch1_reset_counter : unsigned(9 downto 0);

  signal ch0_ref_clk         : std_logic;
  signal ch1_ref_clk         : std_logic;
  signal ch0_ref_clk_out_buf : std_logic;
  signal ch1_ref_clk_out_buf : std_logic;

  signal ch0_rx_bitslide_int : std_logic_vector(4 downto 0);
  signal ch1_rx_bitslide_int : std_logic_vector(4 downto 0);

  signal ch0_ref_clk_in : std_logic_vector(1 downto 0);
  signal ch1_ref_clk_in : std_logic_vector(1 downto 0);


  signal ch0_disparity_set : std_logic;
  signal ch1_disparity_set : std_logic;

  signal ch0_tx_chardispmode : std_logic;
  signal ch1_tx_chardispmode : std_logic;

  signal ch0_tx_chardispval : std_logic;
  signal ch1_tx_chardispval : std_logic;



  component enc_8b10b
    port (
      clk_i     : in  std_logic;
      rst_n_i   : in  std_logic;
      ctrl_i    : in  std_logic;
      in_8b_i   : in  std_logic_vector(7 downto 0);
      err_o     : out std_logic;
      dispar_o  : out std_logic;
      out_10b_o : out std_logic_vector(9 downto 0));
  end component;

  signal ch0_rst_n : std_logic;
  signal ch1_rst_n : std_logic;

  signal ch0_cur_disp  : t_8b10b_disparity;
  signal ch0_disp_pipe : std_logic_vector(1 downto 0);
  signal ch1_cur_disp  : t_8b10b_disparity;
  signal ch1_disp_pipe : std_logic_vector(1 downto 0);
  
  signal reconfig_fromgxb_sig	:	std_logic_vector;
  signal reconfig_togxb_sig	:	std_logic_vector;
  signal busy_sig		:	std_logic;
begin  -- rtl

  ch0_rst_n <= not ch0_gtp_reset;
  ch1_rst_n <= not ch1_gtp_reset;

  gen_disp_ch0 : process(ch0_ref_clk)
  begin
    if rising_edge(ch0_ref_clk) then
      if(ch0_tx_chardispmode = '1' or ch0_rst_n = '0') then
        if(g_force_disparity = 0) then
          ch0_cur_disp <= RD_MINUS;
        else
          ch0_cur_disp <= RD_PLUS;
        end if;
        ch0_disp_pipe <= (others => '0');
      else
        ch0_cur_disp     <= f_next_8b10b_disparity8(ch0_cur_disp, ch0_tx_k_i, ch0_tx_data_i);
        ch0_disp_pipe(0) <= to_std_logic(ch0_cur_disp);
        ch0_disp_pipe(1) <= ch0_disp_pipe(0);
      end if;
    end if;
  end process;

  gen_disp_ch1 : process(ch1_ref_clk)
  begin
    if rising_edge(ch1_ref_clk) then
      if(ch1_tx_chardispmode = '1' or ch1_rst_n = '0') then
        if(g_force_disparity = 0) then
          ch1_cur_disp <= RD_MINUS;
        else
          ch1_cur_disp <= RD_PLUS;
        end if;
        ch1_disp_pipe <= (others => '0');
      else
        ch1_cur_disp     <= f_next_8b10b_disparity8(ch1_cur_disp, ch1_tx_k_i, ch1_tx_data_i);
        ch1_disp_pipe(0) <= to_std_logic(ch1_cur_disp);
        ch1_disp_pipe(1) <= ch1_disp_pipe(0);
      end if;
    end if;
  end process;

  ch0_tx_disparity_o <= ch0_disp_pipe(0);
  ch1_tx_disparity_o <= ch1_disp_pipe(1);

  p_gen_reset_ch0 : process(ch0_ref_clk)
  begin
    if rising_edge(ch0_ref_clk) then

      ch0_rst_d0     <= ch0_rst_i;
      ch0_rst_synced <= ch0_rst_d0;

      if(ch0_rst_synced = '1') then
        ch0_reset_counter <= (others => '0');
      else
        if(ch0_reset_counter(ch0_reset_counter'left) = '0') then
          ch0_reset_counter <= ch0_reset_counter + 1;
        end if;
      end if;
    end if;
  end process;


  p_gen_reset_ch1 : process(ch1_ref_clk)
  begin
    if rising_edge(ch1_ref_clk) then

      ch1_rst_d0     <= ch1_rst_i;
      ch1_rst_synced <= ch1_rst_d0;

      if(ch1_rst_synced = '1') then
        ch1_reset_counter <= (others => '0');
      else
        if(ch1_reset_counter(ch1_reset_counter'left) = '0') then
          ch1_reset_counter <= ch1_reset_counter + 1;
        end if;
      end if;
    end if;
  end process;


  ch0_gtp_reset <= ch0_rst_synced or std_logic(not ch0_reset_counter(ch0_reset_counter'left));
  ch1_gtp_reset <= ch1_rst_synced or std_logic(not ch1_reset_counter(ch1_reset_counter'left));

  ch0_rx_rec_clk_pad <= ch0_gtp_clkout_int(1);
  ch1_rx_rec_clk_pad <= ch1_gtp_clkout_int(1);
	
	altgx_reconf_inst : altgx_reconf PORT MAP (
		reconfig_clk	 	=> reconfig_clk,
		reconfig_fromgxb	=> reconfig_fromgxb_sig,
		busy			=> busy_sig,
		reconfig_togxb		=> reconfig_togxb_sig
	);
	
	gxb_inst: gxb_wr_alt4gxb 
	port map (
		cal_blk_clk => cal_blk_clk,
		pll_inclk => ch0_ref_clk_i, 
		pll_powerdown => "0",
		reconfig_clk => reconfig_clk,
		reconfig_fromgxb => reconfig_fromgxb_sig,
		reconfig_togxb => reconfig_togxb_sig,
		rx_analogreset(0) => ch0_rx_cdr_rst,
		rx_bitslip(0) => ch0_rx_slide,
		rx_bitslipboundaryselectout => open,
		rx_clkout => open,
		rx_ctrldetect => open,
		rx_datain(0) => pad_rxp0_i,
		rx_dataout => ch0_rx_data_int,
		rx_digitalreset(0) => ch0_gtp_reset,
		rx_errdetect => open,
		rx_freqlocked(0) => ch0_gtp_pll_lockdet,
		rx_patterndetect(0) => ch0_rx_comma_det,
		rx_runningdisp(0) => ch0_rx_disperr,
		rx_seriallpbken => "0",
		
		tx_bitslipboundaryselect => open,
		tx_clkout(0) => ch0_gtp_clkout_int(0),
		tx_ctrlenable(0) => ch0_tx_k_i,
		tx_datain => ch0_tx_data_i,
		tx_dataout(0) => pad_txp0_o,
		tx_digitalreset(0) => ch0_gtp_reset
	);

  gen1 : if(g_ch0_use_refclk_out) generate

    refbuf_ch0 : BUFIO2
      port map (
        DIVCLK       => ch0_ref_clk_out_buf,
        IOCLK        => open,
        SERDESSTROBE => open,
        I            => ch0_gtp_clkout_int(0));

    refbufg_ch0 : BUFG
      port map (
        I => ch0_ref_clk_out_buf,
        O => ch0_ref_clk);
  end generate gen1;

  gen2 : if(g_ch1_use_refclk_out) generate

    refbuf_ch1 : BUFIO2
      port map (
        DIVCLK       => ch1_ref_clk_out_buf,
        IOCLK        => open,
        SERDESSTROBE => open,
        I            => ch1_gtp_clkout_int(0));

    refbufg_ch1 : BUFG
      port map (
        I => ch1_ref_clk_out_buf,
        O => ch1_ref_clk);
  end generate gen2;



  gen3 : if(not g_ch0_use_refclk_out) generate
    ch0_ref_clk <= ch0_ref_clk_i;
  end generate gen3;

  gen4 : if(not g_ch1_use_refclk_out) generate
    ch1_ref_clk <= ch1_ref_clk_i;
  end generate gen4;



  ch0_ref_clk_in(g_ch0_refclk_input)   <= ch0_ref_clk_i;
  ch0_ref_clk_in(1-g_ch0_refclk_input) <= '0';

  ch1_ref_clk_in(g_ch1_refclk_input)   <= ch1_ref_clk_i;
  ch1_ref_clk_in(1-g_ch1_refclk_input) <= '0';




  U_Rbclk_buf_ch0 : BUFIO2
    port map (
      DIVCLK       => ch0_rx_divclk,
      IOCLK        => open,
      SERDESSTROBE => open,
      I            => ch0_rx_rec_clk_pad);

  U_Rbclk_bufg_ch0 : BUFG
    port map (
      I => ch0_rx_divclk,
      O => ch0_rx_rec_clk
      );

  U_Rbclk_buf_ch1 : BUFIO2
    port map (
      DIVCLK       => ch1_rx_divclk,
      IOCLK        => open,
      SERDESSTROBE => open,
      I            => ch1_rx_rec_clk_pad);

  U_Rbclk_bufg_ch1 : BUFG
    port map (
      I => ch1_rx_divclk,
      O => ch1_rx_rec_clk
      );

  
  ch0_gtp_locked   <= ch0_gtp_pll_lockdet and ch0_gtp_reset_done;
  ch0_tx_enc_err_o <= '0';

  ch1_gtp_locked   <= ch1_gtp_pll_lockdet and ch1_gtp_reset_done;
  ch1_tx_enc_err_o <= '0';

  U_align_ch0 : gtp_phase_align
    generic map (
      g_simulation => g_simulation) 
    port map (
      gtp_rst_i                   => ch0_gtp_reset,
      gtp_tx_clk_i                => ch0_ref_clk,
      gtp_tx_en_pma_phase_align_o => ch0_tx_en_pma_phase_align,
      gtp_tx_pma_set_phase_o      => ch0_tx_pma_set_phase,
      align_en_i                  => ch0_gtp_locked,
      align_done_o                => ch0_align_done);

  
  U_align_ch1 : gtp_phase_align
    generic map (
      g_simulation => g_simulation) 
    port map (
      gtp_rst_i                   => ch1_gtp_reset,
      gtp_tx_clk_i                => ch1_ref_clk,
      gtp_tx_en_pma_phase_align_o => ch1_tx_en_pma_phase_align,
      gtp_tx_pma_set_phase_o      => ch1_tx_pma_set_phase,
      align_en_i                  => ch1_gtp_locked,
      align_done_o                => ch1_align_done);

  
  U_bitslide_ch0 : gtp_bitslide
    generic map (
      g_simulation => g_simulation)
    port map (
      gtp_rst_i                => ch0_gtp_reset,
      gtp_rx_clk_i             => ch0_rx_rec_clk,
      gtp_rx_comma_det_i       => ch0_rx_comma_det,
      gtp_rx_byte_is_aligned_i => ch0_rx_byte_is_aligned,
      serdes_ready_i           => ch0_gtp_locked,
      gtp_rx_slide_o           => ch0_rx_slide,
      gtp_rx_cdr_rst_o         => ch0_rx_cdr_rst,
      bitslide_o               => ch0_rx_bitslide_int,
      synced_o                 => ch0_rx_synced);

  ch0_rx_bitslide_o <= ch0_rx_bitslide_int(3 downto 0);

  U_bitslide_ch1 : gtp_bitslide
    generic map (
      g_simulation => g_simulation)
    port map (
      gtp_rst_i                => ch1_gtp_reset,
      gtp_rx_clk_i             => ch1_rx_rec_clk,
      gtp_rx_comma_det_i       => ch1_rx_comma_det,
      gtp_rx_byte_is_aligned_i => ch1_rx_byte_is_aligned,
      serdes_ready_i           => ch1_gtp_locked,
      gtp_rx_slide_o           => ch1_rx_slide,
      gtp_rx_cdr_rst_o         => ch1_rx_cdr_rst,
      bitslide_o               => ch1_rx_bitslide_int,
      synced_o                 => ch1_rx_synced);

  ch1_rx_bitslide_o <= ch1_rx_bitslide_int(3 downto 0);


  ch0_rx_enable_output <= ch0_rx_synced and ch0_align_done;
  ch1_rx_enable_output <= ch1_rx_synced and ch1_align_done;

  U_sync_oen_ch0 : gc_sync_ffs
    generic map (
      g_sync_edge => "positive")
    port map (
      clk_i    => ch0_rx_rec_clk,
      rst_n_i  => '1',
      data_i   => ch0_rx_enable_output,
      synced_o => ch0_rx_enable_output_synced,
      npulse_o => open,
      ppulse_o => open);

  U_sync_oen_ch1 : gc_sync_ffs
    generic map (
      g_sync_edge => "positive")
    port map (
      clk_i    => ch1_rx_rec_clk,
      rst_n_i  => '1',
      data_i   => ch1_rx_enable_output,
      synced_o => ch1_rx_enable_output_synced,
      npulse_o => open,
      ppulse_o => open);

  
  p_force_proper_disparity_ch0 : process(ch0_ref_clk, ch0_gtp_reset)
  begin
    if (ch0_gtp_reset = '1') then
      ch0_disparity_set   <= '0';
      ch0_tx_chardispval  <= '0';
      ch0_tx_chardispmode <= '0';
    elsif rising_edge(ch0_ref_clk) then
      if(ch0_disparity_set = '0' and ch0_tx_k_i = '1' and ch0_tx_data_i = x"bc" and ch0_align_done = '1') then
        ch0_disparity_set <= '1';
        if(g_force_disparity = 0) then
          ch0_tx_chardispval <= '0' ;
        else
          ch0_tx_chardispval <= '1';
        end if;
        ch0_tx_chardispmode <= '1';
      else
        ch0_tx_chardispmode <= '0';
        ch0_tx_chardispval  <= '0';
      end if;
    end if;
  end process;

  p_force_proper_disparity_ch1 : process(ch1_ref_clk, ch1_gtp_reset)
  begin
    if (ch1_gtp_reset = '1') then
      ch1_disparity_set   <= '0';
      ch1_tx_chardispval  <= '0';
      ch1_tx_chardispmode <= '0';
      
    elsif rising_edge(ch1_ref_clk) then
      if(ch1_disparity_set = '0' and ch1_tx_k_i = '1' and ch1_tx_data_i = x"bc" and ch1_align_done = '1') then
        ch1_disparity_set <= '1';
        if(g_force_disparity = 0) then
          ch1_tx_chardispval <= '0';
        else
          ch1_tx_chardispval <= '1';
        end if;
        ch1_tx_chardispmode <= '1';
      else
        ch1_tx_chardispmode <= '0';
        ch1_tx_chardispval  <= '0';
      end if;
    end if;
  end process;

  p_gen_output_ch0 : process(ch0_rx_rec_clk, ch0_gtp_reset)
  begin
    if(ch0_gtp_reset = '1') then
      ch0_rx_data_o    <= (others => '0');
      ch0_rx_k_o       <= '0';
      ch0_rx_enc_err_o <= '0';
      
    elsif rising_edge(ch0_rx_rec_clk) then
      if(ch0_rx_enable_output_synced = '0') then
-- make sure the output data is invalid when the link is down and that it will
-- trigger the sync loss detection
        ch0_rx_data_o    <= (others => '0');
        ch0_rx_k_o       <= '1';
        ch0_rx_enc_err_o <= '1';
      else
        ch0_rx_data_o    <= ch0_rx_data_int;
        ch0_rx_k_o       <= ch0_rx_k_int;
        ch0_rx_enc_err_o <= ch0_rx_disperr or ch0_rx_invcode;
      end if;
    end if;
  end process;

  p_gen_output_ch1 : process(ch1_rx_rec_clk, ch1_rst_i)
  begin
    if(ch1_rst_i = '1') then
      ch1_rx_data_o    <= (others => '0');
      ch1_rx_k_o       <= '0';
      ch1_rx_enc_err_o <= '0';
      
    elsif rising_edge(ch1_rx_rec_clk) then
      if(ch1_rx_enable_output_synced = '0') then
-- make sure the output data is invalid when the link is down and that it will
-- trigger the sync loss detection
        ch1_rx_data_o    <= (others => '0');
        ch1_rx_k_o       <= '1';
        ch1_rx_enc_err_o <= '1';
      else
        ch1_rx_data_o    <= ch1_rx_data_int;
        ch1_rx_k_o       <= ch1_rx_k_int;
        ch1_rx_enc_err_o <= ch1_rx_disperr or ch1_rx_invcode;
      end if;
    end if;
  end process;


-- drive the recovered clock output
  ch0_rx_rbclk_o <= ch0_rx_rec_clk;
--  ch0_tx_disparity_o <= ch0_tx_rundisp_vec(0);

  ch1_rx_rbclk_o <= ch1_rx_rec_clk;
--  ch1_tx_disparity_o <= ch1_tx_rundisp_vec(0);

  ch0_ref_clk_o <= ch0_ref_clk;
  ch1_ref_clk_o <= ch1_ref_clk;
  
end rtl;
