library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

library UNISIM;
use UNISIM.VComponents.all;

library work;
use work.AddressMap.all;
use work.BusSignalTypes.all;
use work.AddressBook.all;

entity toplevel is
  Port (
   -- System ----------------------------------------------------------------------
   CLKOSC       : in std_logic; -- 50 MHz
   LED          : out std_logic_vector(3 downto 0);
   DIP          : in  std_logic_vector(7 downto 0);
   PROG_B_ON    : out std_logic;
   
   -- Fixed signal input ----------------------------------------------------------
   FIXED_SIGIN_U  : in std_logic_vector(31 downto 0); -- 0-31 ch
   FIXED_SIGIN_D  : in std_logic_vector(31 downto 0); -- 32-63 ch
   
   -- Mezzanine signal ------------------------------------------------------------
   MZN_SIG_Up   : in std_logic_vector(31 downto 0); -- 64-95 ch
   MZN_SIG_Un   : in std_logic_vector(31 downto 0);
   MZN_SIG_Dp   : in std_logic_vector(31 downto 0); -- 96-127 ch
   MZN_SIG_Dn   : in std_logic_vector(31 downto 0);
   
   -- PHY -------------------------------------------------------------------------
   PHY_MDIO		: inout std_logic;
   PHY_MDC      : out std_logic;
   PHY_nRST     : out std_logic;
   PHY_HPD      : out std_logic;
   --PHY_IRQ      : in std_logic;
   
   PHY_RXD      : in std_logic_vector(7 downto 0);
   PHY_RXDV     : in std_logic;
   PHY_RXER     : in std_logic;
   PHY_RX_CLK   : in std_logic;
   
   PHY_TXD      : out std_logic_vector(7 downto 0);
   PHY_TXEN     : out std_logic;
   PHY_TXER     : out std_logic;
   PHY_TX_CLK   : in std_logic;
   
   PHY_GTX_CLK  : out std_logic;
   
   PHY_CRS      : in std_logic;
   PHY_COL      : in std_logic;
   
   -- EEPROM ----------------------------------------------------------------------
   PROM_CS	    : out std_logic;
   PROM_SK      : out std_logic;
   PROM_DI      : out std_logic;
   PROM_DO      : in std_logic;
   
   -- User I/O --------------------------------------------------------------------
   --USER_RST     : in std_logic;
   NIMIN        : in  std_logic_vector(3 downto 0); -- NIM in1 : stop, NIM in2 : L2, NIM in3 : clear, NIM in4 : gTag
   NIMOUT       : out std_logic_vector(3 downto 0)
   
  );
end toplevel;

