-------------------------------------------------------------------------------
--
-- Project name: UDP_100G
--
-- (C) Copyright 2019 DFC Design, s.r.o., Brno, Czech Republic
-- Author: Jakub Hadamek (j.hadamek@dfcdesign.cz)
--
-------------------------------------------------------------------------------
--
-- This file is part of UDP_100G IP core
-- 
-------------------------------------------------------------------------------



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;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


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

entity axis_register is
   generic (
      g_extra_data_width   : natural
   );
   port (
      RESET                : in  std_logic;
      CLK                  : in  std_logic;
      -- AXI Stream input
      S_AXIS_TVALID        : in  std_logic;
      S_AXIS_TREADY        : out std_logic;
      S_AXIS_TLAST         : in  std_logic;
      S_AXIS_TUSER         : in  std_logic;
      S_AXIS_TKEEP         : in  std_logic_vector(63 downto 0);
      S_AXIS_TDATA         : in  std_logic_vector(511 downto 0);
      S_EXTRA_DATA         : in  std_logic_vector(g_extra_data_width - 1 downto 0) := (others => '0');
      -- AXI Stream output
      M_AXIS_TVALID        : out std_logic;
      M_AXIS_TREADY        : in  std_logic;
      M_AXIS_TLAST         : out std_logic;
      M_AXIS_TUSER         : out std_logic;
      M_AXIS_TKEEP         : out std_logic_vector(63 downto 0);
      M_AXIS_TDATA         : out std_logic_vector(511 downto 0);
      M_EXTRA_DATA         : out std_logic_vector(g_extra_data_width - 1 downto 0)
   );
end;

architecture Behavioral of axis_register is
   
   signal m_axis_tvalid_i  : std_logic;             

   signal s_axis_tvalid_d  : std_logic;                    
   signal s_axis_tready_d  : std_logic;                    
   signal s_axis_tlast_d   : std_logic;     
   signal s_axis_tuser_d   : std_logic;                    
   signal s_axis_tkeep_d   : std_logic_vector(63 downto 0);
   signal s_axis_tdata_d   : std_logic_vector(511 downto 0);
   
   signal extra_data_d     : std_logic_vector(S_EXTRA_DATA'length-1 downto 0) := (others => '0');
   
begin

   
   process(CLK) 
      begin 
         if rising_edge(CLK) then
            if RESET = '1' then
               m_axis_tvalid_i <= '0';
               M_AXIS_TLAST    <= '0';
               M_AXIS_TKEEP    <= (others => '0');
               M_AXIS_TDATA    <= (others => '0');
               M_EXTRA_DATA    <= (others => '0');
               s_axis_tvalid_d <= '0';            
               s_axis_tlast_d  <= '0';            
               s_axis_tkeep_d  <= (others => '0');
               s_axis_tdata_d  <= (others => '0');
               extra_data_d <= (others => '0');
            else     
               if M_AXIS_TREADY = '1' or m_axis_tvalid_i = '0' then
                  -- One cycle delayed data
                  s_axis_tvalid_d <= S_AXIS_TVALID;
                  s_axis_tlast_d <= S_AXIS_TLAST;
                  s_axis_tkeep_d <= S_AXIS_TKEEP;
                  s_axis_tdata_d <= S_AXIS_TDATA;
                  s_axis_tuser_d <= S_AXIS_TUSER;
                  extra_data_d <= S_EXTRA_DATA;
                  -- output data
                  m_axis_tvalid_i <= s_axis_tvalid_d;
                  M_AXIS_TLAST    <= s_axis_tlast_d;  
                  M_AXIS_TKEEP    <= s_axis_tkeep_d;  
                  M_AXIS_TDATA    <= s_axis_tdata_d; 
                  M_AXIS_TUSER    <= s_axis_tuser_d; 
                  M_EXTRA_DATA    <= extra_data_d;
               end if;
            end if;
         end if;
      end process;
      
   M_AXIS_TVALID <= m_axis_tvalid_i;   
   S_AXIS_TREADY <= (not m_axis_tvalid_i or M_AXIS_TREADY) and not RESET;
      
   
end;
