-------------------------------------------------------------------------------
--
-- Project name: ROCE_TO_100G_UDP
--
-- (C) Copyright 2020 DFC Design, s.r.o., Brno, Czech Republic
-- Author: Jakub Hadamek (j.hadamek@dfcdesign.cz)
--
-------------------------------------------------------------------------------
--
-- This is top of ROCE_TO_100G_UDP ip Core
-- 
-------------------------------------------------------------------------------



library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.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 roce_to_100g_udp is
   generic(
      g_crc_pipe_stage_cnt : natural range 0 to 4 := 0
   );  
   port (
      -- Interface reset
      RESET                : in  std_logic;
      -- Interface clock
      CLK                  : in  std_logic;
      
      ------------   COMMON PROPERTIES    ---------
      -- info about host
      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');
      
      ------------   UDP TX INTERFACE (RX isn't needed)   ---------
      -- TX
      M_AXIS_TVALID        : out std_logic;
      M_AXIS_TREADY        : in  std_logic;
      M_AXIS_TLAST         : out std_logic;
      M_AXIS_TDATA         : out std_logic_vector(511 downto 0);
      M_AXIS_TKEEP         : out std_logic_vector(63 downto 0);
      -- UDP packet info towards UDP/IP 
      UDP_TX_SRC_UDP       : out std_logic_vector(15 downto 0) := (others => '0');
      UDP_TX_DST_UDP       : out std_logic_vector(15 downto 0) := (others => '0');
      UDP_TX_DST_IP        : out std_logic_vector(31 downto 0) := (others => '0');
      UDP_TX_DST_MAC       : out std_logic_vector(47 downto 0) := (others => '0');

      ------------   ROCE INTERFACE    ---------
      -- UDP packet info
      ROCE_TX_DST_MAC      : in  std_logic_vector(47 downto 0);
      ROCE_TX_DST_IP       : in  std_logic_vector(31 downto 0);
      ROCE_TX_SRC_UDP      : in  std_logic_vector(15 downto 0);
      ROCE_TX_DST_UDP      : in  std_logic_vector(15 downto 0);
      -- roce stream
      S_AXIS_TVALID        : in  std_logic;
      S_AXIS_TREADY        : out std_logic;
      S_AXIS_TLAST         : in  std_logic;
      S_AXIS_TKEEP         : in  std_logic_vector(63 downto 0);
      S_AXIS_TDATA         : in  std_logic_vector(511 downto 0);
      -- RoCE packet parameters
      ROCE_TX_DATA_LEN     : in  std_logic_vector(15 downto 0);
      ROCE_TX_DEST_QP      : in  std_logic_vector(23 downto 0);
      ROCE_TX_PSN          : in  std_logic_vector(23 downto 0):=(others => '0');
      ROCE_TX_Q_KEY        : in  std_logic_vector(31 downto 0);
      ROCE_TX_SRC_QP       : in  std_logic_vector(23 downto 0)
   );
end;

architecture Behavioral of roce_to_100g_udp is

   -- calculate pipeline values for CRC generator
   function pipe_stages_integer (stages : natural range 0 to 4)
      return integer is
      variable retval : integer := 0;
      begin
         case stages is
            when 0 => retval := 0;
            when 1 => retval := 2;
            when 2 => retval := 10;
            when 3 => retval := 11;
            when 4 => retval := 15; 
         end case;
         return retval;
      end pipe_stages_integer;   
   
   -- udp and ip informations
   signal s_extra_data     : std_logic_vector(UDP_TX_SRC_UDP'length + UDP_TX_DST_UDP'length + 
                              UDP_TX_DST_IP'length + UDP_TX_DST_MAC'length - 1 downto 0);
   -- data with inserted header
   signal m_axis_tvalid_hdr   : std_logic;
   signal m_axis_tready_hdr   : std_logic;
   signal m_axis_tlast_hdr    : std_logic;
   signal m_axis_tkeep_hdr    : std_logic_vector(M_AXIS_TKEEP'range);
   signal m_axis_tdata_hdr    : std_logic_vector(M_AXIS_TDATA'range);
   signal m_extra_data_hdr    : std_logic_vector(s_extra_data'range);
   -- data for crc generator
   signal udp_tx_data_len     : std_logic_vector(15 downto 0);
   signal extra_data          : std_logic_vector(s_extra_data'range);
   -- CRC calculation
   signal crc_data         : std_logic_vector(511 downto 0);
   signal crc_mask         : std_logic_vector(5 downto 0);
   signal crc_out          : std_logic_vector(31 downto 0);
   signal crc_dv           : std_logic;
   signal crc_cv           : std_logic;
   signal crc_eop          : std_logic;
   -- feedback signal saying crc was send out
   signal crc_done         : std_logic;
begin

   s_extra_data(47 downto 0) <= ROCE_TX_DST_MAC;
   s_extra_data(79 downto 48) <= ROCE_TX_DST_IP;
   s_extra_data(95 downto 80) <= ROCE_TX_SRC_UDP;
   s_extra_data(111 downto 96) <= ROCE_TX_DST_UDP;

   roce_insert_header_inst: entity work.roce_insert_header
   generic map(
      g_extra_data_width   => s_extra_data'length
   )
   port map(
      RESET                => RESET,
      CLK                  => CLK,
      -- AXI Stream input
      S_AXIS_TVALID        => S_AXIS_TVALID,
      S_AXIS_TREADY        => S_AXIS_TREADY,
      S_AXIS_TLAST         => S_AXIS_TLAST, 
      S_AXIS_TKEEP         => S_AXIS_TKEEP, 
      S_AXIS_TDATA         => S_AXIS_TDATA, 
      S_EXTRA_DATA         => s_extra_data,
      -- AXI Stream output
      M_AXIS_TVALID        => m_axis_tvalid_hdr,
      M_AXIS_TREADY        => m_axis_tready_hdr,
      M_AXIS_TLAST         => m_axis_tlast_hdr,
      M_AXIS_TKEEP         => m_axis_tkeep_hdr,
      M_AXIS_TDATA         => m_axis_tdata_hdr,
      M_EXTRA_DATA         => m_extra_data_hdr,
      -- RoCE header parameters
      ROCE_TX_DATA_LEN     => ROCE_TX_DATA_LEN,
      UDP_TX_DATA_LEN      => udp_tx_data_len, 
      ROCE_TX_DEST_QP      => ROCE_TX_DEST_QP, 
      ROCE_TX_PSN          => ROCE_TX_PSN,     
      -- DETH header fields
      ROCE_TX_Q_KEY        => ROCE_TX_Q_KEY,
      ROCE_TX_SRC_QP       => ROCE_TX_SRC_QP
   );

   roce_crc_if_inst: entity work.roce_crc_if
   generic map(
      g_extra_data_width   => s_extra_data'length
   )
   port map(
      RESET                => RESET,
      CLK                  => CLK,
      -- AXI Stream input
      S_AXIS_TVALID        => m_axis_tvalid_hdr,
      S_AXIS_TREADY        => m_axis_tready_hdr,
      S_AXIS_TLAST         => m_axis_tlast_hdr, 
      S_AXIS_TKEEP         => m_axis_tkeep_hdr, 
      S_AXIS_TDATA         => m_axis_tdata_hdr, 
      -- Routing informations
      HOST_MAC             => HOST_MAC,     
      HOST_IP              => HOST_IP,      
      HOST_NET_MASK        => HOST_NET_MASK,
      TX_SRC_UDP           => ROCE_TX_SRC_UDP,   
      TX_DST_UDP           => ROCE_TX_DST_UDP,   
      TX_DST_IP            => ROCE_TX_DST_IP,    
      TX_DST_MAC           => ROCE_TX_DST_MAC,   
      ROCE_PKT_LEN         => udp_tx_data_len,
      -- CRC interface
      CRC_DATA             => crc_data,
      CRC_DATA_VALID       => crc_dv,
      CRC_EOP              => crc_eop,
      CRC_MASK             => crc_mask,
      CRC_VALID            => crc_cv,
      CRC_DONE             => crc_done
   );

   crc32_gen_inst : entity work.crc32_gen
   generic map (
      DATA_WIDTH => 512,
      REG_BITMAP => pipe_stages_integer(g_crc_pipe_stage_cnt)     
   )
   port map (
      DI    => crc_data,
      DI_DV => crc_dv,
      EOP   => crc_eop,
      MASK  => crc_mask,
      CLK   => CLK,
      RESET => RESET,
      CRC   => crc_out,
      DO_DV => crc_cv
   );

   roce_append_crc_inst: entity work.roce_append_crc
   generic map(
      g_extra_data_width   => s_extra_data'length
   )
   port map(
      RESET                => RESET,
      CLK                  => CLK,
      -- AXI Stream input
      S_AXIS_TVALID        => m_axis_tvalid_hdr,
      S_AXIS_TREADY        => m_axis_tready_hdr,
      S_AXIS_TLAST         => m_axis_tlast_hdr, 
      S_AXIS_TKEEP         => m_axis_tkeep_hdr, 
      S_AXIS_TDATA         => m_axis_tdata_hdr, 
      S_EXTRA_DATA         => m_extra_data_hdr,
      -- AXI Stream output
      M_AXIS_TVALID        => M_AXIS_TVALID,
      M_AXIS_TREADY        => M_AXIS_TREADY,
      M_AXIS_TLAST         => M_AXIS_TLAST,
      M_AXIS_TKEEP         => M_AXIS_TKEEP,
      M_AXIS_TDATA         => M_AXIS_TDATA,
      M_EXTRA_DATA         => extra_data,
      -- CRC 
      CRC                  => crc_out,
      CRC_VALID            => crc_cv,
      CRC_DONE             => crc_done
   );

   UDP_TX_DST_MAC <= extra_data(47 downto 0); 
   UDP_TX_DST_IP  <= extra_data(79 downto 48); 
   UDP_TX_SRC_UDP <= extra_data(95 downto 80); 
   UDP_TX_DST_UDP <= extra_data(111 downto 96);

end architecture;