-- A bridge between the read side of a native FIFO and the Flexelerator's "enable" signal technique


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity fifo_to_enable is
port(

        -- Input from FIFO:
        din : in std_logic_vector;
        rden : out std_logic;
        empty : in std_logic;
        
        -- Output with enable:
        data : out std_logic_vector;
        valid : out std_logic;
        enable : in std_logic;
        
        clk : in std_logic;
        reset : in std_logic
        
        );
        
end entity;

architecture behavioral of fifo_to_enable is

        signal s_rden : std_logic := '0';
        signal s_rden_d : std_logic := '0';
        signal s_valid : std_logic := '0';
        
        subtype t_data is std_logic_vector( din'range );
        type t_data_buffer is array( 1 to 2 ) of t_data;
        signal s_data_buffer : t_data_buffer := ( others => ( others => '0' ) );
        
        signal s_cntr : natural range 0 to 3;
        
begin
        
        
        s_rden <= '1' when empty = '0' and enable = '1' and reset = '0' and s_cntr < 3 else '0';
        rden <= s_rden;
        s_valid <= '1' when s_cntr > 0 and enable = '1' and reset = '0' else '0';
        valid <= s_valid;
        data <= s_data_buffer( 1 );
                
        -- Delayed rden:
        delayed_rden : process( clk ) is
        begin
                if( rising_edge( clk ) ) then
                        s_rden_d <= s_rden;
                end if;
        end process;
        
        data_manipulation : process( clk ) is
        begin
                if( rising_edge( clk ) ) then
                        
                        if( s_valid = '1' ) then
                                s_data_buffer(1) <= s_data_buffer(2);
                                --s_data_buffer(2) <= s_data_buffer(3);
                        end if;
                                        
                        if( reset = '1' ) then
                                s_cntr <= 0;
                        elsif( s_rden_d = '1' and s_valid = '0' ) then
                                s_cntr <= s_cntr + 1;
                                s_data_buffer( s_cntr + 1 ) <= din;
                        elsif( s_rden_d = '1' and s_valid = '1' ) then
                                s_data_buffer( s_cntr ) <= din;
                        elsif( s_rden_d = '0' and s_valid = '1' ) then
                                s_cntr <= s_cntr - 1;
                        end if;
                        
                end if;
        end process;
        
end architecture;