-------------------------------------------------------------------------------
--
-- Project name: UDP_100G
--
-- (C) Copyright 2019 DFC Design, s.r.o., Brno, Czech Republic
-- Author: Jakub Hadamek (j.hadamek@dfcdesign.cz)
--
-------------------------------------------------------------------------------
-- UDP_100G IP Core
--
-- This file is top of udp_100g component. It is meant to be conected to 
-- Xilinx 100G Ethernet Subsystem via AXI Stream interface and other control 
-- and status signals. 
--
-- It's purpose is to implement UDP/IP protocol on 100Gb Ethernet. It takes 
-- data from User AXI Stream and encapsulates it in UDP, IP and MAC headers. 
-- Packet route informations (destination MAC address, IP address and UDP port)
-- are registered after first data from AXI Stream are accepted by core, it means
-- TVALID from user is in high state and it core is ready for another data signaling
-- it with TREADY high. 
--
-- IP Core consist of 6 + 1(debug) modules:
-- cmac_control
--    It's responsible for reseting CMAC Core and for conection establish process. 
--    It hold all other logic in this IP core in reset state until RX path is fully 
--    aligned and receiver is not sending to us remote fault indication code. 
-- frame_tx_if
--    This module is reposponsible for counting number of bytes which are supposed to
--    be sent in one packet and writing packet data into FIFO. Except data it writes
--    number of bytes to be send together with destination routing informations into 
--    second FIFO. It also checks if incoming AXI Stream has the right format - TKEEP
--    has to be all ones except if TLAST is high. When TLAST is high is checks if 
--    TKEEP has all ones to some point and the rest is zeros. It can't be like 
--    MSb ff00000000000005 LSb. In case data are invalid invalid flag is written into FIFO. 
--    Part of pre calculated IP header checksum is written into FIFO too. 
-- frame_generator
--    This module read data from FIFO and encapsulates it with UDP, IP and MAC headers. 
--    It also checks if data are valid and in case it is not it only pulls it out from FIFO. 
--    Rest of IP header checksum is calculated and inserted into IP header. If packet length 
--    is less than minimal ethernet packet length (64) is completed with zero padding bytes. 
-- frame_receiver
--    This module receive AXI Stream from CMAC and check if incoming packet is for us - compare
--    packet destination addresses with host addresses. It also compute IP header ckecksum so 
--    it is possible to say if packet is valid. If packet is valid and is for us it is written 
--    into FIFO. Source addresses and UDP port are stored in the second FIFO together with 
--    final data count. Module also count number of received bytes and check if data length 
--    parsed from UDP header corresponds with counted number. If it doesn't agree invalid flag
--    is written into FIFO so packet is marked as invalid. 
-- frame_rx_if
--    This module is responsible for taking data out from FIFO and passing it to user if 
--    data in FIFO are valid. In other case in only read it out and wait for next packet. 
-- axis_register
--    This module is used to register outcomming AXI Stream with FLIP FLOPs. 
-- debug_control (plus 1)
--    This module checks if loopback mode is enabled and reset this and CMAC core if its value change. 
-- 
-------------------------------------------------------------------------------




library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

Library xpm;
use xpm.vcomponents.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;

