----------------------------------------------------------------------------------
-- Company: APC
-- Engineer: CC
-- 
-- Create Date:    11:49:52 28/02/2017
-- Design Name: 
-- Module Name:    fifo_mux - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: gather data to be sent: TDC, SPI
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity fifo_mux is
	generic(
		 -- Transmission timeout (in clk_sys_i cycles), after which the contents
		 -- of TX buffer are sent regardless of the amount of data that is currently
		 -- stored in the buffer, so that data in the buffer does not get stuck.
		 g_tx_timeout : natural := 655000 --	~10ms
		 );

    Port ( clk_i 					: in  STD_LOGIC;
           rst_i 					: in  STD_LOGIC;
			  fifo_mux_i			: in  STD_LOGIC;
           wr_en_i				: in  STD_LOGIC;
           rd_en_i				: in  STD_LOGIC;
           almost_full1_i		: in  STD_LOGIC;
           almost_full2_i		: in 	STD_LOGIC;
			  almost_empty1_i		: in  STD_LOGIC;
           almost_empty2_i		: in 	STD_LOGIC;
			  empty1_i				: in  STD_LOGIC;
			  empty2_i				: in  STD_LOGIC;
			  data_cnt1_i			: in  STD_LOGIC_VECTOR(5 downto 0);
			  data_cnt2_i			: in  STD_LOGIC_VECTOR(5 downto 0);
           wr_data_i				: in  STD_LOGIC_VECTOR(95 downto 0);
           rd_data1_i			: in  STD_LOGIC_VECTOR(95 downto 0);
           rd_data2_i			: in  STD_LOGIC_VECTOR(95 downto 0);
           wr_en1_o				: out STD_LOGIC;
           rd_en1_o				: out STD_LOGIC;
           wr_en2_o				: out STD_LOGIC;
           rd_en2_o				: out STD_LOGIC;
			  almost_full_o		: out STD_LOGIC;
			  almost_empty_o		: out STD_LOGIC;
			  tx_timeout_hit_o	: out STD_LOGIC;
			  data_cnt_o			: out STD_LOGIC_VECTOR(5 downto 0);
			  wr_data1_o			: out STD_LOGIC_VECTOR(95 downto 0);
			  wr_data2_o			: out STD_LOGIC_VECTOR(95 downto 0);
			  rd_data_o				: out STD_LOGIC_VECTOR(95 downto 0)
			  --TRIG0 : out std_logic_vector(31 downto 0)
			 );
end fifo_mux;

architecture Behavioral of fifo_mux is

	component time_out_gen is
	generic(
		 g_timeout_val : natural := 65500 --	~1ms @ 62.5MHz
		 );
    Port (
		clk_i				: in std_logic;
		rst_i				: in std_logic;
		timeout_en_i 	: in std_logic;
		timeout_hit_o	: out std_logic
	 );
	end component;

	type STATE_TYPE is (WRITE_FIFO1, WRITE_FIFO2, WAIT4EMPTY1, WAIT4EMPTY2);	
	signal current_state	: STATE_TYPE;
	-- time out
	signal timeout_hit   : std_logic := '0';
	signal timeout_en  : std_logic := '0';
	
begin

	---- time out generator to flush FIFOs ---	
	U_timeout_gen : time_out_gen 
	generic map (g_timeout_val => g_tx_timeout)		
    Port map (
		clk_i				=> clk_i,
     	rst_i 		 	=> rst_i,
		timeout_en_i 	=> timeout_en,
		timeout_hit_o	=> timeout_hit
	 );

--almost_full1_o 	<= almost_full1_i;
--almost_full2_o 	<= almost_full2_i;

	tx_timeout_hit_o <= timeout_hit; 	
--	timeout_hit 	  <= '0';
	
process (clk_i)
	begin
	if rising_edge(clk_i)then
		if (rst_i = '1') then		
			-- write FIFO1
			rd_en1_o    	<= '0';
			rd_en2_o			<= '0';				--rd_en_i;			
			rd_data_o 		<= rd_data2_i;
			wr_en1_o			<= wr_en_i;
			wr_en2_o    	<= '0';	
			wr_data1_o 		<= wr_data_i;
			wr_data2_o 		<= (others => 'X');
			almost_full_o 	<= almost_full1_i;
			almost_empty_o <= almost_empty1_i;
			data_cnt_o		<= data_cnt1_i;
			current_state	<=	WRITE_FIFO1;	
		
		else
			case current_state is
			
				when WRITE_FIFO1 =>	
					rd_en1_o    	<= '0';
					rd_en2_o			<= '0';		--rd_en_i;	
					rd_data_o 		<= rd_data2_i;
					wr_en1_o			<= wr_en_i;
					wr_en2_o    	<= '0';	
					wr_data1_o 		<= wr_data_i;
					wr_data2_o 		<= (others => 'X');	
					almost_full_o 	<= almost_full1_i;		
					almost_empty_o <= almost_empty1_i;
					data_cnt_o		<= data_cnt1_i;