architecture Behavioral of toplevel is
    -- System --------------------------------------------------------------------------------
    signal system_reset : std_logic;
    signal user_reset   : std_logic;
    signal rst_from_bus : std_logic;
    
    -- Finxed input ports --------------------------------------------------------------------
    constant tof_all_zero : std_logic_vector(NofTOF-1 downto 0) := (others => '0');
    constant fbh_all_zero : std_logic_vector(NofFBH-1 downto 0) := (others => '0'); 
    
    signal user_sig_u, user_sig_d   : std_logic_vector(31 downto 0);
    signal pedge_fu, pedge_fd       : std_logic_vector(31 downto 0);
    signal tof_before_delay         : std_logic_vector(31 downto 0);
    signal tof_sig_in, fbh_sig_in   : std_logic_vector(31 downto 0);
    
    constant extra_delayLength    : integer := 8; -- 40 ns    
    type ex_delayType is array(integer range NofFBH-1 downto 0) of std_logic_vector(extra_delayLength-1 downto 0);
    signal ex_delay_fbh : ex_delayType;
    
    constant delayLength    : integer := WidthIn+2;
    type vdelayType is array(integer range 31 downto 0) of std_logic_vector(delayLength downto 0);
    signal delay_fu : vdelayType;
    
    signal or_tof, or_ch1, or_ch2, or_ch, or_fbh, or_fbh_coin    : std_logic;
        
    component input_synchronizer
        Port (
            rst     : in std_logic;
            clk     : in std_logic;
            dataIn  : in std_logic;
            dataOut : out std_logic    
        );
    end component;
    
    component EdgeDetector
        port (
            rst : in std_logic;
            clk : in std_logic;
            dIn : in std_logic;
            dOut : out std_logic 
        );
    end component;
    
    component WidthGen
        generic(
            width   : integer 
        );
        Port (
            rst     : in std_logic;
            clk     : in std_logic;
            dataIn  : in std_logic;
            dataOut : out std_logic
        );
    end component;

    signal fbh_coin      : std_logic_vector(NofFBH_Raw-1 downto 0);
    
    component coinFBH
        generic(
            width       : integer
        );
        Port (
            rst         : in std_logic;
            clk         : in std_logic;
            inFD        : in std_logic_vector(2*NofFBH_Raw -1 downto 0);
            outFBHRaw   : out std_logic_vector(NofFBH_Raw -1 downto 0)
        );
    end component;
    
    signal fbh_cluster, fbh_cl_out      : std_logic_vector(NofFBH-1 downto 0);

    component clusteringFBH
        generic(
            width   : integer
        );
        Port (
            rst     : in std_logic;
            clk     : in std_logic;
            inFBH   : in std_logic_vector(NofFBH_Raw -1 downto 0);
            outFBH  : out std_logic_vector(NofFBH -1 downto 0)
        );
    end component;
    
    -- Mezzanine ports -----------------------------------------------------------------------
    signal mzn_u, mzn_d                         : std_logic_vector(31 downto 0);
    signal sync_mzn_u, sync_mzn_d               : std_logic_vector(31 downto 0);
    signal dcr_u, dcr_d                         : std_logic_vector(31 downto 0);
    signal sch_u, sch_d                         : std_logic_vector(31 downto 0);
    signal pedge_dcr_u, pedge_dcr_d             : std_logic_vector(31 downto 0);
    signal dcru_before_delay, dcrd_before_delay : std_logic_vector(31 downto 0);
    signal ch_sig_in                            : std_logic_vector(NofCH-1 downto 0);
    
    signal delay_dcr_u, delay_dcr_d : vdelayType;
    
    component DCR_NetAssign
        Port (
            mzn_in_u  : in  std_logic_vector(31 downto 0);
            mzn_in_d  : in  std_logic_vector(31 downto 0);
            dcr_out_u : out std_logic_vector(31 downto 0);
            dcr_out_d : out std_logic_vector(31 downto 0)
        );
    end component;
    
    component DCRtoSCH
        port (
            dcrIn  : in  std_logic_vector(31 downto 0);
            schIn  : out std_logic_vector(31 downto 0)
        );
    end component;

    -- LED -----------------------------------------------------------------------------------
    signal out_led	: std_logic_vector(3 downto 0);
    
    component LED_Module is
        port(
          rst	             : in std_logic;
          clk	             : in std_logic;
          -- Module output --
          outLED	: out std_logic_vector(3 downto 0);
          -- Local bus --
          addrLocalBus		: in LocalAddressType;
          dataLocalBusIn	: in LocalBusInType;
          dataLocalBusOut	: out LocalBusOutType;
          reLocalBus		: in std_logic;
          weLocalBus		: in std_logic;
          readyLocalBus		: out std_logic
        );
    end component;
    
    -- TDC -----------------------------------------------------------------------------------
    signal tdc_data   : std_logic_vector(7 downto 0);
    signal req_data   : std_logic;
    signal valid_data : std_logic;
    signal empty_data : std_logic;
    signal stop       : std_logic;
    signal busy_daq   : std_logic;
    signal trig_l2    : std_logic;
    signal trig_clr   : std_logic;
    
    component TDC
        port(
            rst                 : in std_logic;
            clk                 : in std_logic;
            -- Module input --
            tofSig              : in std_logic_vector(NofTOF-1 downto 0);
            fbhSig              : in std_logic_vector(NofFBH-1 downto 0);
            chSig               : in std_logic_vector(NofCH-1 downto 0);
            
            -- DAQ signals --
            tdcStop             : in std_logic;
      		trigL2              : in std_logic;
            Clear               : in std_logic;
            reqData             : in std_logic;
            tdcData             : out std_logic_vector(7 downto 0);
            validData           : out std_logic;
            emptyData           : out std_logic;
            busyDAQ             : out std_logic;
            gTag                : in std_logic;
    
            -- Local bus --
            addrLocalBus        : in LocalAddressType;
            dataLocalBusIn      : in LocalBusInType;
            dataLocalBusOut     : out LocalBusOutType;
            reLocalBus          : in std_logic;
            weLocalBus          : in std_logic;
            readyLocalBus       : out std_logic
        );
    end component;
   
   -- SEL ------------------------------------------------------------------------------------
   signal sync_nimin1, sync_nimin2, sync_nimin3     : std_logic;
   signal delay_nimin1, delay_nimin2, delay_nimin3     : std_logic_vector(2 downto 0);
   signal sel_nim1, sel_nim2, sel_nim3, sel_nim4    : std_logic_vector(3 downto 0);
   signal out_nim1, out_nim2, out_nim3, out_nim4    : std_logic;
   
    component SigSel_Module
        port(
            rst                  : in std_logic;
            clk                  : in std_logic;
            -- Module output --
            outSelNIM1           : out std_logic_vector(3 downto 0);
            outSelNIM2           : out std_logic_vector(3 downto 0);
            outSelNIM3           : out std_logic_vector(3 downto 0);
            outSelNIM4           : out std_logic_vector(3 downto 0);
            -- Local bus --
            addrLocalBus         : in LocalAddressType;
            dataLocalBusIn       : in LocalBusInType;
            dataLocalBusOut      : out LocalBusOutType;
            reLocalBus           : in std_logic;
            weLocalBus           : in std_logic;
            readyLocalBus        : out std_logic
        );
   end component;
   
   -- MTX3D ---------------------------------------------------------------------------------
   signal mtx1  : std_logic;
   
   component Matrix3D_v2
       port(
           rst                : in std_logic;
           clk                : in std_logic;
           sclk               : in std_logic;
           -- Module input --
           tofSig            : in std_logic_vector(NofTOF-1 downto 0);
           fbhSig            : in std_logic_vector(NofFBH-1 downto 0);
           chSig             : in std_logic_vector(NofCH-1 downto 0);
           
           -- Module output --
           Trigger            : out std_logic;
           VETO               : out std_logic;
           -- Local bus --
           addrLocalBus       : in LocalAddressType;
           dataLocalBusIn     : in LocalBusInType;
           dataLocalBusOut    : out LocalBusOutType;
           reLocalBus         : in std_logic;
           weLocalBus         : in std_logic;
           readyLocalBus      : out std_logic
       );
   end component;
   
   -- MTX2D ---------------------------------------------------------------------------------
   signal mtx2  : std_logic;
   
   component Matrix2D
       port(
           rst                : in std_logic;
           clk                : in std_logic;
           sclk               : in std_logic;
           -- Module input --
           tofSig            : in std_logic_vector(NofTOF-1 downto 0);
           fbhSig            : in std_logic_vector(NofFBH-1 downto 0);
           chSig             : in std_logic_vector(NofCH-1 downto 0);
   
           -- Module output --
           Trigger             : out std_logic;
           DirectTrigger       : out std_logic;
           -- Local bus --
           addrLocalBus        : in LocalAddressType;
           dataLocalBusIn      : in LocalBusInType;
           dataLocalBusOut     : out LocalBusOutType;
           reLocalBus          : in std_logic;
           weLocalBus          : in std_logic;
           readyLocalBus       : out std_logic
       );
   end component;
  
  -- Veto ----------------------------------------------------------------------------------
  signal veto_from_3d, trig_from_2d : std_logic;
  signal veto_trigger               : std_logic;
  component VetoModule
       Port (
           rst             : in std_logic;
           clk             : in std_logic;
           VETO            : in std_logic;
           DirectTrigger   : in std_logic;
           VetoTrigger     : out std_logic
       );
   end component;
  
   -- BCT -----------------------------------------------------------------------------------
   signal addr_LocalBus			: LocalAddressType;
   signal data_LocalBusIn       : LocalBusInType;
   signal data_LocalBusOut      : DataArray;
   signal re_LocalBus           : ControlRegArray;
   signal we_LocalBus           : ControlRegArray;
   signal ready_LocalBus        : ControlRegArray;
   
   component BusController
   Port(
           rstSys           : in  std_logic;
           rstFromBus       : out  std_logic;
           reConfig         : out  std_logic;
           clk              : in  std_logic;
           -- Local Bus --
           addrLocalBus                 : out LocalAddressType;
           dataFromUserModules          : in DataArray;
           dataToUserModules            : out LocalBusInType;
           reLocalBus                   : out ControlRegArray;
           weLocalBus                   : out ControlRegArray;
           readyLocalBus                : in  ControlRegArray;
           -- RBCP --
           RBCP_ADDR                    : in std_logic_vector(31 downto 0); -- address [31:0]
           RBCP_WD                      : in std_logic_vector(7 downto 0);  -- data from host [7:0]
           RBCP_WE                      : in std_logic;                             -- RBCP write enable
           RBCP_RE                      : in std_logic;                             -- RBCP read enable
           RBCP_ACK                     : out std_logic;                             -- RBCP acknowledge
           RBCP_RD                      : out std_logic_vector(7 downto 0)     -- data to host [7:0]
           );
   end component;

   -- TSD -----------------------------------------------------------------------------------
   component TCP_sender is
       port(
           RST                     : in std_logic;
           CLK                     : in std_logic;
           
           -- data from EVB --
           rdFromEVB               : in std_logic_vector(7 downto 0);
           rvFromEVB               : in std_logic;
           emptyFromEVB            : in std_logic;
           reToEVB                 : out std_logic;
           
           -- data to SiTCP
           isActive                : in std_logic;
           afullTx                 : in std_logic;
           weTx                    : out std_logic;
           wdTx                    : out std_logic_vector(7 downto 0)
           
           );
   end component;

   -- SiTCP ---------------------------------------------------------------------------------
    signal sel_gmii_mii : std_logic;
    
    signal mdio_out, mdio_oe	: std_logic;
    signal tcp_isActive, close_req, close_act    : std_logic;
    signal reg_dummy0    : std_logic_vector(7 downto 0);
    signal reg_dummy1    : std_logic_vector(7 downto 0);
    signal reg_dummy2    : std_logic_vector(7 downto 0);
    signal reg_dummy3    : std_logic_vector(7 downto 0);
    
    signal tcp_tx_clk   : std_logic;
    signal tcp_rx_wr    : std_logic;
    signal tcp_rx_data  : std_logic_vector(7 downto 0);
    signal tcp_tx_full  : std_logic;
    signal tcp_tx_wr    : std_logic;
    signal tcp_tx_data  : std_logic_vector(7 downto 0);
    
    signal rbcp_act     : std_logic;
    signal rbcp_addr    : std_logic_vector(31 downto 0);
    signal rbcp_wd      : std_logic_vector(7 downto 0);
    signal rbcp_we      : std_logic; --: Write enable
    signal rbcp_re      : std_logic; --: Read enable
    signal rbcp_ack     : std_logic; -- : Access acknowledge
    signal rbcp_rd      : std_logic_vector(7 downto 0 ); -- : Read data[7:0]

    component WRAP_SiTCP_GMII_XC7K_32K
    port
    (
        CLK                    : in std_logic; --: System Clock >129MHz
        RST                    : in std_logic; --: System reset
    -- Configuration parameters
        FORCE_DEFAULTn         : in std_logic; --: Load default parameters
        EXT_IP_ADDR            : in std_logic_vector(31 downto 0); --: IP address[31:0]
        EXT_TCP_PORT           : in std_logic_vector(15 downto 0); --: TCP port #[15:0]
        EXT_RBCP_PORT          : in std_logic_vector(15 downto 0); --: RBCP port #[15:0]
        PHY_ADDR               : in std_logic_vector(4 downto 0);  --: PHY-device MIF address[4:0]
        MY_MAC_ADDR	           : out std_logic_vector(47 downto 0); -- My MAC adder [47:0]
    -- EEPROM
        EEPROM_CS            : out std_logic; --: Chip select
        EEPROM_SK            : out std_logic; --: Serial data clock
        EEPROM_DI            : out    std_logic; --: Serial write data
        EEPROM_DO            : in std_logic; --: Serial read data
        --    user data, intialial values are stored in the EEPROM, 0xFFFF_FC3C-3F
        USR_REG_X3C            : out    std_logic_vector(7 downto 0); --: Stored at 0xFFFF_FF3C
        USR_REG_X3D            : out    std_logic_vector(7 downto 0); --: Stored at 0xFFFF_FF3D
        USR_REG_X3E            : out    std_logic_vector(7 downto 0); --: Stored at 0xFFFF_FF3E
        USR_REG_X3F            : out    std_logic_vector(7 downto 0); --: Stored at 0xFFFF_FF3F
    -- MII interface
        GMII_RSTn             : out    std_logic; --: PHY reset
        GMII_1000M            : in std_logic;  --: GMII mode (0:MII, 1:GMII)
        -- TX
        GMII_TX_CLK           : in std_logic; -- : Tx clock
        GMII_TX_EN            : out    std_logic; --: Tx enable
        GMII_TXD              : out    std_logic_vector(7 downto 0); --: Tx data[7:0]
        GMII_TX_ER            : out    std_logic; --: TX error
        -- RX
        GMII_RX_CLK           : in std_logic; -- : Rx clock
        GMII_RX_DV            : in std_logic; -- : Rx data valid
        GMII_RXD              : in std_logic_vector(7 downto 0); -- : Rx data[7:0]
        GMII_RX_ER            : in std_logic; --: Rx error
        GMII_CRS              : in std_logic; --: Carrier sense
        GMII_COL              : in std_logic; --: Collision detected
        -- Management IF
        GMII_MDC              : out std_logic; --: Clock for MDIO
        GMII_MDIO_IN          : in std_logic; -- : Data
        GMII_MDIO_OUT         : out    std_logic; --: Data
        GMII_MDIO_OE          : out    std_logic; --: MDIO output enable
    -- User I/F
        SiTCP_RST             : out    std_logic; --: Reset for SiTCP and related circuits
        -- TCP connection control
        TCP_OPEN_REQ          : in std_logic; -- : Reserved input, shoud be 0
        TCP_OPEN_ACK          : out    std_logic; --: Acknowledge for open (=Socket busy)
        TCP_ERROR             : out    std_logic; --: TCP error, its active period is equal to MSL
        TCP_CLOSE_REQ         : out    std_logic; --: Connection close request
        TCP_CLOSE_ACK         : in std_logic ;-- : Acknowledge for closing
        -- FIFO I/F
        TCP_RX_WC             : in std_logic_vector(15 downto 0); --: Rx FIFO write count[15:0] (Unused bits should be set 1)
        TCP_RX_WR             : out    std_logic; --: Write enable
        TCP_RX_DATA           : out    std_logic_vector(7 downto 0); --: Write data[7:0]
        TCP_TX_FULL           : out    std_logic; --: Almost full flag
        TCP_TX_WR             : in std_logic; -- : Write enable
        TCP_TX_DATA           : in std_logic_vector(7 downto 0); -- : Write data[7:0]
        -- RBCP
        RBCP_ACT              : out std_logic; -- RBCP active
        RBCP_ADDR             : out    std_logic_vector(31 downto 0); --: Address[31:0]
        RBCP_WD               : out    std_logic_vector(7 downto 0); --: Data[7:0]
        RBCP_WE               : out    std_logic; --: Write enable
        RBCP_RE               : out    std_logic; --: Read enable
        RBCP_ACK              : in std_logic; -- : Access acknowledge
        RBCP_RD               : in std_logic_vector(7 downto 0 ) -- : Read data[7:0]
    );
    end component;

	component global_sitcp_manager
		port(
		RST			: in std_logic;
		CLK			: in std_logic;
		ACTIVE		: in std_logic;
		REQ			: in std_logic;
		ACT			: out std_logic;
		rstFromTcp	: out std_logic
		);
	end component;

    -- Clock ---------------------------------------------------------------------------
    signal clk_125MHz, clk_200MHz   : std_logic;
    signal clk_10MHz                : std_logic;
    signal clk_locked               : std_logic;
    
    component clk_wiz_1
    port
     (-- Clock in ports
      clk_in1           : in     std_logic;
      -- Clock out ports
      clk_out1          : out    std_logic;
      clk_out2          : out    std_logic;
      clk_out3          : out    std_logic;
      -- Status and control signals
      reset             : in     std_logic;
      locked            : out    std_logic
     );
    end component;

