----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 01/21/2020 01:09:14 PM
-- Design Name: 
-- Module Name: rdma_adc_app - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

Library xpm;
use xpm.vcomponents.all;

entity rdma_adc_app is
   generic (
      g_adc_eth_clk_same      : boolean := true;
      g_packet_length         : natural range 1 to 140 := 140;
      g_threshold_words       : natural range 0 to 500 := 0;
      g_roce_qp_num           : std_logic_vector(23 downto 0) := x"000000";
      g_reg_udp_port          : std_logic_vector(15 downto 0) := x"0000";
      g_roce_udp_port         : std_logic_vector(15 downto 0) := x"0000";
      g_debug                 : boolean := false
   );
   port (
      ------------   UDP 100G Interface    ---------
      -- Core clock and reset
      ETH_RESET               : in  std_logic := '0';
      ETH_CLK                 : in  std_logic := '0';
      -- Host net info --
      HOST_MAC                : in  std_logic_vector(47 downto 0) := (others => '0');
      HOST_IP                 : in  std_logic_vector(31 downto 0) := (others => '0');
      HOST_NET_MASK           : in  std_logic_vector(31 downto 0) := (others => '0');
      -- RX Datapath --
      S_AXIS_UDP_TVALID       : in  std_logic := '0';
      S_AXIS_UDP_TREADY       : out std_logic := '0';
      S_AXIS_UDP_TLAST        : in  std_logic := '0';
      S_AXIS_UDP_TKEEP        : in  std_logic_vector(63 downto 0) := (others => '0');
      S_AXIS_UDP_TDATA        : in  std_logic_vector(511 downto 0) := (others => '0');
      -- RX net info
      RX_DST_UDP              : in std_logic_vector(15 downto 0) := (others => '0');
      RX_SRC_UDP              : in std_logic_vector(15 downto 0) := (others => '0');
      RX_SRC_IP               : in std_logic_vector(31 downto 0) := (others => '0');
      RX_SRC_MAC              : in std_logic_vector(47 downto 0) := (others => '0');
      RX_PACKET_LENGTH        : in std_logic_vector(15 downto 0) := (others => '0');
      -- TX Datapath --
      M_AXIS_UDP_TVALID       : out std_logic := '0';
      M_AXIS_UDP_TREADY       : in  std_logic := '0';
      M_AXIS_UDP_TLAST        : out std_logic := '0';
      M_AXIS_UDP_TKEEP        : out std_logic_vector(63 downto 0) := (others => '0');
      M_AXIS_UDP_TDATA        : out std_logic_vector(511 downto 0) := (others => '0');
      -- TX net info
      TX_SRC_UDP              : out  std_logic_vector(15 downto 0) := (others => '0');
      TX_DST_UDP              : out  std_logic_vector(15 downto 0) := (others => '0');
      TX_DST_IP               : out  std_logic_vector(31 downto 0) := (others => '0');
      TX_DST_MAC              : out  std_logic_vector(47 downto 0) := (others => '0');
      -- Packet divided user signal 
      PACKET_DIVIDED          : in  std_logic := '0';

      ------------   ADC Interface    --------- 
      -- Core clock and reset
      ADC_RESET               : in  std_logic := '0';
      ADC_CLK                 : in  std_logic := '0';
      -- ADC data
      S_AXIS_ADC_TVALID       : in  std_logic := '0';
      S_AXIS_ADC_TREADY       : out std_logic := '0';
      S_AXIS_ADC_TLAST        : in  std_logic := '0';
      S_AXIS_ADC_TKEEP        : in  std_logic_vector(63 downto 0) := (others => '0');
      S_AXIS_ADC_TDATA        : in  std_logic_vector(511 downto 0) := (others => '0')
   
    );
end rdma_adc_app;