--					timeout_en		<= '1';
					if (almost_full1_i = '1') or (timeout_hit = '1') then
						rd_en1_o			<= rd_en_i;
						rd_en2_o    	<= '0';
						rd_data_o 		<= rd_data1_i;
						wr_en1_o   	 	<= '0';	
						wr_en2_o			<= wr_en_i;
						wr_data2_o 		<= wr_data_i;
						wr_data1_o 		<= (others => 'X');
						timeout_en 		<= '0';
						current_state	<= WAIT4EMPTY1;
					else 	
						timeout_en		<= '1';
						current_state	<=	WRITE_FIFO1;
					end if;	
					
				when WRITE_FIFO2 =>	
					rd_en1_o			<= '0';	--rd_en_i;
					rd_en2_o    	<= '0';
					rd_data_o 		<= rd_data1_i;
					wr_en2_o			<= wr_en_i;
					wr_en1_o   	 	<= '0';	
					wr_data2_o 		<= wr_data_i;
					wr_data1_o 		<= (others => 'X');
					almost_full_o 	<= almost_full2_i;		
					almost_empty_o <= almost_empty2_i;
					data_cnt_o		<= data_cnt2_i;	
--					timeout_en		<= '1';
					if (almost_full2_i = '1') or (timeout_hit = '1') then
						rd_en2_o			<= rd_en_i;
						rd_en1_o    	<= '0';
						rd_data_o 		<= rd_data2_i;
						wr_en1_o			<= wr_en_i;
						wr_en2_o    	<= '0';	
						wr_data1_o 		<= wr_data_i;
						wr_data2_o 		<= (others => 'X');	
						timeout_en		<= '0';
						current_state	<= WAIT4EMPTY2;
					else 	
						timeout_en		<= '1';
						current_state	<=	WRITE_FIFO2;
					end if;	

				when WAIT4EMPTY1 =>	
					rd_en1_o			<= rd_en_i;
					rd_en2_o    	<= '0';
					rd_data_o 		<= rd_data1_i;
					wr_en2_o			<= wr_en_i;
					wr_en1_o   	 	<= '0';	
					wr_data2_o 		<= wr_data_i;
					wr_data1_o 		<= (others => 'X');
					almost_full_o 	<= almost_full1_i;
					almost_empty_o <= almost_empty1_i;
					data_cnt_o		<= data_cnt1_i;
					timeout_en		<= '0';
					if  fifo_mux_i = '1' then -- ready to send FIFO2 data 
						rd_en1_o			<= '0';		--rd_en_i;
						rd_en2_o    	<= '0';
						rd_data_o 		<= (others => 'X');		--rd_data1_i;
						wr_en2_o			<= wr_en_i;
						wr_en1_o   	 	<= '0';	
						wr_data2_o 		<= wr_data_i;
						wr_data1_o 		<= (others => 'X');
						almost_full_o 	<= almost_full2_i;		
						almost_empty_o <= almost_empty2_i;
						data_cnt_o		<= data_cnt2_i;	
						current_state	<=	WRITE_FIFO2;	
					else 
						current_state	<= WAIT4EMPTY1;
					end if;	

				when WAIT4EMPTY2 =>	
					rd_en2_o			<= rd_en_i;
					rd_en1_o    	<= '0';
					rd_data_o 		<= rd_data2_i;
					wr_en1_o			<= wr_en_i;
					wr_en2_o    	<= '0';	
					wr_data1_o 		<= wr_data_i;
					wr_data2_o 		<= (others => 'X');	
					almost_full_o 	<= almost_full2_i;
					almost_empty_o <= almost_empty2_i;
					data_cnt_o		<= data_cnt2_i;
					timeout_en		<= '0';
					if  fifo_mux_i = '1' then -- ready to send FIFO1 data 
						rd_en1_o    	<= '0';
						rd_en2_o			<= '0';		--rd_en_i;	
						rd_data_o 		<= (others => 'X'); --rd_data2_i;
						wr_en1_o			<= wr_en_i;
						wr_en2_o    	<= '0';	
						wr_data1_o 		<= wr_data_i;
						wr_data2_o 		<= (others => 'X');	
						almost_full_o 	<= almost_full1_i;		
						almost_empty_o <= almost_empty1_i;
						data_cnt_o		<= data_cnt1_i;
						current_state	<=	WRITE_FIFO1;	
					else 
						current_state	<= WAIT4EMPTY2;	
					end if;
					
				when others => 
					current_state	<=	WRITE_FIFO1;			
					
			end case;
		end if;
	end if;
end process;

		
end Behavioral;


