----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 12/11/2019 02:48:23 PM
-- Design Name: 
-- Module Name: roce_append_header_sim - 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;
use IEEE.STD_LOGIC_UNSIGNED.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_sim is
--  Port ( );
end;

architecture Behavioral of roce_to_100g_udp_sim is

   -- convert tkeep to number
   function tkeep2num (vector : std_logic_vector)
      return natural is
      begin
         for i in 0 to vector'length-1 loop
            if vector(i) = '0' then
               return i;
            end if;
         end loop;
         return vector'length;
      end tkeep2num;


   -- convert tkeep to number
   function tkeep_round_to_4_bytes (vector : std_logic_vector)
      return std_logic_vector is
      variable ret_vec : std_logic_vector(vector'range);
      begin
         ret_vec := vector;
         for i in 0 to vector'length-1 loop
            if vector(i) = '0' then
               case i mod 4 is
               when 0 =>   null;
               when 1 =>   ret_vec(i+2 downto i) := (others => '1');
               when 2 =>   ret_vec(i+1 downto i) := (others => '1');
               when others =>   ret_vec(i) := '1';
               end case;
               return ret_vec;
            end if;
         end loop;
         return ret_vec;
      end tkeep_round_to_4_bytes;



   signal clk                    : std_logic := '0';
   signal rst                    : std_logic := '1';
   signal cnt                    : natural range 0 to 16;
   
   signal s_axis_tvalid          : std_logic := '1';
   signal s_axis_tready          : std_logic := '1';
   signal s_axis_tlast           : std_logic := '1';
   signal s_axis_tkeep           : std_logic_vector(63 downto 0) := (others => '0');
   signal s_axis_tdata           : std_logic_vector(511 downto 0) := (others => '0');
   signal s_extra_data           : std_logic_vector(7 downto 0) := x"09";
   signal m_axis_tvalid          : std_logic := '1';
   signal m_axis_tready          : std_logic := '1';
   signal m_axis_tlast           : std_logic := '1';
   signal m_axis_tkeep           : std_logic_vector(63 downto 0) := (others => '0');
   signal m_axis_tdata           : std_logic_vector(511 downto 0) := (others => '0');
   signal m_extra_data           : std_logic_vector(7 downto 0) := x"00";
   
  
   constant LC_ROCE_TX_DEST_QP   : std_logic_vector(23 downto 0) := x"080808";
   constant LC_ROCE_TX_PSN       : std_logic_vector(23 downto 0) := x"090909";
   constant LC_ROCE_TX_SRC_QP    : std_logic_vector(23 downto 0) := x"0b0b0b";
   constant LC_ROCE_TX_Q_KEY     : std_logic_vector(31 downto 0) := x"0a0a0a0a";
   
   constant LC_LAST_CYCLE_TKEEP  : std_logic_vector(63 downto 0) := x"01ffffffffffffff";
   constant LC_DATA_CYCLES       : std_logic_vector(7 downto 0) := x"01";
   constant LC_PAUSE_CYCLES      : std_logic_vector(63 downto 0) := x"0000000000000000";
   constant LC_ROCE_TX_DATA_LEN  : std_logic_vector(15 downto 0) := x"0080";
   
      
   constant LC_DATA              : std_logic_vector(511 downto 0) := (others => '0');  
   constant LC_KEEP              : std_logic_vector(63 downto 0) := (others => '0');  
   
   
   signal roce_tx_data_len       : std_logic_vector(15 downto 0);
   signal last_tkeep             : std_logic_vector(63 downto 0);
   
   
begin

   clk <= not clk after 10ns;
   rst <= '0' after 1000ns;
   last_tkeep <= tkeep_round_to_4_bytes(LC_LAST_CYCLE_TKEEP);
   roce_tx_data_len  <= ("00" & LC_DATA_CYCLES & "000000") - (64 - tkeep2num(last_tkeep));

   axis_generator_inst: entity work.axis_generator
   port map(
      CLK                  => clk,
      RESET                => rst,
      M_AXIS_TVALID        => s_axis_tvalid,
      M_AXIS_TREADY        => s_axis_tready,
      M_AXIS_TLAST         => s_axis_tlast, 
      M_AXIS_TKEEP         => s_axis_tkeep, 
      M_AXIS_TDATA         => s_axis_tdata, 
      -- VIO control
      LAST_CYCLE_TKEEP     => LC_LAST_CYCLE_TKEEP,
      DATA_CYCLES          => LC_DATA_CYCLES,     
      PAUSE_CYCLES         => LC_PAUSE_CYCLES    
   );


--   roce_append_header_inst: entity work.roce_insert_header
--   generic map(
--      g_extra_data_width   => s_extra_data'length
--   )
--   port map(
--      RESET                => rst,
--      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,
--      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         => m_extra_data,
--      -- RoCE header parameters
--      ROCE_TX_DATA_LEN     => LC_ROCE_TX_DATA_LEN,
--      UDP_TX_DATA_LEN      => udp_tx_data_len,
--      ROCE_TX_DEST_QP      => LC_ROCE_TX_DEST_QP,
--      ROCE_TX_PSN          => LC_ROCE_TX_PSN,
--      -- DETH header fields
--      ROCE_TX_Q_KEY        => LC_ROCE_TX_Q_KEY,
--      ROCE_TX_SRC_QP       => LC_ROCE_TX_SRC_QP
--   );


   m_axis_tready <= '1';

   roce_to_100g_udp_inst: entity work.roce_to_100g_udp
   port map(
      RESET                => rst,
      CLK                  => clk,
      
      ------------   COMMON PROPERTIES    ---------
      -- info about host
      HOST_MAC             => x"010101010101",
      HOST_IP              => x"02020202",
      HOST_NET_MASK        => x"03030303",
      
      ------------   UDP INTERFACE    ---------
      -- TX
      M_AXIS_TVALID        =>  m_axis_tvalid,
      M_AXIS_TREADY        =>  m_axis_tready,
      M_AXIS_TLAST         =>  m_axis_tlast, 
      M_AXIS_TDATA         =>  m_axis_tdata, 
      M_AXIS_TKEEP         =>  m_axis_tkeep, 
      -- UDP info towards UDP/IP 
      UDP_TX_SRC_UDP       => open,
      UDP_TX_DST_UDP       => open,
      UDP_TX_DST_IP        => open,
      UDP_TX_DST_MAC       => open,

      ------------   ROCE INTERFACE    ---------
      -- info about target
      ROCE_TX_DST_MAC      => x"040404040404",
      ROCE_TX_DST_IP       => x"05050505",
      ROCE_TX_SRC_UDP      => x"0606",
      ROCE_TX_DST_UDP      => x"0707",
      -- roce stream
      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, 
      ROCE_TX_DATA_LEN     => roce_tx_data_len,
      ROCE_TX_DEST_QP      => LC_ROCE_TX_DEST_QP,
      ROCE_TX_PSN          => LC_ROCE_TX_PSN,
      -- DETH header fields
      ROCE_TX_Q_KEY        => LC_ROCE_TX_Q_KEY, 
      ROCE_TX_SRC_QP       => LC_ROCE_TX_SRC_QP
      
   );

end Behavioral;