architecture Behavioral of rdma_adc_app is

   type channel_control_t is (IDLE_ST, RUN_ST, OVERFLOW_ST);
   signal channel_fsm       : channel_control_t := IDLE_ST;

   signal eth_resetn            : std_logic := '0';
   signal roce_reset            : std_logic := '0';
   signal adc_resetn            : std_logic := '0';
   
   signal channel_s_axis_tvalid     : std_logic := '0';     
   signal channel_s_axis_tlast      : std_logic := '0';     
   signal channel_s_axis_tready     : std_logic := '0';         
   signal channel_s_axis_tdata      : std_logic_vector(511 downto 0) := (others => '0');   
   signal channel_s_axis_tkeep      : std_logic_vector(63 downto 0) := (others => '0');    
   signal channel_s_axis_tvalid_cdc : std_logic := '0';     
   signal channel_s_axis_tlast_cdc  : std_logic := '0';     
   signal channel_s_axis_tready_cdc : std_logic := '0';         
   signal channel_s_axis_tdata_cdc  : std_logic_vector(511 downto 0) := (others => '0');   
   signal channel_s_axis_tkeep_cdc  : std_logic_vector(63 downto 0) := (others => '0');        
   signal channel_fifo_cnt          : std_logic_vector(31 downto 0) := (others => '0');  
   signal channel_rstn              : std_logic := '0';
   signal channel_full              : std_logic := '0';  
   signal channel_running           : std_logic := '0';
   
   
   -- TX Datapath
   signal roce_s_axis_tvalid        : std_logic := '0';
   signal roce_s_axis_tready        : std_logic := '0';
   signal roce_s_axis_tlast         : std_logic := '0';
   signal roce_s_axis_tkeep         : std_logic_vector(63 downto 0) := (others => '0');
   signal roce_s_axis_tdata         : std_logic_vector(511 downto 0) := (others => '0');
   signal roce_tx_dst_ip           : std_logic_vector(31 downto 0);
   signal roce_tx_dst_mac          : std_logic_vector(47 downto 0);
   
 
   ------------   Control signals  --------------
   -- original clock domain
   signal channel_run_not_clear  : std_logic := '0';  
   signal channel_run            : std_logic := '0';                                
   signal channel_clear          : std_logic := '0';                               
   signal channel_overflow       : std_logic := '0';                                
   signal channel_word_cnt       : std_logic_vector(63 downto 0) := (others => '0');                                
   signal roce_tx_dst_qp        : std_logic_vector(23 downto 0) := (others => '0');                   
   signal roce_tx_psn            : std_logic_vector(23 downto 0) := (others => '0');  
   signal roce_tx_q_key          : std_logic_vector(31 downto 0) := (others => '0');
   signal roce_tx_dst_udp       : std_logic_vector(15 downto 0) := (others => '0');
   -- another clock domain
   signal channel_run_cdc        : std_logic := '0';                                
   signal channel_clear_cdc      : std_logic := '0';                               
   signal channel_overflow_cdc   : std_logic := '0';                                

   signal common_axis_tready     : std_logic := '0';    
   signal tmp_rst_cnt            : std_logic_vector(3 downto 0) := (others => '0');
   constant LC_TMP_RST_CNT       : std_logic_vector(tmp_rst_cnt'range) := (others => '1');

   ------------   UDP registers --------------
   -- TX Datapath
   signal app0_s_axis_tvalid      : std_logic := '0';
   signal app0_s_axis_tready      : std_logic := '0';
   signal app0_s_axis_tlast       : std_logic := '0';
   signal app0_s_axis_tkeep       : std_logic_vector(63 downto 0) := (others => '0');
   signal app0_s_axis_tdata       : std_logic_vector(511 downto 0) := (others => '0');
   -- tx net info         
   signal app0_tx_src_udp         : std_logic_vector(15 downto 0) := (others => '0');
   signal app0_tx_dst_udp         : std_logic_vector(15 downto 0) := (others => '0');
   signal app0_tx_dst_ip          : std_logic_vector(31 downto 0) := (others => '0');
   signal app0_tx_dst_mac         : std_logic_vector(47 downto 0) := (others => '0');
   -- packet divided user signal 
   signal app0_packet_divided     : std_logic := '0';
   -- rx data             
   signal app0_m_axis_tvalid      : std_logic := '0';
   signal app0_m_axis_tready      : std_logic := '0';
   signal app0_m_axis_tlast       : std_logic := '0';
   signal app0_m_axis_tkeep       : std_logic_vector(63 downto 0) := (others => '0'); 
   signal app0_m_axis_tdata       : std_logic_vector(511 downto 0) := (others => '0');
   -- rx net              
   signal app0_rx_dst_udp         : std_logic_vector(15 downto 0) := (others => '0');
   signal app0_rx_src_udp         : std_logic_vector(15 downto 0) := (others => '0');
   signal app0_rx_src_ip          : std_logic_vector(31 downto 0) := (others => '0');
   signal app0_rx_src_mac         : std_logic_vector(47 downto 0) := (others => '0');
   signal app0_rx_packet_length   : std_logic_vector(15 downto 0) := (others => '0');
   signal app0_duplicate_port     : std_logic := '0';
   
   ------------   UDP application --------------
   -- TX Datapath
   signal app1_s_axis_tvalid      : std_logic := '0';
   signal app1_s_axis_tready      : std_logic := '0';
   signal app1_s_axis_tlast       : std_logic := '0';
   signal app1_s_axis_tkeep       : std_logic_vector(63 downto 0) := (others => '0');
   signal app1_s_axis_tdata       : std_logic_vector(511 downto 0) := (others => '0');
   -- tx net info         
   signal app1_tx_src_udp         : std_logic_vector(15 downto 0) := (others => '0');
   signal app1_tx_dst_udp         : std_logic_vector(15 downto 0) := (others => '0');
   signal app1_tx_dst_ip          : std_logic_vector(31 downto 0) := (others => '0');
   signal app1_tx_dst_mac         : std_logic_vector(47 downto 0) := (others => '0');
   -- packet divided user signal 
   signal app1_packet_divided     : std_logic := '0';
   -- rx data             
   signal app1_m_axis_tvalid      : std_logic := '0';
   signal app1_m_axis_tready      : std_logic := '0';
   signal app1_m_axis_tlast       : std_logic := '0';
   signal app1_m_axis_tkeep       : std_logic_vector(63 downto 0) := (others => '0'); 
   signal app1_m_axis_tdata       : std_logic_vector(511 downto 0) := (others => '0');
   -- rx net              
   signal app1_rx_dst_udp         : std_logic_vector(15 downto 0) := (others => '0');
   signal app1_rx_src_udp         : std_logic_vector(15 downto 0) := (others => '0');
   signal app1_rx_src_ip          : std_logic_vector(31 downto 0) := (others => '0');
   signal app1_rx_src_mac         : std_logic_vector(47 downto 0) := (others => '0');
   signal app1_rx_packet_length   : std_logic_vector(15 downto 0) := (others => '0');
   signal app1_duplicate_port     : std_logic := '0';

   constant LC_ROCE_PKT_LEN         : std_logic_vector(15 downto 0) := std_logic_vector(to_unsigned(g_packet_length,16));
   constant LC_ROCE_PKT_LEN_BYTES   : std_logic_vector(15 downto 0) := LC_ROCE_PKT_LEN(9 downto 0) & "000000";    

   -- or vector
   function round_up (num  : natural)
      return natural is
      begin
         for i in 0 to 9 loop
            if 2**i > num then
               return 2**i;
            end if;
         end loop;
         return 2**10;
      end round_up;

   -- read count width
   function rd_cnt_width (num  : natural)
      return natural is
      begin
         for i in 0 to 9 loop
            if 2**i = num then
               return i + 1;
            end if;
         end loop;
         return 11;
      end rd_cnt_width;
      
   constant LC_FIFO_DEPTH           : natural := round_up(g_packet_length);
   constant LC_RD_CNT_WIDTH         : natural := rd_cnt_width(LC_FIFO_DEPTH);
begin

   -- negation of incoming resets
   eth_resetn <= not ETH_RESET;
   adc_resetn <= not ADC_RESET;


   -- channel control register
      -- run channel
      -- clear channel
   -- channel status register
      -- send counter
      -- overflow
   -- common control register
      -- synchronized (use this register insted of channel registers)
      -- run all
      -- clear all -- clear runs
   -- common status register
      -- overflow (set if one or more channels are overflowed)



   channel_ctrl_fsm_proc: process(ADC_CLK)
   begin
      if rising_edge(ADC_CLK) then
         if ADC_RESET = '1' then
            channel_fsm <= IDLE_ST;
            channel_running <= '0';
            channel_overflow <= '0';
         else
           -- channel control
           case channel_fsm is
              when IDLE_ST =>
                 if channel_s_axis_tready = '1' then
                    channel_fsm <= RUN_ST;
                    channel_running <= '1';
                 end if;
              when RUN_ST =>
                 if channel_s_axis_tready = '0' then
                    channel_fsm <= IDLE_ST;
                    channel_running <= '0';
                 elsif channel_full = '1' then
                    channel_fsm <= OVERFLOW_ST;
                    channel_running <= '0';
                    channel_overflow <= '1';
                 end if;
              when OVERFLOW_ST => 
                 if channel_clear_cdc = '1' then
                    channel_fsm <= IDLE_ST;
                    channel_overflow <= '0';
                 end if;
           end case;

        end if;
      end if;
   end process;

   -- is system ready?
   S_AXIS_ADC_TREADY <= channel_s_axis_tready and channel_running;
   
   -- is data valid?
   channel_s_axis_tvalid <= S_AXIS_ADC_TVALID and channel_running;
   channel_s_axis_tlast  <= S_AXIS_ADC_TLAST;
   channel_s_axis_tdata  <= S_AXIS_ADC_TDATA;
   channel_s_axis_tkeep  <= S_AXIS_ADC_TKEEP;

   adc_eth_clk_different_gen: if g_adc_eth_clk_same = false generate     
   
      axis_data_fifo_channel_dif_clk: xpm_fifo_axis
      generic map(
        CLOCKING_MODE         =>  "independent_clock",
        FIFO_DEPTH            =>  LC_FIFO_DEPTH,
        TDATA_WIDTH           =>  512,
        USE_ADV_FEATURES      => "1408",
        RD_DATA_COUNT_WIDTH   =>  LC_RD_CNT_WIDTH
      )
      port map(
        s_aresetn             => channel_rstn,
        m_aclk                => ETH_CLK,
        s_aclk                => ADC_CLK,
        s_axis_tvalid         => channel_s_axis_tvalid,
        s_axis_tready         => channel_s_axis_tready,
        s_axis_tdata          => channel_s_axis_tdata, 
        s_axis_tstrb          => x"ffffffffffffffff",      
        s_axis_tkeep          => channel_s_axis_tkeep, 
        s_axis_tlast          => channel_s_axis_tlast, 
        s_axis_tid            => "0",                     
        s_axis_tdest          => "0",                     
        s_axis_tuser          => "0",                     
        m_axis_tvalid         => channel_s_axis_tvalid_cdc,
        m_axis_tready         => channel_s_axis_tready_cdc,
        m_axis_tdata          => channel_s_axis_tdata_cdc,
        m_axis_tstrb          => open,
        m_axis_tkeep          => channel_s_axis_tkeep_cdc,
        m_axis_tlast          => channel_s_axis_tlast_cdc,
        m_axis_tid            => open,
        m_axis_tdest          => open,
        m_axis_tuser          => open,
        almost_full_axis      => channel_full,
        rd_data_count_axis    => channel_fifo_cnt(LC_RD_CNT_WIDTH-1 downto 0),
        injectsbiterr_axis    => '0',
        injectdbiterr_axis    => '0',
        sbiterr_axis          => open,
        dbiterr_axis          => open
      );
          
      channel_clear_cdc_inst: entity work.xcdc_bit
      port map(
         RSTN        => adc_resetn,
         DCLK        => ADC_CLK,
         DATA_IN     => channel_clear,
         DATA_OUT    => channel_clear_cdc
      );

      channel_overflow_cdc_inst: entity work.xcdc_bit
      port map(
         RSTN        => eth_resetn,
         DCLK        => ETH_CLK,
         DATA_IN     => channel_overflow,
         DATA_OUT    => channel_overflow_cdc
      );
   end generate;
   
   adc_eth_clk_same_gen: if g_adc_eth_clk_same = true generate

      axis_data_fifo_channel_same_clk: xpm_fifo_axis
      generic map(
        CLOCKING_MODE         =>  "common_clock",
        FIFO_DEPTH            =>  LC_FIFO_DEPTH,
        TDATA_WIDTH           =>  512,
        USE_ADV_FEATURES      => "1408",
        RD_DATA_COUNT_WIDTH   =>  LC_RD_CNT_WIDTH
      )
      port map(
        s_aresetn             => channel_rstn,
        m_aclk                => ETH_CLK,
        s_aclk                => ETH_CLK,
        s_axis_tvalid         => channel_s_axis_tvalid,
        s_axis_tready         => channel_s_axis_tready,
        s_axis_tdata          => channel_s_axis_tdata, 
        s_axis_tstrb          => x"ffffffffffffffff",      
        s_axis_tkeep          => channel_s_axis_tkeep, 
        s_axis_tlast          => channel_s_axis_tlast, 
        s_axis_tid            => "0",                     
        s_axis_tdest          => "0",                     
        s_axis_tuser          => "0",                     
        m_axis_tvalid         => channel_s_axis_tvalid_cdc,
        m_axis_tready         => channel_s_axis_tready_cdc,
        m_axis_tdata          => channel_s_axis_tdata_cdc,
        m_axis_tstrb          => open,
        m_axis_tkeep          => channel_s_axis_tkeep_cdc,
        m_axis_tlast          => channel_s_axis_tlast_cdc,
        m_axis_tid            => open,
        m_axis_tdest          => open,
        m_axis_tuser          => open,
        almost_full_axis      => channel_full,
        rd_data_count_axis    => channel_fifo_cnt(LC_RD_CNT_WIDTH-1 downto 0),
        injectsbiterr_axis    => '0',
        injectdbiterr_axis    => '0',
        sbiterr_axis          => open,
        dbiterr_axis          => open
      );

   
      channel_clear_cdc <= channel_clear;
      channel_overflow_cdc <= channel_overflow;
   end generate;
   
   
   channel_control_inst: entity work.channel_control
   generic map(
      -- if there is need to finish packet of packet length
      -- before it's stopped
      g_packet_mode     => true,
      -- should be MAX_UDP_PACKET - 1 (because of RoCE headers)
      g_packet_length   => g_packet_length,
      g_threshold_words => g_threshold_words
   )
   port map(
      CLK               => ETH_CLK,
      RESET             => ETH_RESET,
      -- Control signals
      RUN               => channel_run_not_clear,
      FIFO_RSTN         => channel_rstn,
      OVERFLOW          => channel_overflow_cdc,
      -- Status signals
      SEND_CNT          => channel_word_cnt,
      -- Data input
      S_AXIS_TVALID     => channel_s_axis_tvalid_cdc,
      S_AXIS_TREADY     => channel_s_axis_tready_cdc,
      S_AXIS_TLAST      => channel_s_axis_tlast_cdc, 
      S_AXIS_TKEEP      => channel_s_axis_tkeep_cdc, 
      S_AXIS_TDATA      => channel_s_axis_tdata_cdc, 
      FIFO_DATA_CNT     => channel_fifo_cnt,
      -- Data output
      M_AXIS_TVALID     => roce_s_axis_tvalid,
      M_AXIS_TREADY     => roce_s_axis_tready, 
      M_AXIS_TLAST      => roce_s_axis_tlast,
      M_AXIS_TKEEP      => roce_s_axis_tkeep, 
      M_AXIS_TDATA      => roce_s_axis_tdata
    );

   channel_run_not_clear <= channel_run and not channel_clear;

   udp_registers_inst: entity work.udp_registers
   generic map(
      g_udp_port              => g_reg_udp_port,
      g_debug                 => g_debug
   )
   port map(
      ------------   UDP 100G Interface    ---------
      -- Core clock and reset
      RESET                   => ETH_RESET,
      CLK                     => ETH_CLK,
      -- Host info
      HOST_MAC                => HOST_MAC,
      HOST_IP                 => HOST_IP,
      HOST_NET_MASK           => HOST_NET_MASK,
      -- RX Datapath --
      S_AXIS_TVALID           => app0_m_axis_tvalid,   
      S_AXIS_TREADY           => app0_m_axis_tready,   
      S_AXIS_TLAST            => app0_m_axis_tlast,    
      S_AXIS_TKEEP            => app0_m_axis_tkeep,    
      S_AXIS_TDATA            => app0_m_axis_tdata,    
      -- RX net info
      RX_DST_UDP              => app0_rx_dst_udp,      
      RX_SRC_UDP              => app0_rx_src_udp,      
      RX_SRC_IP               => app0_rx_src_ip,       
      RX_SRC_MAC              => app0_rx_src_mac,      
      RX_PACKET_LENGTH        => app0_rx_packet_length,
      -- TX Datapath --
      M_AXIS_TVALID           => app0_s_axis_tvalid,
      M_AXIS_TREADY           => app0_s_axis_tready,
      M_AXIS_TLAST            => app0_s_axis_tlast, 
      M_AXIS_TKEEP            => app0_s_axis_tkeep, 
      M_AXIS_TDATA            => app0_s_axis_tdata, 
      -- TX net info
      TX_SRC_UDP              => app0_tx_src_udp,   
      TX_DST_UDP              => app0_tx_dst_udp,   
      TX_DST_IP               => app0_tx_dst_ip,    
      TX_DST_MAC              => app0_tx_dst_mac,   
      -- control signals
      REG_CHANNEL_RUN         => channel_run,
      REG_CHANNEL_CLEAR       => channel_clear,
      REG_CHANNEL_OVERFLOW    => channel_overflow_cdc,  
      REG_CHANNEL_WORD_CNT    => channel_word_cnt,
      -- packets related signals
      REG_ROCE_TX_DEST_IP     => roce_tx_dst_ip,
      REG_ROCE_TX_DEST_MAC    => roce_tx_dst_mac,
      REG_ROCE_TX_DEST_QP     => roce_tx_dst_qp,
      REG_ROCE_TX_DEST_UDP    => roce_tx_dst_udp,
      REG_ROCE_TX_PSN         => roce_tx_psn,
      REG_ROCE_TX_Q_KEY       => roce_tx_q_key
    );

   roce_reset <= ETH_RESET;-- or not channel_run_not_clear;
   
  roce_to_100g_udp_inst: entity work.roce_to_100g_udp
  generic map(
      g_crc_pipe_stage_cnt => 4
  )
  port map(
      RESET                => roce_reset,
      CLK                  => ETH_CLK,
      -- 100G UDP Interface
      HOST_MAC             => HOST_MAC,
      HOST_IP              => HOST_IP,
      HOST_NET_MASK        => HOST_NET_MASK,
      M_AXIS_TVALID        => app1_s_axis_tvalid,
      M_AXIS_TREADY        => app1_s_axis_tready,
      M_AXIS_TLAST         => app1_s_axis_tlast, 
      M_AXIS_TKEEP         => app1_s_axis_tkeep, 
      M_AXIS_TDATA         => app1_s_axis_tdata, 
      UDP_TX_SRC_UDP       => app1_tx_src_udp,
      UDP_TX_DST_UDP       => app1_tx_dst_udp,
      UDP_TX_DST_IP        => app1_tx_dst_ip, 
      UDP_TX_DST_MAC       => app1_tx_dst_mac,
      -- RoCE Interface (Data)
      ROCE_TX_DST_MAC      => roce_tx_dst_mac,
      ROCE_TX_DST_IP       => roce_tx_dst_ip,
      ROCE_TX_SRC_UDP      => g_roce_udp_port,
      ROCE_TX_DST_UDP      => roce_tx_dst_udp,
      S_AXIS_TVALID        => roce_s_axis_tvalid,
      S_AXIS_TREADY        => roce_s_axis_tready,
      S_AXIS_TLAST         => roce_s_axis_tlast,
      S_AXIS_TKEEP         => roce_s_axis_tkeep,
      S_AXIS_TDATA         => roce_s_axis_tdata,
      ROCE_TX_DATA_LEN     => LC_ROCE_PKT_LEN_BYTES,
      ROCE_TX_DEST_QP      => roce_tx_dst_qp,
      ROCE_TX_PSN          => roce_tx_psn,
      ROCE_TX_Q_KEY        => roce_tx_q_key,
      ROCE_TX_SRC_QP       => g_roce_qp_num
   );

   udp_100g_switch_2ports_inst: entity work.udp_100g_switch_2ports
   port map(
      -- Core clock and reset
      RESET                   => ETH_RESET,
      CLK                     => ETH_CLK,

      ------------   UDP 100G Interface    ---------
      -- RX Datapath --
      S_AXIS_UDP_TVALID       => S_AXIS_UDP_TVALID,
      S_AXIS_UDP_TREADY       => S_AXIS_UDP_TREADY,
      S_AXIS_UDP_TLAST        => S_AXIS_UDP_TLAST,
      S_AXIS_UDP_TKEEP        => S_AXIS_UDP_TKEEP,
      S_AXIS_UDP_TDATA        => S_AXIS_UDP_TDATA,
      -- RX net info
      RX_DST_UDP              => RX_DST_UDP,
      RX_SRC_UDP              => RX_SRC_UDP,
      RX_SRC_IP               => RX_SRC_IP,
      RX_SRC_MAC              => RX_SRC_MAC,
      RX_PACKET_LENGTH        => RX_PACKET_LENGTH,
      -- TX Datapath --
      M_AXIS_UDP_TVALID       => M_AXIS_UDP_TVALID,
      M_AXIS_UDP_TREADY       => M_AXIS_UDP_TREADY,
      M_AXIS_UDP_TLAST        => M_AXIS_UDP_TLAST,
      M_AXIS_UDP_TKEEP        => M_AXIS_UDP_TKEEP,
      M_AXIS_UDP_TDATA        => M_AXIS_UDP_TDATA,
      -- TX net info
      TX_SRC_UDP              => TX_SRC_UDP,
      TX_DST_UDP              => TX_DST_UDP,
      TX_DST_IP               => TX_DST_IP,
      TX_DST_MAC              => TX_DST_MAC,
      -- Packet divided user signal 
      PACKET_DIVIDED          => PACKET_DIVIDED,

      ------------   UDP Application 0 (UDP registers)    ---------
      -- TX Datapath
      APP0_S_AXIS_TVALID      => app0_s_axis_tvalid,
      APP0_S_AXIS_TREADY      => app0_s_axis_tready,
      APP0_S_AXIS_TLAST       => app0_s_axis_tlast, 
      APP0_S_AXIS_TKEEP       => app0_s_axis_tkeep, 
      APP0_S_AXIS_TDATA       => app0_s_axis_tdata, 
      -- tx net info
      APP0_TX_SRC_UDP         => app0_tx_src_udp,   
      APP0_TX_DST_UDP         => app0_tx_dst_udp,   
      APP0_TX_DST_IP          => app0_tx_dst_ip,    
      APP0_TX_DST_MAC         => app0_tx_dst_mac,   
      -- Packet divided user signal 
      APP0_PACKET_DIVIDED     => app0_packet_divided,   
      -- RX Data
      APP0_M_AXIS_TVALID      => app0_m_axis_tvalid,    
      APP0_M_AXIS_TREADY      => app0_m_axis_tready,    
      APP0_M_AXIS_TLAST       => app0_m_axis_tlast,     
      APP0_M_AXIS_TKEEP       => app0_m_axis_tkeep,     
      APP0_M_AXIS_TDATA       => app0_m_axis_tdata,     
      -- RX net info
      APP0_RX_DST_UDP         => app0_rx_dst_udp,
      APP0_RX_SRC_UDP         => app0_rx_src_udp,
      APP0_RX_SRC_IP          => app0_rx_src_ip,
      APP0_RX_SRC_MAC         => app0_rx_src_mac,
      APP0_RX_PACKET_LENGTH   => app0_rx_packet_length,
      APP0_DUPLICATE_PORT     => app0_duplicate_port,

      ------------   UDP Application 1 (RoCE)    ---------
      -- TX Datapath
      APP1_S_AXIS_TVALID      => app1_s_axis_tvalid, 
      APP1_S_AXIS_TREADY      => app1_s_axis_tready, 
      APP1_S_AXIS_TLAST       => app1_s_axis_tlast,  
      APP1_S_AXIS_TKEEP       => app1_s_axis_tkeep,  
      APP1_S_AXIS_TDATA       => app1_s_axis_tdata,  
      -- tx net info
      APP1_TX_SRC_UDP         => app1_tx_src_udp,    
      APP1_TX_DST_UDP         => app1_tx_dst_udp,    
      APP1_TX_DST_IP          => app1_tx_dst_ip,     
      APP1_TX_DST_MAC         => app1_tx_dst_mac,    
      -- Packet divided user signal 
      APP1_PACKET_DIVIDED     => app1_packet_divided,  
      -- RX Data
      APP1_M_AXIS_TVALID      => app1_m_axis_tvalid,   
      APP1_M_AXIS_TREADY      => app1_m_axis_tready,   
      APP1_M_AXIS_TLAST       => app1_m_axis_tlast,    
      APP1_M_AXIS_TKEEP       => app1_m_axis_tkeep,    
      APP1_M_AXIS_TDATA       => app1_m_axis_tdata,    
      -- RX net info
      APP1_RX_DST_UDP         => app1_rx_dst_udp,      
      APP1_RX_SRC_UDP         => app1_rx_src_udp,      
      APP1_RX_SRC_IP          => app1_rx_src_ip,       
      APP1_RX_SRC_MAC         => app1_rx_src_mac,      
      APP1_RX_PACKET_LENGTH   => app1_rx_packet_length,
      APP1_DUPLICATE_PORT     => app1_duplicate_port   
   );

   app1_m_axis_tready <= '1';

   debug_gen: if g_debug = true generate
      debug_ila: entity work.debug_ila
         port map(
            clk         => ETH_CLK,
            probe0(0)   => channel_s_axis_tvalid_cdc,
            probe1(0)   => channel_s_axis_tready_cdc,
            probe2(0)   => channel_s_axis_tlast_cdc, 
            probe3(0)   => roce_s_axis_tvalid,
            probe4(0)   => roce_s_axis_tready,
            probe5(0)   => roce_s_axis_tlast, 
            probe6(0)   => app1_s_axis_tvalid,
            probe7(0)   => app1_s_axis_tready,
            probe8(0)   => app1_s_axis_tlast, 
            probe9(0)   => app0_s_axis_tvalid,
            probe10(0)  => app0_s_axis_tready,
            probe11(0)  => app0_s_axis_tlast,
            probe12(0)  => channel_run,
            probe13(0)  => channel_run_not_clear,
            probe14(0)  => channel_overflow_cdc
         );
   end generate;
   
end Behavioral;
