----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 07/23/2019 03:52:40 PM
-- Design Name: 
-- Module Name: axis_generator - 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 arp_generator is
   port (
      CLK                  : in  std_logic;
      RESET                : in  std_logic;
      M_AXIS_TVALID        : out std_logic;
      M_AXIS_TREADY        : in  std_logic;
      M_AXIS_TLAST         : out std_logic;
      M_AXIS_TKEEP         : out std_logic_vector(63 downto 0);
      M_AXIS_TDATA         : out std_logic_vector(511 downto 0);
      ARP_SRC_MAC          : in  std_logic_vector(47 downto 0);
      ARP_SRC_IP           : in  std_logic_vector(31 downto 0);
      ARP_DST_IP           : in  std_logic_vector(31 downto 0)
   );
end;

architecture Behavioral of arp_generator is


   -- Swap bytes form LSB ... MSB to MSB ... LSB
   function swap_bytes (vector   : std_logic_vector)
      return std_logic_vector is
         variable swapped_vector    : std_logic_vector(vector'length - 1 downto 0);
         variable vec               : std_logic_vector(vector'length - 1 downto 0);
      begin 
         vec := vector;
         for i in 0 to vec'length/8 - 1 loop
            swapped_vector(swapped_vector'length - i*8 - 1 downto swapped_vector'length - i*8 - 8) := vec((i+1)*8 - 1 downto i*8);
         end loop;
         return swapped_vector;
      end swap_bytes;

   constant LC_CNT_MAX        : natural := 3;
   constant LC_PAUSE_CNT_MAX  : natural := 1000;
   signal cnt                 : natural range 0 to LC_CNT_MAX := 0;
   signal pause_cnt           : natural range 0 to LC_PAUSE_CNT_MAX := 0;
   
   signal data_cnt            : std_logic_vector(511 downto 0) := (others => '0');
   constant LC_DATA_CNT_MAX   : std_logic_vector(511 downto 0) := (others => '1');
   


   
   -- ARP packet
   constant LC_BROADCAST_MAC        : std_logic_vector(47 downto 0) := x"ffffffffffff"; 
   constant LC_ARP_PACKET_LENGTH    : natural := 42*8;
   constant LC_ARP_ETHER_TYPE       : std_logic_vector(15 downto 0) := x"0806";
   constant LC_ARP_HW_TYPE          : std_logic_vector(15 downto 0) := x"0001";
   constant LC_ARP_IPV4_PROTO_TYPE       : std_logic_vector(15 downto 0) := x"0800";
   constant LC_ARP_HLEN             : std_logic_vector(7 downto 0)  := x"06";
   constant LC_ARP_PLEN             : std_logic_vector(7 downto 0)  := x"04";
   constant LC_ARP_OP_RESPOND       : std_logic_vector(15 downto 0) := x"0002";
   constant LC_ARP_OP_REQUEST       : std_logic_vector(15 downto 0) := x"0001";
   
   signal arp_packet       : std_logic_vector(LC_ARP_PACKET_LENGTH-1 downto 0) := (others => '0');   
   
   constant LC_EMPTY_MAC            : std_logic_vector(47 downto 0) := (others => '0');
   constant LC_EMPTY_IP             : std_logic_vector(31 downto 0) := (others => '0');
begin


   process(CLK)
      begin
         if rising_edge(CLK) then
            if RESET = '1' then
               M_AXIS_TVALID <= '0';
               M_AXIS_TKEEP <= (others => '0');
               M_AXIS_TLAST <= '0';
            else
               M_AXIS_TVALID <= '0';
               M_AXIS_TKEEP <= (others => '0');
               M_AXIS_TLAST <= '0';
            
               if pause_cnt < LC_PAUSE_CNT_MAX then
                  if pause_cnt = LC_PAUSE_CNT_MAX-1 then
                     M_AXIS_TVALID <= '1';
                     M_AXIS_TLAST <= '1';
                     M_AXIS_TKEEP(59 downto 0) <= (others => '1');
                  end if;
                  pause_cnt <= pause_cnt + 1;
               else
                  if M_AXIS_TREADY = '0' then 
                     M_AXIS_TVALID <= '1';
                     M_AXIS_TLAST <= '1';
                     M_AXIS_TKEEP(59 downto 0) <= (others => '1');
                  else
                     pause_cnt <= 0;
                  end if;
                  
--                  if cnt < LC_CNT_MAX-1 then
--                     M_AXIS_TKEEP <= (others => '1');
--                  else
--                     M_AXIS_TKEEP <= x"0000000000000001";
--                     M_AXIS_TLAST <= '1';
--                  end if;
                 
--                  if M_AXIS_TREADY = '1' then
--                     if cnt < LC_CNT_MAX-1 then
--                        cnt <= cnt + 1;
--                     else 
--                        cnt <= 0;
--                        pause_cnt <= 0;
--                     end if;
                     
--                     if cnt < LC_DATA_CNT_MAX then
--                        data_cnt <= data_cnt + 1;
--                     else 
--                        data_cnt <= (others => '0');
--                     end if;                        
--                  end if;  
               end if;
            end if;
         end if;
      end process;

   M_AXIS_TDATA <= data_cnt(511 downto arp_packet'length) & arp_packet;

   arp_packet <= swap_bytes(LC_BROADCAST_MAC & ARP_SRC_MAC & LC_ARP_ETHER_TYPE & LC_ARP_HW_TYPE & LC_ARP_IPV4_PROTO_TYPE
                           & LC_ARP_HLEN & LC_ARP_PLEN & LC_ARP_OP_REQUEST & ARP_SRC_MAC & ARP_SRC_IP & LC_EMPTY_MAC & ARP_DST_IP);

      
--   process(CLK)
--      begin
--         if rising_edge(CLK) then
--            if RESET = '1' then
--            else
--               if cnt < 10 then
--                  cnt <= cnt + 1;
--                  M_AXIS_TVALID <= '0';
--                  M_AXIS_TKEEP <= (others => '0');
--                  M_AXIS_TDATA <= (others => '0');
--                  M_AXIS_TLAST <= '0';
--               else
--                  if M_AXIS_TREADY = '1' then
--                     M_AXIS_TVALID <= '1';
--                     M_AXIS_TKEEP <= x"00000000007fffff";
--                     M_AXIS_TLAST <= '1';
--                     M_AXIS_TDATA <= data;
--                     if cnt < LC_CNT_MAX then
--                        cnt <= cnt + 1;
--                     else
--                        cnt <= 0;
--                     end if;
--                  end if;
--               end if;
--            end if;
--         end if;
--      end process;      

end Behavioral;
