----------------------------------------------------------------------------------
-- Company: APC
-- Engineer: CC
-- 
-- Create Date:    11:49:52 09/06/2016 
-- Design Name: 
-- Module Name:    Trigger_throttlerv4 - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: Stop writing Tx data in FIFO if time difference between first and last event
--               of a bunch is too small (default 200us) => too high trigger rate
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Revision 0.02 - use UDP command to set countdown value (throttle_val_i)
-- Revision 0.03 - throttler default is OFF, cntdown_val = x"FFFF"
-- Additional Comments: v2 use countdown instead of time difference
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity trigger_throttler is

    Port ( clk_i 					: in  STD_LOGIC;
           rst_i 					: in  STD_LOGIC;
			  throttle_val_i		: in  STD_LOGIC_VECTOR(15 downto 0);
			  set_throttle_val_i	: in  STD_LOGIC;			  
			  tx_almost_empty_i 	: in  STD_LOGIC;
           tx_almost_full_i 	: in  STD_LOGIC;
           stop_wr_o 			: out STD_LOGIC;
			  TRIG0 : out std_logic_vector(31 downto 0)
			 );
end trigger_throttler;

architecture Behavioral of trigger_throttler is

--	constant c_cntdown_val    : natural := 12499;	-- 200us with clk_sys (62.5MHz)

	type STATE_TYPE is (IDLE, COUNTDOWN, STOP_TRIG);
	
	signal cntdown_val    	: unsigned(15 downto 0) := x"FFFF";		--default is OFF    -- x"30D3" => 200us with clk_sys (62.5MHz)
	signal current_state		: STATE_TYPE;
	signal cntdown				: unsigned(15 downto 0);
	signal stop_trigger, throttler_en 		: std_logic;
	
	
begin

--	set countdown value process
set_cntdown_val_proc : process (clk_i)
	begin
	if rising_edge(clk_i)  then
		if (rst_i = '1') then
			cntdown_val	<= x"FFFF";
            throttler_en <= '0';    
		elsif (set_throttle_val_i = '1') then 
            if  throttle_val_i = x"FFFF" then
                throttler_en <= '0';
            else
			    cntdown_val	<= unsigned(throttle_val_i);
                throttler_en <= '1';
            end if;
		end if;
	end if;
  end process;
		
	process (clk_i)
	begin
	if rising_edge(clk_i)then
		if (rst_i = '1') then
			stop_trigger 	<= '0';
			cntdown		 	<= cntdown_val;	
			current_state	<= IDLE;	

		else
			case current_state is
				when IDLE =>
					stop_trigger	<= '0';
					cntdown		 	<= cntdown_val;	
                    if throttler_en = '0' then
                        current_state	<=	IDLE;
                    else
					    if tx_almost_empty_i = '1' then		-- first timetag of bunch
						    current_state	<= COUNTDOWN;		
					    else
						    current_state	<=	IDLE;
					    end if;
				    end if;

				when COUNTDOWN =>
					stop_trigger	<= '0';
					cntdown		 	<= cntdown -1;
					if cntdown	= 0 then 	        --keep writing in FIFO if time difference between first and last trigger of bunch > 200us(default)
						cntdown		 	<= cntdown_val;
						current_state	<=	IDLE;
					elsif tx_almost_full_i = '1' then	--last timetag of bunch before 200us(default)
						current_state	<= STOP_TRIG;	
						stop_trigger	<= '1';						
					else
						current_state	<=	COUNTDOWN ;
					end if;	

				when STOP_TRIG =>			
					if cntdown	> 0 then
						stop_trigger	<= '1';			-- wait cntdown is 0 before writing in FIFO
						cntdown		 	<= cntdown -1;
						current_state	<= STOP_TRIG;				
					else 								
						stop_trigger 	<= '0';
						cntdown		 	<= cntdown_val;
						current_state	<=	IDLE;
					end if;
				
				when others => 
					current_state	<=	IDLE;			
			end case;
			end if; 
	end if;
	end process;
	
	stop_wr_o <= stop_trigger;
	
	--debug
	TRIG0(31 downto 17)	<= std_logic_vector(cntdown(14 downto 0)); --
	TRIG0(16)				<= tx_almost_empty_i;
	TRIG0(15 downto 2)	<= std_logic_vector(cntdown_val(13 downto 0));
	TRIG0(1)					<= tx_almost_full_i;
	TRIG0(0)					<= stop_trigger;
	
	
		
end Behavioral;