begin
    -- ===================================================================================
    -- body
    -- ===================================================================================

    -- Global ----------------------------------------------------------------------------
    system_reset    <= NOT clk_locked;
    user_reset      <= (NOT clk_locked) OR rst_from_bus;
    
    -- Fixed input ports -----------------------------------------------------------------
    -- TOF (Fixed Input U)
    -- SyncModule -> EdgeDetector -> WidthGen ->       Delay        -> MTX
    -- FBH (Fixed Input D)
    -- SyncModule -> EdgeDetector -> WidthGen -> Coin -> Clustering -> MTX
    
    gen_fixed : for i in 0 to 31 generate
        u_sync_fu : input_synchronizer port map(rst => system_reset, clk => clk_200MHz, dataIn => FIXED_SIGIN_U(i), dataOut => user_sig_u(i));
        u_sync_fd : input_synchronizer port map(rst => system_reset, clk => clk_200MHz, dataIn => FIXED_SIGIN_D(i), dataOut => user_sig_d(i));
        
        u_edge_fu : EdgeDetector port map(rst => system_reset, clk => clk_200MHz, dIn => user_sig_u(i), dOut => pedge_fu(i));
        u_edge_fd : EdgeDetector port map(rst => system_reset, clk => clk_200MHz, dIn => user_sig_d(i), dOut => pedge_fd(i));
        
        u_width_tof : WidthGen
            generic map(width => WidthMtxCoin)
            port map(rst => system_reset, clk => clk_200MHz, dataIn => pedge_fu(i), dataOut => tof_before_delay(i));
            
        tof_sig_in(i)    <= delay_fu(i)(delayLength);
        
        u_width_fbh : WidthGen
            generic map(width => WidthCoin)
            port map(rst => system_reset, clk => clk_200MHz, dataIn => pedge_fd(i), dataOut => fbh_sig_in(i));
    end generate;
    
    -- Delay TOF signal --
    u_DelayTOF : process(system_reset, clk_200MHz)
    begin
        if(system_reset = '1') then
            for i in 0 to 31 loop
                delay_fu(i) <= (others => '0');
            end loop;
        elsif(clk_200MHz'event AND clk_200MHz = '1') then
            for i in 0 to 31 loop
                delay_fu(i) <= delay_fu(i)(delayLength-1 downto 0) & tof_before_delay(i);
            end loop;
        end if;
    end process u_DelayTOF;
    
    -- UD coin FBH --
    u_coinFBH : coinFBH 
        generic map(width => WidthIn)
        port map(rst=>system_reset, clk=>clk_200MHz, inFD=>fbh_sig_in, outFBHRaw=>fbh_coin);
    
    -- Clustering FBH --
    u_ClusteringFBH : clusteringFBH
        generic map(width => WidthIn)
        port map(rst => system_reset, clk => clk_200MHz, inFBH => fbh_coin, outFBH => fbh_cl_out);
        
    -- Extra delay FBH --
    u_ExDelayFBH : process(clk_200MHz)
    begin
        if(clk_200MHz'event AND clk_200MHz = '1') then
            for i in 0 to NofFBH-1 loop
                ex_delay_fbh(i)    <= ex_delay_fbh(i)(extra_delayLength-2 downto 0) & fbh_cl_out(i);
            end loop;
        end if;
    end process u_ExDelayFBH;
    gen_fbh_connect : for i in 0 to NofFBH-1 generate
        fbh_cluster(i)  <= ex_delay_fbh(i)(extra_delayLength-1);
    end generate;
    
    -- Make OR --
    or_tof       <= '0' when(tof_sig_in(23 downto 0) = tof_all_zero) else '1';
    or_fbh       <= '0' when(fbh_cluster = fbh_all_zero) else '1';
    or_fbh_coin  <= '0' when(fbh_coin = X"0000") else '1'; 
    --or_fbh  <= '0' 
    
    -- Mezzanine connectors --------------------------------------------------------------
    -- CH (MZN U/D)
    -- IBUF_DS -> SyncModule -> NetAssign -> EdgeDetector -> WidthGenerator -> Delay -> MTX
     
    gen_mzn_sig : for i in 0 to 31 generate
        MZNU_BUFDS_Inst : IBUFDS
        generic map (DIFF_TERM => TRUE, IBUF_LOW_PWR => TRUE, IOSTANDARD => "LVDS")
        port map (O  => mzn_u(i), I  => MZN_SIG_Up(i), IB => MZN_SIG_Un(i));
        
        MZND_BUFDS_Inst : IBUFDS
        generic map (DIFF_TERM => TRUE, IBUF_LOW_PWR => TRUE, IOSTANDARD => "LVDS")
        port map (O  => mzn_d(i), I  => MZN_SIG_Dp(i), IB => MZN_SIG_Dn(i));
        
        u_sync_mu : input_synchronizer port map(rst => system_reset, clk => clk_200MHz, dataIn => mzn_u(i), dataOut => sync_mzn_u(i));
        u_sync_md : input_synchronizer port map(rst => system_reset, clk => clk_200MHz, dataIn => mzn_d(i), dataOut => sync_mzn_d(i));
        
        u_edge_mu : EdgeDetector port map(rst => system_reset, clk => clk_200MHz, dIn => sch_u(i), dOut => pedge_dcr_u(i));
        u_edge_md : EdgeDetector port map(rst => system_reset, clk => clk_200MHz, dIn => sch_d(i), dOut => pedge_dcr_d(i));
        
        u_width_ch1 : WidthGen
            generic map(width => WidthMtxCoin)
            port map(rst => system_reset, clk => clk_200MHz, dataIn => pedge_dcr_u(i), dataOut => dcru_before_delay(i));
        
        u_width_ch2 : WidthGen
            generic map(width => WidthMtxCoin)
            port map(rst => system_reset, clk => clk_200MHz, dataIn => pedge_dcr_d(i), dataOut => dcrd_before_delay(i));
            
        ch_sig_in(i)      <= delay_dcr_u(i)(delayLength);
        ch_sig_in(i+32)   <= delay_dcr_d(i)(delayLength);
    end generate;
    
    DCRNet_Inst : DCR_NetAssign
    port map(
        mzn_in_u  => sync_mzn_u,
        mzn_in_d  => sync_mzn_d,
        dcr_out_u => dcr_u,
        dcr_out_d => dcr_d
    );
    
    SCH_UNet_Inst : DCRtoSCH
    port map(
        dcrIn   => dcr_u,
        schIn   => sch_u
    );
    
    SCH_DNet_Inst : DCRtoSCH
    port map(
        dcrIn   => dcr_d,
        schIn   => sch_d
    );
    
    -- Delay CH signal --
    u_DelayCH : process(system_reset, clk_200MHz)
    begin
        if(system_reset = '1') then
            for i in 0 to 31 loop
                delay_dcr_u(i) <= (others => '0');
                delay_dcr_d(i) <= (others => '0');
            end loop;
        elsif(clk_200MHz'event AND clk_200MHz = '1') then
            for i in 0 to 31 loop
                delay_dcr_u(i) <= delay_dcr_u(i)(delayLength-1 downto 0) & dcru_before_delay(i);
                delay_dcr_d(i) <= delay_dcr_d(i)(delayLength-1 downto 0) & dcrd_before_delay(i);
            end loop;
        end if;
    end process u_DelayCH;
    
    -- Make OR -- 
    or_ch1  <= '0' when(ch_sig_in(31 downto 0)  = X"00000000") else '1';
    or_ch2  <= '0' when(ch_sig_in(63 downto 32) = X"00000000") else '1';
    or_ch   <= or_ch1 OR or_ch2;
    
    -- NIM I/O ---------------------------------------------------------------------------
    u_sync_nimin1 : input_synchronizer port map(rst => system_reset, clk => clk_200MHz, dataIn => NIMIN(0), dataOut => sync_nimin1);
    u_sync_nimin2 : input_synchronizer port map(rst => system_reset, clk => clk_200MHz, dataIn => NIMIN(1), dataOut => sync_nimin2);
    u_sync_nimin3 : input_synchronizer port map(rst => system_reset, clk => clk_200MHz, dataIn => NIMIN(2), dataOut => sync_nimin3);
    
    u_edge_in1 : EdgeDetector port map(rst => system_reset, clk => clk_200MHz, dIn => delay_nimin1(2), dOut => stop);
    u_edge_in2 : EdgeDetector port map(rst => system_reset, clk => clk_200MHz, dIn => delay_nimin2(2), dOut => trig_l2);
    u_edge_in3 : EdgeDetector port map(rst => system_reset, clk => clk_200MHz, dIn => delay_nimin3(2), dOut => trig_clr);
    
    u_DelayNIMIN : process(system_reset, clk_200MHz)
    begin
        if(clk_200MHz'event AND clk_200MHz = '1') then
            delay_nimin1    <= delay_nimin1(1 downto 0) & sync_nimin1;
            delay_nimin2    <= delay_nimin2(1 downto 0) & sync_nimin2;
            delay_nimin3    <= delay_nimin3(1 downto 0) & sync_nimin3;
        end if;
    end process u_DelayNIMIN;
    
    NIMOUT(0)   <= out_nim1;
    NIMOUT(1)   <= out_nim2;
    NIMOUT(2)   <= out_nim3;
    NIMOUT(3)   <= out_nim4;

    -- LED -------------------------------------------------------------------------------
    LED <= out_led(3 downto 2) & busy_daq &  tcp_isActive;
    
    u_LED_Module :  LED_Module
    port map(
      rst                 => user_reset,
      clk                 => clk_200MHz,
      -- Module output --
      outLED    => out_led,
      -- Local bus --
      addrLocalBus        => addr_LocalBus, 
      dataLocalBusIn      => data_LocalBusIn,
      dataLocalBusOut     => data_LocalBusOut(i_LED.ID),
      reLocalBus          => re_LocalBus(i_LED.ID),
      weLocalBus          => we_LocalBus(i_LED.ID),
      readyLocalBus       => ready_LocalBus(i_LED.ID)
    );
    
    -- TDC -------------------------------------------------------------------------------
   u_TDC : TDC
   port map(
         rst                 => user_reset,
         clk                 => clk_200MHz,
         -- Module input --
         tofSig              => tof_sig_in(NofTOF-1 downto 0),
         fbhSig              => fbh_cluster,
         chSig               => ch_sig_in,
         
         -- DAQ signals --
         tdcStop             => stop,
         trigL2              => trig_l2,
         Clear               => trig_clr,
         reqData             => req_data,
         tdcData             => tdc_data,
         validData           => valid_data,
         emptyData           => empty_data,
         busyDAQ             => busy_daq,
         gTag                => NIMIN(3),
 
         -- Local bus --
         addrLocalBus        => addr_LocalBus,
         dataLocalBusIn      => data_LocalBusIn,
         dataLocalBusOut     => data_LocalBusOut(i_TDC.ID),
         reLocalBus          => re_LocalBus(i_TDC.ID),
         weLocalBus          => we_LocalBus(i_TDC.ID),
         readyLocalBus       => ready_LocalBus(i_TDC.ID)
     );
    
    -- SEL -------------------------------------------------------------------------------
    out_nim1    <= mtx1         when(sel_nim1 = "0000") else
                   mtx2         when(sel_nim1 = "0001") else
                   or_tof       when(sel_nim1 = "0010") else
                   or_fbh       when(sel_nim1 = "0011") else
                   or_ch        when(sel_nim1 = "0100") else
                   or_fbh_coin  when(sel_nim1 = "0101") else
                   busy_daq     when(sel_nim1 = "0110") else
                   veto_trigger when(sel_nim1 = "0111") else mtx1;
                   
    
    out_nim2    <= mtx1         when(sel_nim2 = "0000") else
                   mtx2         when(sel_nim2 = "0001") else
                   or_tof       when(sel_nim2 = "0010") else
                   or_fbh       when(sel_nim2 = "0011") else
                   or_ch        when(sel_nim2 = "0100") else
                   or_fbh_coin  when(sel_nim2 = "0101") else
                   busy_daq     when(sel_nim2 = "0110") else
                   veto_trigger when(sel_nim2 = "0111") else mtx1;
                   
    out_nim3    <= mtx1         when(sel_nim3 = "0000") else
                   mtx2         when(sel_nim3 = "0001") else
                   or_tof       when(sel_nim3 = "0010") else
                   or_fbh       when(sel_nim3 = "0011") else
                   or_ch        when(sel_nim3 = "0100") else
                   or_fbh_coin  when(sel_nim3 = "0101") else
                   busy_daq     when(sel_nim3 = "0110") else
                   veto_trigger when(sel_nim3 = "0111") else mtx1;
 
    out_nim4    <= mtx1         when(sel_nim4 = "0000") else
                   mtx2         when(sel_nim4 = "0001") else
                   or_tof       when(sel_nim4 = "0010") else
                   or_fbh       when(sel_nim4 = "0011") else
                   or_ch        when(sel_nim4 = "0100") else
                   or_fbh_coin  when(sel_nim4 = "0101") else
                   busy_daq     when(sel_nim4 = "0110") else   
                   veto_trigger when(sel_nim4 = "0111") else mtx1;               

                   
    u_SelSig_Module :  SigSel_Module
    port map(
      rst    => system_reset,
      clk    => clk_200MHz,
      -- Module output --
      outSelNIM1    => sel_nim1,
      outSelNIM2    => sel_nim2,
      outSelNIM3    => sel_nim3,
      outSelNIM4    => sel_nim4,

      -- Local bus --
      addrLocalBus        => addr_LocalBus, 
      dataLocalBusIn      => data_LocalBusIn,
      dataLocalBusOut     => data_LocalBusOut(i_SEL.ID),
      reLocalBus          => re_LocalBus(i_SEL.ID),
      weLocalBus          => we_LocalBus(i_SEL.ID),
      readyLocalBus       => ready_LocalBus(i_SEL.ID)
    );
    
    -- MTX3D -----------------------------------------------------------------------------
    u_MTX1 : Matrix3D_v2
    port map(
      rst                 => system_reset,
      clk                 => clk_200MHz,
      sclk                => clk_10MHz,
      -- Module input --
      tofSig              => tof_sig_in(NofTOF-1 downto 0),
      fbhSig              => fbh_cluster,
      chSig               => ch_sig_in,
            
      -- Module output --
      Trigger             => mtx1,
      VETO                => veto_from_3d,
      -- Local bus --
      addrLocalBus        => addr_LocalBus, 
      dataLocalBusIn      => data_LocalBusIn,
      dataLocalBusOut     => data_LocalBusOut(i_MTX3D.ID),
      reLocalBus          => re_LocalBus(i_MTX3D.ID),
      weLocalBus          => we_LocalBus(i_MTX3D.ID),
      readyLocalBus       => ready_LocalBus(i_MTX3D.ID)
    );
    
    -- MTX2D -----------------------------------------------------------------------------
    u_MTX2 : Matrix2D
    port map(
      rst                 => system_reset,
      clk                 => clk_200MHz,
      sclk                => clk_10MHz,
      -- Module input --
      tofSig              => tof_sig_in(NofTOF-1 downto 0),
      fbhSig              => fbh_cluster,
      chSig               => ch_sig_in,
            
      -- Module output --
      Trigger             => mtx2,
      DirectTrigger       => trig_from_2d,
      -- Local bus --
      addrLocalBus        => addr_LocalBus, 
      dataLocalBusIn      => data_LocalBusIn,
      dataLocalBusOut     => data_LocalBusOut(i_MTX2D.ID),
      reLocalBus          => re_LocalBus(i_MTX2D.ID),
      weLocalBus          => we_LocalBus(i_MTX2D.ID),
      readyLocalBus       => ready_LocalBus(i_MTX2D.ID)
    );
    
    -- Veto ------------------------------------------------------------------------------
    u_Veto : VetoModule
    port map(
        rst             => system_reset, 
        clk             => clk_200MHz,
        VETO            => veto_from_3d,
        DirectTrigger   => trig_from_2d,
        VetoTrigger     => veto_trigger
    );
    
    -- BCT -------------------------------------------------------------------------------
    u_BCT_Inst : BusController
    port map(
        rstSys                      => system_reset,
        rstFromBus                  => rst_from_bus,
        reConfig                    => PROG_B_ON,
        clk                         => clk_200MHz,
        -- Local Bus --
        addrLocalBus                => addr_LocalBus,
        dataFromUserModules         => data_LocalBusOut,
        dataToUserModules           => data_LocalBusIn,
        reLocalBus                  => re_LocalBus,
        weLocalBus                  => we_LocalBus,
        readyLocalBus               => ready_LocalBus,
        -- RBCP --
        RBCP_ADDR                   => rbcp_addr,
        RBCP_WD                     => rbcp_wd,
        RBCP_WE                     => rbcp_we,
        RBCP_RE                     => rbcp_re,
        RBCP_ACK                    => rbcp_ack,
        RBCP_RD                     => rbcp_rd
    );
    
    -- TSD -------------------------------------------------------------------------------
    u_TSD : TCP_sender
    port map(
        RST                      => user_reset,
        CLK                      => clk_200MHz,
         
        -- data from EVB --
        rdFromEVB                => tdc_data,
        rvFromEVB                => valid_data,
        emptyFromEVB             => empty_data,
        reToEVB                  => req_data,
           
        -- data to SiTCP
        isActive                 => tcp_isActive,
        afullTx                  => tcp_tx_full,
        weTx                     => tcp_tx_wr,
        wdTx                     => tcp_tx_data
    );


    -- SiTCP Inst ------------------------------------------------------------------------
   	PHY_MDIO        <= mdio_out when(mdio_oe = '1') else 'Z';
   	sel_gmii_mii    <= '1';
   	tcp_tx_clk      <= clk_125MHz when(sel_gmii_mii = '1') else PHY_TX_CLK;
   	PHY_GTX_CLK     <= clk_125MHz;
   	PHY_HPD         <= '0';

    u_SiTCP_Inst : WRAP_SiTCP_GMII_XC7K_32K
    port map
    (
        CLK                    => clk_200MHz, --: System Clock >129MHz
        RST                    => system_reset, --: System reset
    -- Configuration parameters
        FORCE_DEFAULTn         => DIP(0), --: Load default parameters
        EXT_IP_ADDR            => X"00000000", --: IP address[31:0]
        EXT_TCP_PORT           => X"0000", --: TCP port #[15:0]
        EXT_RBCP_PORT          => X"0000", --: RBCP port #[15:0]
        PHY_ADDR               => "00000", --: PHY-device MIF address[4:0]
        MY_MAC_ADDR	           => open,
    -- EEPROM
        EEPROM_CS            => PROM_CS, --: Chip select
        EEPROM_SK            => PROM_SK, --: Serial data clock
        EEPROM_DI            => PROM_DI, --: Serial write data
        EEPROM_DO            => PROM_DO, --: Serial read data
        --    user data, intialial values are stored in the EEPROM, 0xFFFF_FC3C-3F
        USR_REG_X3C            => reg_dummy0, --: Stored at 0xFFFF_FF3C
        USR_REG_X3D            => reg_dummy1, --: Stored at 0xFFFF_FF3D
        USR_REG_X3E            => reg_dummy2, --: Stored at 0xFFFF_FF3E
        USR_REG_X3F            => reg_dummy3, --: Stored at 0xFFFF_FF3F
    -- MII interface
        GMII_RSTn             => PHY_nRST, --: PHY reset
        GMII_1000M            => sel_gmii_mii,  --: GMII mode (0:MII, 1:GMII)
        -- TX
        GMII_TX_CLK           => tcp_tx_clk, -- : Tx clock
        GMII_TX_EN            => PHY_TXEN, --: Tx enable
        GMII_TXD              => PHY_TXD, --: Tx data[7:0]
        GMII_TX_ER            => PHY_TXER, --: TX error
        -- RX
        GMII_RX_CLK           => PHY_RX_CLK, -- : Rx clock
        GMII_RX_DV            => PHY_RXDV, -- : Rx data valid
        GMII_RXD              => PHY_RXD, -- : Rx data[7:0]
        GMII_RX_ER            => PHY_RXER, --: Rx error
        GMII_CRS              => PHY_CRS, --: Carrier sense
        GMII_COL              => PHY_COL, --: Collision detected
        -- Management IF
        GMII_MDC              => PHY_MDC, --: Clock for MDIO
        GMII_MDIO_IN          => PHY_MDIO, -- : Data
        GMII_MDIO_OUT         => mdio_out, --: Data
        GMII_MDIO_OE          => mdio_oe, --: MDIO output enable
    -- User I/F
        SiTCP_RST             => open, --: Reset for SiTCP and related circuits
        -- TCP connection control
        TCP_OPEN_REQ          => '0', -- : Reserved input, shoud be 0
        TCP_OPEN_ACK          => tcp_isActive, --: Acknowledge for open (=Socket busy)
    --    TCP_ERROR           : out    std_logic; --: TCP error, its active period is equal to MSL
        TCP_CLOSE_REQ         => close_req, --: Connection close request
        TCP_CLOSE_ACK         => close_act, -- : Acknowledge for closing
        -- FIFO I/F
        TCP_RX_WC             => X"0000",    --: Rx FIFO write count[15:0] (Unused bits should be set 1)
        TCP_RX_WR             => open, --: Read enable
        TCP_RX_DATA           => open, --: Read data[7:0]
        TCP_TX_FULL           => tcp_tx_full, --: Almost full flag
        TCP_TX_WR             => tcp_tx_wr, -- : Write enable
        TCP_TX_DATA           => tcp_tx_data, -- : Write data[7:0]
        -- RBCP
        RBCP_ACT              => open, --: RBCP active
        RBCP_ADDR             => rbcp_addr, --: Address[31:0]
        RBCP_WD               => rbcp_wd, --: Data[7:0]
        RBCP_WE               => rbcp_we, --: Write enable
        RBCP_RE               => rbcp_re, --: Read enable
        RBCP_ACK              => rbcp_ack, -- : Access acknowledge
        RBCP_RD               => rbcp_rd -- : Read data[7:0]
    );

    u_gTCP_inst : global_sitcp_manager
    port map(
        RST           => system_reset,
        CLK           => clk_200MHz,
        ACTIVE        => tcp_isActive,
        REQ           => close_req,
        ACT           => close_act,
        rstFromTCP    => open
    );

    -- Clock inst ------------------------------------------------------------------------
    u_ClkWis_Inst :  clk_wiz_1
    port map(
       -- Clock in ports
       clk_in1           => CLKOSC,
       -- Clock out ports
       clk_out1          => clk_200MHz,
       clk_out2          => clk_125MHz,
       clk_out3          => clk_10MHz,
       -- Status and control signals
       reset             => '0',
       locked            => clk_locked
      );

end Behavioral;
