-- PROJECT FOFB
-- COMBPM ELECTRON TOP LEVEL
-- RBR

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

library xpm;
use xpm.vcomponents.all;


entity top_combpm_electron is
    port(

        rst_n                : in std_logic;    -- Asynchronous reset
        free_100_clk         : in std_logic;    -- Freerunning clock for GT
        pps                  : in std_logic;    -- A pulse per second signal, sync to clk domain
        clk                  : out std_logic;   -- main clock (AXIS and AXI-MM)
        mc_time              : in std_logic_vector(39 downto 0);

        -- Transceiver QPLL interface
        qpll_out_clk         : in std_logic;    -- QPLL clock for transceivers
        qpll_ref_clk         : in std_logic;    -- QPLL ref clock
        qpll_reset           : out std_logic;   -- QPLL reset
        qpll_lock            : in std_logic;    -- QPLL is locked

        -- Debug output
        debug_datarx         : out std_logic_vector(15 downto 0);
        debug_status         : out std_logic_vector(6 downto 0);
        error_detect         : out std_logic;

        -- SFP interfaces
        sfp_txp              : out std_logic;
        sfp_txn              : out std_logic;
        sfp_rxp              : in std_logic;
        sfp_rxn              : in std_logic;
        sfp_rx_los           : in std_logic;
        sfp_mod_abs          : in std_logic;
        sfp_tx_disable       : out std_logic;
        sfp_tx_fault         : in std_logic;

        -- AXIS interface
        m_axis_tid           : out std_logic_vector(0 downto 0);
        m_axis_tdest         : out std_logic_vector(9 downto 0);
        m_axis_tdata         : out std_logic_vector(127 downto 0);
        m_axis_tstrb         : out std_logic_vector(15 downto 0);
        m_axis_tkeep         : out std_logic_vector(15 downto 0);
        m_axis_tlast         : out std_logic;
        m_axis_tuser         : out std_logic_vector(0 downto 0);
        m_axis_tvalid        : out std_logic;
        m_axis_tready        : in std_logic;

        -- AXI bus interface
        s_axi_awaddr         : in std_logic_vector(7 downto 0);
        s_axi_awprot         : in std_logic_vector(2 downto 0);
        s_axi_awvalid        : in std_logic;
        s_axi_awready        : out std_logic;
        s_axi_wdata          : in std_logic_vector(32-1 downto 0);
        s_axi_wstrb          : in std_logic_vector(32/8-1 downto 0);
        s_axi_wvalid         : in std_logic;
        s_axi_wready         : out std_logic;
        s_axi_bresp          : out std_logic_vector(1 downto 0);
        s_axi_bvalid         : out std_logic;
        s_axi_bready         : in std_logic;
        s_axi_araddr         : in std_logic_vector(7 downto 0);
        s_axi_arprot         : in std_logic_vector(2 downto 0);
        s_axi_arvalid        : in std_logic;
        s_axi_arready        : out std_logic;
        s_axi_rdata          : out std_logic_vector(32-1 downto 0);
        s_axi_rresp          : out std_logic_vector(1 downto 0);
        s_axi_rvalid         : out std_logic;
        s_axi_rready         : in std_logic
    );
end top_combpm_electron;

