--------------------------------------------
-- Multiplexer from FIFOs
--
-- Waits until all i_valid signals are asserted. Then, if i_full == '0', cycles through all inputs and puts them to output.
-- If at that time i_full == '1', all the inputs are discarded.

library ieee;
use ieee.std_logic_1164.all;


entity multiplexer_from_fifos is
generic
	( G_NUM_CHANNELS : natural :=  2;  -- number of channels
		G_DATA_WIDTH   : natural := 32   -- data width of individual packets
	);
port (
	
	clk : in std_logic;
	rst : in std_logic;
	
	-- input side
	i_data  : in std_logic_vector( G_DATA_WIDTH*G_NUM_CHANNELS - 1 downto 0 );
	i_valid : in std_logic_vector( G_NUM_CHANNELS - 1 downto 0 );
	o_rden  : out std_logic_vector( G_NUM_CHANNELS - 1 downto 0 );
	
	-- output side
	o_data  : out std_logic_vector( G_DATA_WIDTH - 1 downto 0 );
	o_valid : out std_logic;
	i_full  : in std_logic

);
end multiplexer_from_fifos;

architecture behavioral of multiplexer_from_fifos is

	subtype t_counter is natural range 0 to G_NUM_CHANNELS;
	signal s_counter : t_counter := 0;

	signal s_all_i_valid : std_logic;
	signal s_drop_data : std_logic;

begin

	assert( G_NUM_CHANNELS > 1 ) report "The number of channels must be higher than 1." severity failure;

	s_all_i_valid <= '1' when i_valid = ( i_valid'range => '1' ) else
									 '0';
	
	
	counter_process : process( clk )
	begin
		if( rising_edge( clk ) ) then
			s_drop_data <= '0';
			if( rst = '1' ) then
				-- reset
				s_counter <= 0;
			elsif( s_counter = 0 and s_all_i_valid = '1' and i_full = '0' and s_drop_data = '0' ) then
				-- counter is stopped, i_data have new data and the following FIFO is ready to receive.
				-- start the counter.
				s_counter <= 1;
			elsif( s_counter = 0 and s_all_i_valid = '1' and i_full = '1' ) then
				-- discard the complete set of data because the following FIFO is full.
				s_drop_data <= '1';
			elsif( s_counter > 0 and s_counter < t_counter'high ) then
				-- the counter is running and is somewhere in between, just increase the value.
				s_counter <= s_counter + 1;
			elsif( s_counter = t_counter'high and s_all_i_valid = '1' and i_full = '0' ) then
			  -- the counter has reached maximum value and there are new data waiting
			  -- start the counter right away
			  s_counter <= 1;
			else
				-- stop the counter
				s_counter <= 0;
			end if;
		end if;
	end process;								 
	
	----------------------------------------------
	-- OUTPUT SIGNALS:
	o_data <= i_data( G_DATA_WIDTH*s_counter - 1 downto G_DATA_WIDTH*s_counter - G_DATA_WIDTH ) when s_counter > 0 and rst = '0' else
					  ( others => '0' );
	o_valid <= i_valid( s_counter - 1 ) when s_counter > 0 and rst = '0' else
						 '0';
	o_rden_gen : for i in 0 to G_NUM_CHANNELS - 1 generate
		o_rden(i) <= '1' when ( s_counter = i + 1 or s_drop_data = '1' ) and i_valid(i) = '1' else
								 '0';
	end generate;
	----------------------------------------------
				
	
end architecture;