entity udp_100g is
   generic (
      g_tx_dfifo_depth  : integer  := 512; -- 512 bit data width (8 data bytes)
      g_tx_tfifo_depth  : integer  := 128;  -- 129 bit data width
      g_rx_dfifo_depth  : integer  := 512; -- 512 bit data width (8 data bytes)
      g_rx_tfifo_depth  : integer  := 128;  -- 129 bit data width
      g_tx_dfifo_type   : string   := "block"; -- auto, block, distributed
      g_tx_tfifo_type   : string   := "block";
      g_rx_dfifo_type   : string   := "block";
      g_rx_tfifo_type   : string   := "block";
      g_arp_enable      : boolean  := FALSE;
      g_arp_stack_depth : integer  := 16;
      g_max_pkt_len     : natural range 64 to 9600 := 9600
           );
   port (
      -- Core reset
      RESET                : in  std_logic := '0';
      -- Core clock
      CLK                  : in  std_logic := '0';
      CMAC_CLK             : in  std_logic := '0';

      ------------   CMAC Interface    ---------
      -- TX Datapath
      M_AXIS_TX_TVALID     : out std_logic := '0';
      M_AXIS_TX_TREADY     : in  std_logic := '0';
      M_AXIS_TX_TUSER      : out std_logic := '0';
      M_AXIS_TX_TLAST      : out std_logic := '0';
      M_AXIS_TX_TKEEP      : out std_logic_vector(63 downto 0);
      M_AXIS_TX_TDATA      : out std_logic_vector(511 downto 0);
      -- RX Datapath
      S_AXIS_RX_TVALID     : in  std_logic := '0';
      S_AXIS_RX_TREADY     : out std_logic := '0';
      S_AXIS_RX_TUSER      : in  std_logic := '0';
      S_AXIS_RX_TLAST      : in  std_logic := '0';
      S_AXIS_RX_TKEEP      : in  std_logic_vector(63 downto 0) := (others => '0');
      S_AXIS_RX_TDATA      : in  std_logic_vector(511 downto 0) := (others => '0');
      -- Control signals
      CTL_RX_ENABLE        : out std_logic := '0';
      CTL_TX_ENABLE        : out std_logic := '0';      
      CTL_TX_SEND_RFI      : out std_logic := '0';
      CTL_TX_SEND_LFI      : out std_logic := '0';
      CTL_TX_SEND_IDLE     : out std_logic := '0';
      CTL_TX_PREAMBLE      : out std_logic_vector(55 downto 0) := (others => '0');
      -- Status signals
      STAT_RX_ALIGNED      : in  std_logic := '1';
      STAT_RX_REMOTE_FAULT : in  std_logic := '0';
      STAT_TX_OVERFLOW     : in  std_logic := '0';
      STAT_TX_UNDERFLOW    : in  std_logic := '0';     
      -- User interface reset signals from CMAC
      USR_RX_RESET         : in  std_logic := '0';
      USR_TX_RESET         : in  std_logic := '0';      
      -- CMAC core reset
      CMAC_RESET           : out std_logic := '0';
      -- CMAC datapaths reset
      RX_RESET             : out std_logic := '0';
      TX_RESET             : out std_logic := '0';
      
      ------------   USER Interface    ---------
      -- TX Datapath
      S_AXIS_TX_TVALID     : in  std_logic := '0';
      S_AXIS_TX_TREADY     : out std_logic := '0';
      S_AXIS_TX_TLAST      : in  std_logic := '0';
      S_AXIS_TX_TKEEP      : in  std_logic_vector(63 downto 0) := (others => '0');
      S_AXIS_TX_TDATA      : in  std_logic_vector(511 downto 0) := (others => '0');
      -- RX Datapath
      M_AXIS_RX_TVALID     : out std_logic := '0';
      M_AXIS_RX_TREADY     : in  std_logic := '0';
      M_AXIS_RX_TLAST      : out std_logic := '0';
      M_AXIS_RX_TKEEP      : out std_logic_vector(63 downto 0) := (others => '0');
      M_AXIS_RX_TDATA      : out std_logic_vector(511 downto 0) := (others => '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 net info
      RX_DST_UDP           : out std_logic_vector(15 downto 0) := (others => '0');
      RX_SRC_UDP           : out std_logic_vector(15 downto 0) := (others => '0');
      RX_SRC_IP            : out std_logic_vector(31 downto 0) := (others => '0');
      RX_SRC_MAC           : out std_logic_vector(47 downto 0) := (others => '0');
      RX_PACKET_LENGTH     : out std_logic_vector(15 downto 0) := (others => '0');
      -- TX net info
      TX_SRC_UDP           : in  std_logic_vector(15 downto 0) := (others => '0');
      TX_DST_UDP           : in  std_logic_vector(15 downto 0) := (others => '0');
      TX_DST_IP            : in  std_logic_vector(31 downto 0) := (others => '0');
      TX_DST_MAC           : in  std_logic_vector(47 downto 0) := (others => '0');
      -- Initialization done - ready to send and receive
      INIT_DONE            : out std_logic := '0';
      -- Packet divided user signal 
      PACKET_DIVIDED       : out std_logic := '0';
      RX_OVERFLOW          : out std_logic := '0'
   );
end;

architecture Behavioral of udp_100g is


component xcdc_bit is
   generic (
      g_length       : integer := 2;
      g_rst_val      : std_logic := '0'
           );
   port (
      RSTN        : in  std_logic;
      DCLK        : in  std_logic;
      DATA_IN     : in  std_logic;
      DATA_OUT    : out std_logic
        );
end component;

   -- 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;
      
   constant LC_FIFO_DEPTH           : natural := round_up(g_max_pkt_len*2/64);
   

   ----------------------------------------
   ------------   Constants    ------------
   ----------------------------------------
   constant LC_TX_TAG_FIFO_WIDTH : natural := 131;
   constant LC_RX_TAG_FIFO_WIDTH : natural := 129;
   constant LC_DATA_FIFO_WIDTH   : natural := 576;
   
   ----------------------------------------
   ------------   TX Interface    ---------
   ----------------------------------------
   -- Data from TX interface to FIFO
   signal txi_dfifo_wren         : std_logic;
   signal txi_dfifo_data         : std_logic_vector(LC_DATA_FIFO_WIDTH-1 downto 0);
   signal txi_dfifo_full         : std_logic := '0';
   signal txi_dfifo_wr_rst_busy  : std_logic := '0';
   -- Tags from TX interface to FIFO
   signal txi_tfifo_wren         : std_logic;
   signal txi_tfifo_data         : std_logic_vector(LC_TX_TAG_FIFO_WIDTH-1 downto 0);
   signal txi_tfifo_full         : std_logic := '0';
   signal txi_tfifo_wr_rst_busy  : std_logic := '0';
   -- Data from FIFO to frame generator
   signal txg_dfifo_rden         : std_logic;
   signal txg_dfifo_data         : std_logic_vector(LC_DATA_FIFO_WIDTH-1 downto 0);
   signal txg_dfifo_empty        : std_logic := '0';
   signal txg_dfifo_rd_rst_busy  : std_logic := '0';
   -- Tags from FIFO to frame generator
   signal txg_tfifo_rden         : std_logic;
   signal txg_tfifo_data         : std_logic_vector(LC_TX_TAG_FIFO_WIDTH-1  downto 0);
   signal txg_tfifo_empty        : std_logic := '0';
   signal txg_tfifo_rd_rst_busy  : std_logic := '0';
   -- Non registered output stream
   signal m_axis_tx_tvalid_i     : std_logic := '0';
   signal m_axis_tx_tready_i     : std_logic := '0';
   signal m_axis_tx_tlast_i      : std_logic := '0';
   signal m_axis_tx_tuser_i      : std_logic := '0';
   signal m_axis_tx_tkeep_i      : std_logic_vector(63 downto 0) := (others => '0');
   signal m_axis_tx_tdata_i      : std_logic_vector(511 downto 0) := (others => '0');
   
   ----------------------------------------
   ------------   RX Interface    ---------
   ----------------------------------------
   -- Data from frame receiver to FIFO
   signal rxr_dfifo_wren         : std_logic;
   signal rxr_dfifo_data         : std_logic_vector(LC_DATA_FIFO_WIDTH-1 downto 0);
   signal rxr_dfifo_full         : std_logic := '0';
   signal rxr_dfifo_wr_rst_busy  : std_logic := '0';
   -- Tags from frame receiver to FIFO
   signal rxr_tfifo_wren         : std_logic;
   signal rxr_tfifo_data         : std_logic_vector(LC_RX_TAG_FIFO_WIDTH-1  downto 0);
   signal rxr_tfifo_full         : std_logic := '0';
   signal rxr_tfifo_wr_rst_busy  : std_logic := '0';
   -- Data from FIFO to RX interface
   signal rxi_dfifo_rden         : std_logic;
   signal rxi_dfifo_data         : std_logic_vector(LC_DATA_FIFO_WIDTH-1 downto 0);
   signal rxi_dfifo_empty        : std_logic := '0';
   signal rxi_dfifo_rd_rst_busy  : std_logic := '0';
   -- Tags from FIFO to RX interface
   signal rxi_tfifo_rden         : std_logic;
   signal rxi_tfifo_data         : std_logic_vector(LC_RX_TAG_FIFO_WIDTH-1  downto 0);
   signal rxi_tfifo_empty        : std_logic := '0';
   signal rxi_tfifo_rd_rst_busy  : std_logic := '0';
   -- Non registered output stream
   signal m_axis_rx_tvalid_i     : std_logic := '0';
   signal m_axis_rx_tready_i     : std_logic := '0';
   signal m_axis_rx_tlast_i      : std_logic := '0';
   signal m_axis_rx_tkeep_i      : std_logic_vector(63 downto 0) := (others => '0');
   signal m_axis_rx_tdata_i      : std_logic_vector(511 downto 0) := (others => '0');
   -- registered source infos
   signal pkt_info               : std_logic_vector(RX_DST_UDP'length + RX_SRC_UDP'length + 
                                    RX_SRC_IP'length + RX_SRC_MAC'length + RX_PACKET_LENGTH'length - 1 downto 0) := (others => '0');
   signal pkt_info_reg           : std_logic_vector(RX_DST_UDP'length + RX_SRC_UDP'length + 
                                    RX_SRC_IP'length + RX_SRC_MAC'length + RX_PACKET_LENGTH'length - 1 downto 0) := (others => '0');
      
   ----------------------------------------
   ------------   CMAC Control    ---------
   ----------------------------------------   
   -- Initialization done
   signal init_done_i            : std_logic := '0';
   -- Internal reset signals
   signal tx_rst                 : std_logic := '0';
   signal rx_rst                 : std_logic := '0';   
   signal debug_rst              : std_logic := '0';
   signal cmac_rst               : std_logic := '0';
   
   -- ARP
   signal arp_request_rcv        : std_logic := '0';
   signal arp_src_mac_rcv        : std_logic_vector(47 downto 0) := (others => '0');
   signal arp_src_ip_rcv         : std_logic_vector(31 downto 0) := (others => '0');
   signal arp_request_gen        : std_logic := '0';
   signal arp_request_accepted   : std_logic := '0';
   signal arp_src_mac_gen        : std_logic_vector(47 downto 0) := (others => '0');
   signal arp_src_ip_gen         : std_logic_vector(31 downto 0) := (others => '0');
   
   -- control and status internals
  -- Control signals
  signal ctl_rx_enable_i         : std_logic := '0';
  signal ctl_tx_enable_i         : std_logic := '0';      
  signal ctl_tx_send_rfi_i       : std_logic := '0';
  signal ctl_tx_send_lfi_i       : std_logic := '0';
  signal ctl_tx_send_idle_i      : std_logic := '0';
  signal ctl_tx_preamble_i       : std_logic_vector(55 downto 0) := (others => '0');
  -- Status signal
  signal stat_rx_aligned_i       : std_logic := '1';
  signal stat_rx_remote_fault_i  : std_logic := '0';
  signal stat_tx_overflow_i      : std_logic := '0';
  signal stat_tx_underflow_i     : std_logic := '0';     
  -- User interface reset signals from CMAC
  signal usr_rx_reset_i          : std_logic := '0';
  signal usr_tx_reset_i          : std_logic := '0';      
  -- CMAC core reset
  signal cmac_reset_i            : std_logic := '0';
  -- CMAC datapaths reset
  signal rx_reset_i              : std_logic := '0';
  signal tx_reset_i              : std_logic := '0';
   
  signal s_axis_rx_tvalid_i      : std_logic := '0';
  signal s_axis_rx_tready_i      : std_logic := '0';
  signal s_axis_rx_tuser_i       : std_logic := '0';
  signal s_axis_rx_tlast_i       : std_logic := '0';
  signal s_axis_rx_tkeep_i       : std_logic_vector(63 downto 0) := (others => '0');
  signal s_axis_rx_tdata_i       : std_logic_vector(511 downto 0) := (others => '0');   
begin


   ----------------------------------------
   ------------   Debug Control    --------
   ---------------------------------------- 
   
--   INIT_DONE <= init_done_i;
   
--   debug_control_inst: entity work.debug_control
--   port map( 
--      -- Reset and clock
--      RESET                => RESET,
--      INIT_CLK             => INIT_CLK,
--      CLK             => CLK,
--      -- Debug control enable
--      DEBUG_ON             => DBG_DEBUG_ON,
--      -- Initialization done
--      INIT_DONE            => init_done_i,
--      -- Test pattern generating and checking 
--      TEST_PATTERN         => DBG_TEST_PATTERN_EN,
--      -- RX test pattern checking enable
--      RX_TEST_PATTERN      => DBG_RX_TEST_PATTERN,
--      -- TX test pattern generation enable
--      TX_TEST_PATTERN      => DBG_TX_TEST_PATTERN,
--      -- Loopback mode 
--      LOOPBACK_MODE_CTRL   => DBG_LOOPBACK_MODE_USER,
--      LOOPBACK_MODE        => DBG_LOOPBACK_MODE_CMAC,
--      -- CMAC reset after change of loopback mode
--      DEBUG_RESET          => debug_rst
--   );

   ---------------------------------------------
   ------------   CMAC Control    --------------
   ---------------------------------------------
   
--   CMAC_RESET <= debug_rst or cmac_rst;
--   CMAC_RESET <= cmac_rst;
   
   cmac_control_inst: entity work.cmac_control
   port map(
      -- Core reset
      RESET                => RESET,
      
      -- Core clock
      CLK                  => CLK,

      -- Control signals
      RX_ENABLE            => ctl_rx_enable_i,   
      TX_ENABLE            => ctl_tx_enable_i,   
      TX_SEND_RFI          => ctl_tx_send_rfi_i, 
      TX_SEND_LFI          => ctl_tx_send_lfi_i, 
      TX_SEND_IDLE         => ctl_tx_send_idle_i,
      TX_PREAMBLE          => ctl_tx_preamble_i, 
      
      -- Status signals
      RX_ALIGNED           => stat_rx_aligned_i,      
      RX_RFI               => stat_rx_remote_fault_i, 
      TX_OVERFLOW          => stat_tx_overflow_i,     
      TX_UNDERFLOW         => stat_tx_underflow_i,    
      
      -- User interface reset signals from CMAC
      USR_RX_RESET         => usr_rx_reset_i,
      USR_TX_RESET         => usr_tx_reset_i,
      
      -- Reset signals to user interface
      RX_RESET             => rx_reset_i,
      TX_RESET             => tx_reset_i,
      CMAC_RESET           => cmac_reset_i,
      
      -- Reset signals to Core
      RX_CORE_RESET        => rx_rst,
      TX_CORE_RESET        => tx_rst,
      
      -- Initialization done
      INIT_DONE            => INIT_DONE
   );




   ----------------------------------------
   ------------   TX SIDE    --------------
   ----------------------------------------
      
   frame_tx_if_inst: entity work.frame_tx_if
   generic map( 
      g_max_pkt_len                 => g_max_pkt_len
   )
   port map(
      -- Interface reset
      RESET                         => tx_rst,
      -- Interface clock
      CLK                           => CLK,
      -- TX from USER
      S_AXIS_TVALID                 => S_AXIS_TX_TVALID,
      S_AXIS_TREADY                 => S_AXIS_TX_TREADY,
      S_AXIS_TLAST                  => S_AXIS_TX_TLAST, 
      S_AXIS_TKEEP                  => S_AXIS_TX_TKEEP, 
      S_AXIS_TDATA                  => S_AXIS_TX_TDATA, 
      -- TX to data FIFO
      TD_FIFO_WREN                  => txi_dfifo_wren, 
      TD_FIFO_FULL                  => txi_dfifo_full, 
      TD_FIFO_DATA                  => txi_dfifo_data, 
      TD_FIFO_RST_BUSY              => txi_dfifo_wr_rst_busy,
      -- TX to tag FIFO
      TT_FIFO_WREN                  => txi_tfifo_wren, 
      TT_FIFO_FULL                  => txi_tfifo_full, 
      TT_FIFO_DATA                  => txi_tfifo_data, 
      TT_FIFO_RST_BUSY              => txi_tfifo_wr_rst_busy,
      -- TX net info
      SRC_UDP                       => TX_SRC_UDP,
      DST_UDP                       => TX_DST_UDP,
      DST_IP                        => TX_DST_IP, 
      DST_MAC                       => TX_DST_MAC,
      PACKET_DIVIDED                => PACKET_DIVIDED,
      HOST_IP                       => HOST_IP
   );
   
   txi_dfifo_inst : xpm_fifo_sync
   generic map (
      FIFO_MEMORY_TYPE           => g_tx_dfifo_type,          
      ECC_MODE                   => "no_ecc",         
      FIFO_WRITE_DEPTH           => g_tx_dfifo_depth,             
      WRITE_DATA_WIDTH           => txi_dfifo_data'length, 
      WR_DATA_COUNT_WIDTH        => 1,               
      PROG_FULL_THRESH           => 5,               
      FULL_RESET_VALUE           => 0,                
      READ_MODE                  => "fwft",           
      FIFO_READ_LATENCY          => 0,                
      READ_DATA_WIDTH            => txi_dfifo_data'length, 
      RD_DATA_COUNT_WIDTH        => 1,               
      PROG_EMPTY_THRESH          => 5,               
      DOUT_RESET_VALUE           => "0",              
      WAKEUP_TIME                => 0                 
   )
   port map (
      rst                        => tx_rst,
      wr_clk                     => CLK,
      wr_en                      => txi_dfifo_wren,
      din                        => txi_dfifo_data,
      full                       => txi_dfifo_full,
      overflow                   => open,
      wr_rst_busy                => txi_dfifo_wr_rst_busy,
      rd_en                      => txg_dfifo_rden,
      dout                       => txg_dfifo_data,
      empty                      => txg_dfifo_empty,
      underflow                  => open,
      rd_rst_busy                => txg_dfifo_rd_rst_busy,
      prog_full                  => open,
      wr_data_count              => open,
      prog_empty                 => open,
      rd_data_count              => open,
      sleep                      => '0',
      injectsbiterr              => '0',
      injectdbiterr              => '0',
      sbiterr                    => open,
      dbiterr                    => open
   );

   txi_tfifo_inst : xpm_fifo_sync
   generic map (
      FIFO_MEMORY_TYPE           => g_tx_dfifo_type,          
      ECC_MODE                   => "no_ecc",         
      FIFO_WRITE_DEPTH           => g_tx_tfifo_depth,             
      WRITE_DATA_WIDTH           => txi_tfifo_data'length, 
      WR_DATA_COUNT_WIDTH        => 1,               
      PROG_FULL_THRESH           => 5,               
      FULL_RESET_VALUE           => 0,                
      READ_MODE                  => "fwft",           
      FIFO_READ_LATENCY          => 0,                
      READ_DATA_WIDTH            => txi_tfifo_data'length, 
      RD_DATA_COUNT_WIDTH        => 1,               
      PROG_EMPTY_THRESH          => 5,               
      DOUT_RESET_VALUE           => "0",              
      WAKEUP_TIME                => 0                 
   )
   port map (
      rst                        => tx_rst,
      wr_clk                     => CLK,
      wr_en                      => txi_tfifo_wren,
      din                        => txi_tfifo_data,
      full                       => txi_tfifo_full,
      overflow                   => open,
      wr_rst_busy                => txi_tfifo_wr_rst_busy,
      rd_en                      => txg_tfifo_rden,
      dout                       => txg_tfifo_data,
      empty                      => txg_tfifo_empty,
      underflow                  => open,
      rd_rst_busy                => txg_tfifo_rd_rst_busy,
      prog_full                  => open,
      wr_data_count              => open,
      prog_empty                 => open,
      rd_data_count              => open,
      sleep                      => '0',
      injectsbiterr              => '0',
      injectdbiterr              => '0',
      sbiterr                    => open,
      dbiterr                    => open
   );

   frame_generator_inst: entity work.frame_gen
   port map(
      -- Interface reset
      RESET                         => tx_rst,
      -- Interface clock
      CLK                           => CLK,
      -- TX to CMAC
      M_AXIS_TVALID                 => m_axis_tx_tvalid_i,
      M_AXIS_TREADY                 => m_axis_tx_tready_i,
      M_AXIS_TUSER                  => m_axis_tx_tuser_i, 
      M_AXIS_TLAST                  => m_axis_tx_tlast_i, 
      M_AXIS_TKEEP                  => m_axis_tx_tkeep_i, 
      M_AXIS_TDATA                  => m_axis_tx_tdata_i, 
      -- TX to data FIFO
      TD_FIFO_RDEN                  => txg_dfifo_rden, 
      TD_FIFO_EMPTY                 => txg_dfifo_empty, 
      TD_FIFO_DATA                  => txg_dfifo_data, 
      TD_FIFO_RST_BUSY              => txg_dfifo_rd_rst_busy,
      -- TX to tag FIFO
      TT_FIFO_RDEN                  => txg_tfifo_rden, 
      TT_FIFO_EMPTY                 => txg_tfifo_empty, 
      TT_FIFO_DATA                  => txg_tfifo_data,
      TT_FIFO_RST_BUSY              => txg_tfifo_rd_rst_busy,
      -- ETH/IP/UDP
      HOST_MAC                      => HOST_MAC,
      HOST_IP                       => HOST_IP,
      -- ARP request
      ARP_REQUEST                   => arp_request_gen,
      ARP_ACCEPTED                  => arp_request_accepted,
      ARP_SRC_MAC                   => arp_src_mac_gen,
      ARP_SRC_IP                    => arp_src_ip_gen
   );

--   tx_cmac_axis_register: entity work.axis_register
--   generic map(
--      g_extra_data_width   => 0
--   )
--   port map(
--      RESET                => tx_rst,
--      CLK                  => CLK,
--      -- AXI Stream input
--      S_AXIS_TVALID        => m_axis_tx_tvalid_i,
--      S_AXIS_TREADY        => m_axis_tx_tready_i,
--      S_AXIS_TLAST         => m_axis_tx_tlast_i, 
--      S_AXIS_TUSER         => m_axis_tx_tuser_i,
--      S_AXIS_TKEEP         => m_axis_tx_tkeep_i, 
--      S_AXIS_TDATA         => m_axis_tx_tdata_i, 
      
--      -- AXI Stream output
--      M_AXIS_TVALID        => M_AXIS_TX_TVALID, 
--      M_AXIS_TREADY        => M_AXIS_TX_TREADY,
--      M_AXIS_TLAST         => M_AXIS_TX_TLAST, 
--      M_AXIS_TUSER         => M_AXIS_TX_TUSER,
--      M_AXIS_TKEEP         => M_AXIS_TX_TKEEP, 
--      M_AXIS_TDATA         => M_AXIS_TX_TDATA
--   );


   ----------------------------------------
   ------------   RX SIDE    --------------
   ----------------------------------------
      
   frame_receiver_inst: entity work.frame_receiver
   port map(
      -- Interface reset
      RESET                => rx_rst,
      -- Interface clock
      CLK                  => CLK,
      -- RX from CMAC
      S_AXIS_TVALID        => s_axis_rx_tvalid_i,
      S_AXIS_TREADY        => s_axis_rx_tready_i,
      S_AXIS_TUSER         => s_axis_rx_tuser_i, 
      S_AXIS_TLAST         => s_axis_rx_tlast_i, 
      S_AXIS_TKEEP         => s_axis_rx_tkeep_i, 
      S_AXIS_TDATA         => s_axis_rx_tdata_i, 
      -- RX to data FIFO
      RD_FIFO_WREN         => rxr_dfifo_wren,
      RD_FIFO_FULL         => rxr_dfifo_full,
      RD_FIFO_DATA         => rxr_dfifo_data,
      RD_FIFO_RST_BUSY     => rxr_dfifo_wr_rst_busy,
      -- RX to tag FIFO
      RT_FIFO_WREN         => rxr_tfifo_wren,
      RT_FIFO_FULL         => rxr_tfifo_full,
      RT_FIFO_DATA         => rxr_tfifo_data,
      RT_FIFO_RST_BUSY     => rxr_tfifo_wr_rst_busy,
      -- ETH/IP/UDP
      HOST_MAC             => HOST_MAC,     
      HOST_IP              => HOST_IP,      
      HOST_NET_MASK        => HOST_NET_MASK,
      -- Status
      RX_OVERFLOW          => RX_OVERFLOW,
      -- ARP
      ARP_REQUEST          => arp_request_rcv,
      ARP_SRC_MAC          => arp_src_mac_rcv,
      ARP_SRC_IP           => arp_src_ip_rcv
   );

   
   rxi_dfifo_inst : xpm_fifo_sync
   generic map (
      FIFO_MEMORY_TYPE           => g_rx_dfifo_type,          
      ECC_MODE                   => "no_ecc",         
      FIFO_WRITE_DEPTH           => g_rx_dfifo_depth,            
      WRITE_DATA_WIDTH           => rxi_dfifo_data'length, 
      WR_DATA_COUNT_WIDTH        => 1,               
      PROG_FULL_THRESH           => 5,               
      FULL_RESET_VALUE           => 0,                
      READ_MODE                  => "fwft",           
      FIFO_READ_LATENCY          => 0,                
      READ_DATA_WIDTH            => rxi_dfifo_data'length, 
      RD_DATA_COUNT_WIDTH        => 1,               
      PROG_EMPTY_THRESH          => 5,               
      DOUT_RESET_VALUE           => "0",              
      WAKEUP_TIME                => 0                 
   )
   port map (
      rst                        => rx_rst,
      wr_clk                     => CLK,
      wr_en                      => rxr_dfifo_wren,
      din                        => rxr_dfifo_data,
      full                       => rxr_dfifo_full,
      overflow                   => open,
      wr_rst_busy                => rxr_dfifo_wr_rst_busy,
      rd_en                      => rxi_dfifo_rden,
      dout                       => rxi_dfifo_data,
      empty                      => rxi_dfifo_empty,
      underflow                  => open,
      rd_rst_busy                => rxi_dfifo_rd_rst_busy,
      prog_full                  => open,
      wr_data_count              => open,
      prog_empty                 => open,
      rd_data_count              => open,
      sleep                      => '0',
      injectsbiterr              => '0',
      injectdbiterr              => '0',
      sbiterr                    => open,
      dbiterr                    => open
   );

   rxi_tfifo_inst : xpm_fifo_sync
   generic map (
      FIFO_MEMORY_TYPE           => g_rx_dfifo_type,          
      ECC_MODE                   => "no_ecc",         
      FIFO_WRITE_DEPTH           => g_tx_tfifo_depth,             
      WRITE_DATA_WIDTH           => rxi_tfifo_data'length, 
      WR_DATA_COUNT_WIDTH        => 1,               
      PROG_FULL_THRESH           => 5,               
      FULL_RESET_VALUE           => 0,                
      READ_MODE                  => "fwft",           
      FIFO_READ_LATENCY          => 0,                
      READ_DATA_WIDTH            => rxi_tfifo_data'length, 
      RD_DATA_COUNT_WIDTH        => 1,               
      PROG_EMPTY_THRESH          => 5,               
      DOUT_RESET_VALUE           => "0",              
      WAKEUP_TIME                => 0                 
   )
   port map (
      rst                        => rx_rst,
      wr_clk                     => CLK,
      wr_en                      => rxr_tfifo_wren,
      din                        => rxr_tfifo_data,
      full                       => rxr_tfifo_full,
      overflow                   => open,
      wr_rst_busy                => rxr_tfifo_wr_rst_busy,
      rd_en                      => rxi_tfifo_rden,
      dout                       => rxi_tfifo_data,
      empty                      => rxi_tfifo_empty,
      underflow                  => open,
      rd_rst_busy                => rxi_tfifo_rd_rst_busy,
      prog_full                  => open,
      wr_data_count              => open,
      prog_empty                 => open,
      rd_data_count              => open,
      sleep                      => '0',
      injectsbiterr              => '0',
      injectdbiterr              => '0',
      sbiterr                    => open,
      dbiterr                    => open
   );

   frame_rx_if_inst: entity work.frame_rx_if 
   port map(
      -- Interface reset
      RESET                => rx_rst,
      -- Interface clock
      CLK                  => CLK,
      -- RX to USER
      M_AXIS_TVALID        => m_axis_rx_tvalid_i,
      M_AXIS_TREADY        => m_axis_rx_tready_i,
      M_AXIS_TLAST         => m_axis_rx_tlast_i, 
      M_AXIS_TKEEP         => m_axis_rx_tkeep_i, 
      M_AXIS_TDATA         => m_axis_rx_tdata_i, 
      -- RX from data FIFO
      RD_FIFO_RDEN         => rxi_dfifo_rden,
      RD_FIFO_EMPTY        => rxi_dfifo_empty,
      RD_FIFO_DATA         => rxi_dfifo_data,
      RD_FIFO_RST_BUSY     => rxi_dfifo_rd_rst_busy,
      -- RX from tag FIFO
      RT_FIFO_RDEN         => rxi_tfifo_rden,
      RT_FIFO_EMPTY        => rxi_tfifo_empty,
      RT_FIFO_DATA         => rxi_tfifo_data,
      RT_FIFO_RST_BUSY     => rxi_tfifo_rd_rst_busy,
      -- RX net inf
      SRC_UDP              => pkt_info(RX_SRC_UDP'length-1 downto 0), 
      DST_UDP              => pkt_info(RX_SRC_UDP'length+RX_DST_UDP'length-1 downto RX_SRC_UDP'length),
      SRC_IP               => pkt_info(RX_SRC_UDP'length+RX_DST_UDP'length+RX_SRC_IP'length-1 
                              downto RX_SRC_UDP'length+RX_DST_UDP'length),
      SRC_MAC              => pkt_info(RX_SRC_UDP'length+RX_DST_UDP'length+RX_SRC_IP'length+RX_SRC_MAC'length-1 
                              downto RX_SRC_UDP'length+RX_DST_UDP'length+RX_SRC_IP'length),
      PACKET_LENGTH        => pkt_info(RX_SRC_UDP'length+RX_DST_UDP'length+RX_SRC_IP'length+RX_SRC_MAC'length+RX_PACKET_LENGTH'length-1 
                              downto RX_SRC_UDP'length+RX_DST_UDP'length+RX_SRC_IP'length+RX_SRC_MAC'length)
   );   

   rx_user_axis_register: entity work.axis_register
   generic map(
      g_extra_data_width   => pkt_info'length
   )
   port map(
      RESET                => rx_rst,
      CLK                  => CLK,
      -- AXI Stream input
      S_AXIS_TVALID        => m_axis_rx_tvalid_i,
      S_AXIS_TREADY        => m_axis_rx_tready_i,
      S_AXIS_TLAST         => m_axis_rx_tlast_i, 
      S_AXIS_TUSER         => '0', 
      S_AXIS_TKEEP         => m_axis_rx_tkeep_i, 
      S_AXIS_TDATA         => m_axis_rx_tdata_i, 
      S_EXTRA_DATA         => pkt_info,
      -- AXI Stream output
      M_AXIS_TVALID        => M_AXIS_RX_TVALID, 
      M_AXIS_TREADY        => M_AXIS_RX_TREADY,
      M_AXIS_TLAST         => M_AXIS_RX_TLAST, 
      M_AXIS_TUSER         => open, 
      M_AXIS_TKEEP         => M_AXIS_RX_TKEEP, 
      M_AXIS_TDATA         => M_AXIS_RX_TDATA,
      M_EXTRA_DATA         => pkt_info_reg
   );

   RX_SRC_UDP        <= pkt_info_reg(RX_SRC_UDP'length-1 downto 0);
   RX_DST_UDP        <= pkt_info_reg(RX_SRC_UDP'length+RX_DST_UDP'length-1 downto RX_SRC_UDP'length);
   RX_SRC_IP         <= pkt_info_reg(RX_SRC_UDP'length+RX_DST_UDP'length+RX_SRC_IP'length-1 
                        downto RX_SRC_UDP'length+RX_DST_UDP'length);
   RX_SRC_MAC        <= pkt_info_reg(RX_SRC_UDP'length+RX_DST_UDP'length+RX_SRC_IP'length+RX_SRC_MAC'length-1 
                        downto RX_SRC_UDP'length+RX_DST_UDP'length+RX_SRC_IP'length);
   RX_PACKET_LENGTH  <= pkt_info_reg(RX_SRC_UDP'length+RX_DST_UDP'length+RX_SRC_IP'length+RX_SRC_MAC'length+RX_PACKET_LENGTH'length-1 
                        downto RX_SRC_UDP'length+RX_DST_UDP'length+RX_SRC_IP'length+RX_SRC_MAC'length);



   ----------------------------------------
   ------------      ARP        -----------
   ----------------------------------------
   arp_stack_gen: if g_arp_enable = TRUE generate
      arp_stack_inst: entity work.arp_stack
         generic map(
            g_stack_length       => g_arp_stack_depth
         )
         port map(
            -- Interface reset
            RESET                => rx_rst,
            -- Interface clock
            CLK                  => CLK,
            -- ARP request input
            ARP_REQUEST_IN       => arp_request_rcv,
            ARP_SRC_MAC_IN       => arp_src_mac_rcv,
            ARP_SRC_IP_IN        => arp_src_ip_rcv,
            -- ARP request output
            ARP_REQUEST          => arp_request_gen,
            ARP_ACCEPTED         => arp_request_accepted,
            ARP_SRC_MAC          => arp_src_mac_gen,
            ARP_SRC_IP           => arp_src_ip_gen
         );
   end generate;
   
   
   udp_to_cmac_cdc_inst: entity work.udp_to_cmac_cdc
   generic map(
      g_max_pkt_len              => g_max_pkt_len
   )
   port map(
      RESET                      => RESET,
      -- Core clock
      CMAC_CLK                   => CMAC_CLK,
      UDP_CLK                    => CLK,

      ------------   CMAC side    ---------
      -- TX Datapath
      CMAC_M_AXIS_TX_TVALID      => M_AXIS_TX_TVALID,
      CMAC_M_AXIS_TX_TREADY      => M_AXIS_TX_TREADY,
      CMAC_M_AXIS_TX_TUSER       => M_AXIS_TX_TUSER,
      CMAC_M_AXIS_TX_TLAST       => M_AXIS_TX_TLAST,
      CMAC_M_AXIS_TX_TKEEP       => M_AXIS_TX_TKEEP,
      CMAC_M_AXIS_TX_TDATA       => M_AXIS_TX_TDATA,
      -- RX Datapath
      CMAC_S_AXIS_RX_TVALID      => S_AXIS_RX_TVALID,
      CMAC_S_AXIS_RX_TREADY      => S_AXIS_RX_TREADY,
      CMAC_S_AXIS_RX_TUSER       => S_AXIS_RX_TUSER,
      CMAC_S_AXIS_RX_TLAST       => S_AXIS_RX_TLAST,
      CMAC_S_AXIS_RX_TKEEP       => S_AXIS_RX_TKEEP,
      CMAC_S_AXIS_RX_TDATA       => S_AXIS_RX_TDATA,
      -- Control signals
      CMAC_CTL_RX_ENABLE         => CTL_RX_ENABLE,
      CMAC_CTL_TX_ENABLE         => CTL_TX_ENABLE,
      CMAC_CTL_TX_SEND_RFI       => CTL_TX_SEND_RFI,
      CMAC_CTL_TX_SEND_LFI       => CTL_TX_SEND_LFI,
      CMAC_CTL_TX_SEND_IDLE      => CTL_TX_SEND_IDLE,
      CMAC_CTL_TX_PREAMBLE       => CTL_TX_PREAMBLE,
      -- Status signals
      CMAC_STAT_RX_ALIGNED       => STAT_RX_ALIGNED,
      CMAC_STAT_RX_REMOTE_FAULT  => STAT_RX_REMOTE_FAULT,
      CMAC_STAT_TX_OVERFLOW      => STAT_TX_OVERFLOW,
      CMAC_STAT_TX_UNDERFLOW     => STAT_TX_UNDERFLOW,     
      -- User interface reset signals from CMAC
      CMAC_USR_RX_RESET          => USR_RX_RESET,
      CMAC_USR_TX_RESET          => USR_TX_RESET,      
      -- CMAC core reset
      CMAC_CMAC_RESET            => CMAC_RESET,
      -- CMAC datapaths reset
      CMAC_RX_RESET              => RX_RESET,
      CMAC_TX_RESET              => TX_RESET,
   
      ------------   UDP side    ---------
      -- TX Datapath
      UDP_M_AXIS_TX_TVALID       => m_axis_tx_tvalid_i,
      UDP_M_AXIS_TX_TREADY       => m_axis_tx_tready_i,
      UDP_M_AXIS_TX_TUSER        => m_axis_tx_tuser_i, 
      UDP_M_AXIS_TX_TLAST        => m_axis_tx_tlast_i, 
      UDP_M_AXIS_TX_TKEEP        => m_axis_tx_tkeep_i, 
      UDP_M_AXIS_TX_TDATA        => m_axis_tx_tdata_i, 
      -- RX Datapath
      UDP_S_AXIS_RX_TVALID       => s_axis_rx_tvalid_i,
      UDP_S_AXIS_RX_TREADY       => s_axis_rx_tready_i,
      UDP_S_AXIS_RX_TUSER        => s_axis_rx_tuser_i,
      UDP_S_AXIS_RX_TLAST        => s_axis_rx_tlast_i,
      UDP_S_AXIS_RX_TKEEP        => s_axis_rx_tkeep_i,
      UDP_S_AXIS_RX_TDATA        => s_axis_rx_tdata_i,
      -- Control signals
      UDP_CTL_RX_ENABLE          => ctl_rx_enable_i,
      UDP_CTL_TX_ENABLE          => ctl_tx_enable_i,
      UDP_CTL_TX_SEND_RFI        => ctl_tx_send_rfi_i,
      UDP_CTL_TX_SEND_LFI        => ctl_tx_send_lfi_i,
      UDP_CTL_TX_SEND_IDLE       => ctl_tx_send_idle_i,
      UDP_CTL_TX_PREAMBLE        => ctl_tx_preamble_i,
      -- Status signals
      UDP_STAT_RX_ALIGNED        => stat_rx_aligned_i,
      UDP_STAT_RX_REMOTE_FAULT   => stat_rx_remote_fault_i,
      UDP_STAT_TX_OVERFLOW       => stat_tx_overflow_i,
      UDP_STAT_TX_UNDERFLOW      => stat_tx_underflow_i,     
      -- User interface reset signals from CMAC
      UDP_USR_RX_RESET           => usr_rx_reset_i,
      UDP_USR_TX_RESET           => usr_tx_reset_i,     
      -- CMAC core reset
      UDP_CMAC_RESET             => cmac_reset_i,
      -- CMAC datapaths reset
      UDP_RX_RESET               => rx_reset_i,
      UDP_TX_RESET               => tx_reset_i
    );
   
end;