architecture struct of top_combpm_electron is

    --------------------------
    -- INTERFACE ATTRIBUTES --
    --------------------------
    ATTRIBUTE X_INTERFACE_INFO                       : STRING;
    ATTRIBUTE X_INTERFACE_PARAMETER                  : STRING;

    ATTRIBUTE X_INTERFACE_INFO of rst_n              :  SIGNAL is "xilinx.com:signal:reset:1.0 rst_n RST";
    ATTRIBUTE X_INTERFACE_PARAMETER of rst_n         :  SIGNAL is "POLARITY ACTIVE_LOW";

    ATTRIBUTE X_INTERFACE_INFO of qpll_reset         :  SIGNAL is "xilinx.com:signal:reset:1.0 qpll_reset RST";
    ATTRIBUTE X_INTERFACE_PARAMETER of qpll_reset    :  SIGNAL is "POLARITY ACTIVE_HIGH";

    ATTRIBUTE X_INTERFACE_PARAMETER of free_100_clk: SIGNAL is "FREQ_HZ 100000000";
    ATTRIBUTE X_INTERFACE_PARAMETER of clk: SIGNAL is "FREQ_HZ 156250000, ASSOCIATED_BUSIF m_axis:s_axi";

    ATTRIBUTE X_INTERFACE_INFO of sfp_txn: SIGNAL is "xilinx.com:interface:sfp:1.0 sfp TXN";
    ATTRIBUTE X_INTERFACE_INFO of sfp_rxn: SIGNAL is "xilinx.com:interface:sfp:1.0 sfp RXN";
    ATTRIBUTE X_INTERFACE_INFO of sfp_txp: SIGNAL is "xilinx.com:interface:sfp:1.0 sfp TXP";
    ATTRIBUTE X_INTERFACE_INFO of sfp_rxp: SIGNAL is "xilinx.com:interface:sfp:1.0 sfp RXP";
    ATTRIBUTE X_INTERFACE_INFO of sfp_rx_los: SIGNAL is "xilinx.com:interface:sfp:1.0 sfp RX_LOS";
    ATTRIBUTE X_INTERFACE_INFO of sfp_mod_abs: SIGNAL is "xilinx.com:interface:sfp:1.0 sfp MOD_ABS";
    ATTRIBUTE X_INTERFACE_INFO of sfp_tx_disable: SIGNAL is "xilinx.com:interface:sfp:1.0 sfp TX_DISABLE";
    ATTRIBUTE X_INTERFACE_INFO of sfp_tx_fault: SIGNAL is "xilinx.com:interface:sfp:1.0 sfp TX_FAULT";

    COMPONENT combpm_gtwizard
      PORT (
        gtwiz_userclk_tx_reset_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_userclk_tx_srcclk_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_userclk_tx_usrclk_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_userclk_tx_usrclk2_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_userclk_tx_active_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_userclk_rx_reset_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_userclk_rx_srcclk_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_userclk_rx_usrclk_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_userclk_rx_usrclk2_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_userclk_rx_active_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_clk_freerun_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_all_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_tx_pll_and_datapath_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_tx_datapath_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_rx_pll_and_datapath_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_rx_datapath_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_qpll1lock_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_rx_cdr_stable_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_tx_done_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_rx_done_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_reset_qpll1reset_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtwiz_userdata_tx_in : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
        gtwiz_userdata_rx_out : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
        gthrxn_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        gthrxp_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        qpll0clk_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        qpll0refclk_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        qpll1clk_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        qpll1refclk_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        rx8b10ben_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        rxbufreset_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        rxcommadeten_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        rxmcommaalignen_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        rxpcommaalignen_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        tx8b10ben_in : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
        txctrl0_in : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
        txctrl1_in : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
        txctrl2_in : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
        gthtxn_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gthtxp_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        gtpowergood_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        rxbufstatus_out : OUT STD_LOGIC_VECTOR(2 DOWNTO 0);
        rxbyteisaligned_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        rxbyterealign_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        rxcdrlock_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        rxclkcorcnt_out : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
        rxcommadet_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        rxctrl0_out : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
        rxctrl1_out : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
        rxctrl2_out : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
        rxctrl3_out : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
        rxpmaresetdone_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0);
        txpmaresetdone_out : OUT STD_LOGIC_VECTOR(0 DOWNTO 0)
      );
    END COMPONENT;

    ------------------------
    -- SIGNAL DECLARATION --
    ------------------------
    signal sync_resetn   : std_logic;
    signal sync_reset    : std_logic;
    signal usrclk        : std_logic;
    signal rst           : std_logic;
    signal soft_reset    : std_logic;

    signal frame_seq_cnt      : std_logic_vector(15 downto 0);
    signal frame_valid_cnt    : std_logic_vector(15 downto 0);
    signal frame_invalid_cnt  : std_logic_vector(15 downto 0);
    signal frame_valid_rate   : std_logic_vector(15 downto 0);
    signal frame_invalid_rate : std_logic_vector(15 downto 0);
    signal cnt_seq_mismatch   : std_logic;
    signal seq_discontinuity  : std_logic;
    signal frame_error        : std_logic;

    signal gt_datarx          : std_logic_vector(15 downto 0);
    signal gt_powergood       : std_logic;
    signal gt_rxclkactive     : std_logic;
    signal gt_rxcdrlock       : std_logic;
    signal gt_rxresetdone     : std_logic;
    signal gt_rxbyteisaligned : std_logic;
    signal gt_rxbyterealign   : std_logic;
    signal gt_rxcommadet      : std_logic;
    signal gt_rxcommadeten    : std_logic;
    signal gt_rxresetdatapath : std_logic;
    signal gt_rxresetplldatapath : std_logic;

    signal interface_ready :  std_logic;

