----------------------------------------------------------------------------------
-- 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 axis_gen is
   generic  (
      g_stream_width       : natural range 0 to 1024 := 512
   );
   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(g_stream_width/8-1 downto 0);
      M_AXIS_TDATA         : out std_logic_vector(g_stream_width-1 downto 0);
      -- VIO control
      LAST_CYCLE_TKEEP     : in  std_logic_vector(g_stream_width/8-1 downto 0);
      DATA_CYCLES          : in  std_logic_vector(7 downto 0);
      PAUSE_CYCLES         : in  std_logic_vector(63 downto 0);
      CONTINUOUS           : in  std_logic
   );
end ;

architecture Behavioral of axis_gen is
--   constant LC_CNT_MAX        : natural := 5;

   constant LC_PAUSE_CNT_MAX  : natural := 5;
   signal pause_cnt           : std_logic_vector(PAUSE_CYCLES'range) := (others => '0');
   signal cnt                 : natural range 0 to 2**DATA_CYCLES'length := 0;
   
   signal data_cnt            : std_logic_vector(15 downto 0) := (others => '0');
   signal pkt_cnt             : std_logic_vector(63 downto 0) := (others => '0');
   constant LC_DATA_CNT_MAX   : std_logic_vector(15 downto 0) := x"ffff";
   constant LC_CONST_DATA     : std_logic_vector(63 downto 0) := x"dfc3dfc2dfc1dfc0";
   
   signal last                : std_logic := '0';
   signal valid                : std_logic := '0';
begin
   
   
   M_AXIS_TVALID <= valid;
   M_AXIS_TKEEP <= (others => '1') when cnt < DATA_CYCLES-1 or CONTINUOUS = '1' else LAST_CYCLE_TKEEP;
   
--   data_gen: for i in 0 to M_AXIS_TDATA'length/data_cnt'length-1 generate
----      M_AXIS_TDATA((i+1)*data_cnt'length-1 downto i*data_cnt'length) <= pkt_cnt;
--      M_AXIS_TDATA((i+1)*data_cnt'length-1 downto i*data_cnt'length) <= data_cnt when i = 0 else (others => '0');      
--   end generate;
   
   M_AXIS_TLAST <= last;
   last <= '1' when cnt = DATA_CYCLES-1 and CONTINUOUS = '0' else '0';

--   data_gen: for i in 0 to M_AXIS_TDATA'length/32-1 generate
--      M_AXIS_TDATA((i+1)*data_cnt'length-1 downto i*data_cnt'length) <= data_cnt + i;      
--      M_AXIS_TDATA((i+1+8)*data_cnt'length-1 downto (i+8)*data_cnt'length) <= data_cnt + i;    
--   end generate;


   data_gen: for i in 0 to M_AXIS_TDATA'length/16-1 generate
      M_AXIS_TDATA((i+1)*data_cnt'length-1 downto i*data_cnt'length) <= data_cnt when i = 0 else (others => '0');      
   end generate;
   
   
   process(CLK)
      begin
         if rising_edge(CLK) then
            if RESET = '1' then
               valid <= '0';
               cnt <= 0;
               data_cnt <= (others => '0');
               pause_cnt <= (others => '0');
               pkt_cnt <= (others => '0');
            else
            
               if pause_cnt < PAUSE_CYCLES and CONTINUOUS = '0' then
                  pause_cnt <= pause_cnt + 1;
                  valid <= '0';
               else
               
                  -- always valid
                  valid <= '1';
                  
                  -- change data and other signals when ready
                  if M_AXIS_TREADY = '1' and valid = '1' then 
                  
                     if data_cnt < LC_DATA_CNT_MAX then
                        data_cnt <= data_cnt + 1;
                     else 
                        data_cnt <= (others => '0');
                     end if;   
                     
                     if CONTINUOUS = '0' then
                        if cnt < DATA_CYCLES-1 then
                           cnt <= cnt + 1;
                        else
                           valid <= '0';
                           cnt <= 0;
                           pause_cnt <= (others => '0');
                        end if;

                        if last = '1' then
                           if pkt_cnt < LC_DATA_CNT_MAX then
                              pkt_cnt <= pkt_cnt + 1;
                           else 
                              pkt_cnt <= (others => '0');
                           end if;  
                        end if;
                     end if;
                  end if;
               end if;
            end if;
         end if;
      end process;    

end;