begin


    xpm_cdc_async_rst_inst : xpm_cdc_async_rst
    generic map (
        DEST_SYNC_FF => 4,
        INIT_SYNC_FF => 0,
        RST_ACTIVE_HIGH => 0  -- DECIMAL; 0=active low reset, 1=active high reset
    )
    port map (
        dest_arst => sync_resetn,
        dest_clk => usrclk,
        src_arst => rst_n
    );


    -- Reset invert polarity
    rst <= not rst_n;
    sync_reset <= not sync_resetn;

    -- Debug
    debug_datarx        <= gt_datarx;
    debug_status(0)     <= gt_rxcommadet;
    debug_status(1)     <= gt_rxcdrlock;
    debug_status(2)     <= gt_rxbyterealign;
    debug_status(3)     <= gt_rxbyteisaligned;
    debug_status(4)     <= frame_error;
    debug_status(5)     <= cnt_seq_mismatch;
    debug_status(6)     <= seq_discontinuity;
    error_detect        <= frame_error or cnt_seq_mismatch or seq_discontinuity;

    -- Output clock
    clk <= usrclk;

    -- SFP direct connexion
    sfp_tx_disable  <= '1';

    -- Interface Ready signal combinatorial
    interface_ready <= gt_powergood and gt_rxresetdone and gt_rxbyteisaligned and qpll_lock;

    ----------------------
    -- AXI-MM INTERFACE --
    ----------------------
    axiitf_inst: entity work.combpm_ctrl_axi
    generic map(
        G_ADDR_W => 8
    )
    port map(
        sfp_rxlos_i           => sfp_rx_los,
        sfp_modabs_i          => sfp_mod_abs,
        gt_powergood_i        => gt_powergood,
        gt_qplllock_i         => qpll_lock,
        gt_rxclkactive_i      => gt_rxclkactive,
        gt_rxcdrlock_i        => gt_rxcdrlock,
        gt_rxresetdone_i      => gt_rxresetdone,
        gt_rxbyteisaligned_i  => gt_rxbyteisaligned,
        gt_rxbyterealign_i    => gt_rxbyterealign,
        gt_rxcommadet_i       => gt_rxcommadet,
        gt_rxcommadeten_o     => gt_rxcommadeten,
        gt_rxrstdatapath_o    => gt_rxresetdatapath,
        gt_rxrstplldatapath_o => gt_rxresetplldatapath,
        protocol_softreset_o  => soft_reset,

        protocol_frameerror_i => frame_error,
        protocol_seqframecnterror_i => cnt_seq_mismatch,
        protocol_seqframediscont_i => seq_discontinuity,
        framecnt_validframecnt_i => frame_valid_cnt,
        framecnt_invalidframecnt_i => frame_invalid_cnt,
        framerate_validframerate_i => frame_valid_rate,
        framerate_invalidframerate_i => frame_invalid_rate,
        frameseq_framecnt_i => frame_seq_cnt,

        clk                   => usrclk,
        reset                 => sync_reset,
        S_AXI_AWADDR          => S_AXI_AWADDR,
        S_AXI_AWPROT          => S_AXI_AWPROT,
        S_AXI_AWVALID         => S_AXI_AWVALID,
        S_AXI_AWREADY         => S_AXI_AWREADY,
        S_AXI_WDATA           => S_AXI_WDATA,
        S_AXI_WSTRB           => S_AXI_WSTRB,
        S_AXI_WVALID          => S_AXI_WVALID,
        S_AXI_WREADY          => S_AXI_WREADY,
        S_AXI_BRESP           => S_AXI_BRESP,
        S_AXI_BVALID          => S_AXI_BVALID,
        S_AXI_BREADY          => S_AXI_BREADY,
        S_AXI_ARADDR          => S_AXI_ARADDR,
        S_AXI_ARPROT          => S_AXI_ARPROT,
        S_AXI_ARVALID         => S_AXI_ARVALID,
        S_AXI_ARREADY         => S_AXI_ARREADY,
        S_AXI_RDATA           => S_AXI_RDATA,
        S_AXI_RRESP           => S_AXI_RRESP,
        S_AXI_RVALID          => S_AXI_RVALID,
        S_AXI_RREADY          => S_AXI_RREADY
    );

    --------------------------------------
    -- LIBERA ELECTRON PROCOTOL DECODER --
    --------------------------------------
    protocol_inst: entity work.combpm_protocol_electron
    port map(
        rst_n              => sync_resetn,
        clk                => usrclk,
        pps                => pps,
        gt_datarx          => gt_datarx,
        gt_interfaceready  => interface_ready,

        m_axi_tid          => m_axis_tid,
        m_axi_tdest        => m_axis_tdest,
        m_axi_tdata        => m_axis_tdata,
        m_axi_tstrb        => m_axis_tstrb,
        m_axi_tkeep        => m_axis_tkeep,
        m_axi_tlast        => m_axis_tlast,
        m_axi_tuser        => m_axis_tuser,
        m_axi_tvalid       => m_axis_tvalid,
        m_axi_tready       => m_axis_tready,

        mc_time            => mc_time,
        soft_reset         => soft_reset,
        frame_seq_cnt      => frame_seq_cnt,
        frame_valid_cnt    => frame_valid_cnt,
        frame_invalid_cnt  => frame_invalid_cnt,
        frame_valid_rate   => frame_valid_rate,
        frame_invalid_rate => frame_invalid_rate,
        cnt_seq_mismatch   => cnt_seq_mismatch,
        seq_discontinuity  => seq_discontinuity,
        frame_error        => frame_error
    );

    ---------------
    -- GT WIZARD --
    ---------------
    gtwizard_inst : combpm_gtwizard
    PORT MAP (
        -- Async reset
        gtwiz_reset_all_in(0)                 => rst,
        gtwiz_userclk_tx_reset_in(0)          => rst,
        gtwiz_userclk_rx_reset_in(0)          => rst,

        -- Free run clock
        gtwiz_reset_clk_freerun_in(0)         => free_100_clk,

        -- Clock and data
        gtwiz_userclk_rx_usrclk2_out(0)       => usrclk,
        gtwiz_userdata_tx_in                  => (others => '0'),
        gtwiz_userdata_rx_out                 => gt_datarx,

        -- QPLL COMMON
        gtwiz_reset_qpll1lock_in(0)           => qpll_lock,
        gtwiz_reset_qpll1reset_out(0)         => qpll_reset,
        qpll1clk_in(0)                        => qpll_out_clk,
        qpll1refclk_in(0)                     => qpll_ref_clk,

        -- Control
        gtwiz_reset_rx_datapath_in(0)         => gt_rxresetdatapath,
        gtwiz_reset_rx_pll_and_datapath_in(0) => gt_rxresetplldatapath,
        rxbufreset_in                         => "0",
        rxcommadeten_in(0)                    => gt_rxcommadeten,
        rx8b10ben_in                          => "1",
        rxmcommaalignen_in                    => "1",
        rxpcommaalignen_in                    => "1",
        tx8b10ben_in                          => "1",
        gtwiz_reset_tx_pll_and_datapath_in    => "0",
        gtwiz_reset_tx_datapath_in            => "0",

        -- Status
        gtwiz_userclk_tx_active_out           => open,
        gtwiz_userclk_rx_active_out(0)        => gt_rxclkactive,
        gtwiz_reset_tx_done_out               => open,
        gtwiz_reset_rx_done_out(0)            => gt_rxresetdone,
        gtpowergood_out(0)                    => gt_powergood,
        rxbyteisaligned_out(0)                => gt_rxbyteisaligned,
        rxbyterealign_out(0)                  => gt_rxbyterealign,
        rxcdrlock_out(0)                      => gt_rxcdrlock,
        rxcommadet_out(0)                     => gt_rxcommadet,
        rxbufstatus_out                       => open,
        rxclkcorcnt_out                       => open,
        rxpmaresetdone_out                    => open,
        txpmaresetdone_out                    => open,

        -- SFP
        gthrxn_in(0)                          => sfp_rxn,
        gthrxp_in(0)                          => sfp_rxp,
        gthtxn_out(0)                         => sfp_txn,
        gthtxp_out(0)                         => sfp_txp,

        -- Not used
        qpll0clk_in                           => "0",     -- not used
        qpll0refclk_in                        => "0",  -- not used
        gtwiz_reset_rx_cdr_stable_out         => open, -- Do not use
        gtwiz_userclk_rx_srcclk_out           => open,
        gtwiz_userclk_rx_usrclk_out           => open,
        rxctrl0_out                           => open,
        rxctrl1_out                           => open,
        rxctrl2_out                           => open,
        rxctrl3_out                           => open,
        txctrl0_in                            => (others => '0'),
        txctrl1_in                            => (others => '0'),
        txctrl2_in                            => (others => '0'),
        gtwiz_userclk_tx_srcclk_out           => open,
        gtwiz_userclk_tx_usrclk_out           => open,
        gtwiz_userclk_tx_usrclk2_out          => open
    );
end architecture struct;