-- Provides information about the firmware.
-- This block is written as a generic memory that sends data based on the requested address.
--
-- Generally this block is connected to the 'control' interface in the userlogiccmp_forxilly block and the user interacts with it using the 'control' files.
-- The information_data package should contain several mandatory constants as well as the contents of the memory. Generally, the first four 32-bit-tuples are occupied by a unique GUID that identifies the firmware.

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

library utilities;
use utilities.utilities.all;

library information;
use information.information_data.all;

----------------------------------------------------------------
-- NOTE: No range check on the i_data requested address. 

entity information_block is
	
port (

	clk : in std_logic;
	rst : in std_logic;
	
	-- Input side:
	i_data   : in  std_logic_vector( 31 downto 0 );
	i_valid  : in  std_logic;
	o_enable : out std_logic;
	
	-- Output side:
	o_data   : out std_logic_vector( 31 downto 0 );
	o_valid  : out std_logic;
	i_enable : in  std_logic
		
	);
		
end entity;

architecture rtl of information_block is

	-- data in buffer
	signal buffer_valid : std_logic;
	signal buffer_data : std_logic_vector( o_data'range );
	-- data from the memory
	signal mem_valid : std_logic;
	signal mem_data : std_logic_vector( o_data'range );
	
	signal oo_valid : std_logic;
	
	signal addr : unsigned( log2( C_INFO_NUMDATA ) - 1 downto 0 );
	--signal i_valid_d : std_logic;

	constant C_RESVAL : std_logic_vector( C_INFO_BITWIDTH -1 downto 0 ) := ( others => '0' );

	-- Memory content:
	subtype t_memdata is t_twodim_stdlogic( C_INFO_NUMDATA - 1 downto 0, C_INFO_BITWIDTH - 1 downto 0 );
	constant C_MEMDATA : t_memdata := stdlogicvector_to_twodim( C_INFO_DATA, C_INFO_NUMDATA, C_INFO_BITWIDTH );

begin

	o_enable <= i_enable;
	o_valid <= oo_valid and i_enable;
	
	o_data <= buffer_data when buffer_valid = '1' else
						mem_data;
	oo_valid <= buffer_valid when buffer_valid = '1' else
							mem_valid;
	
	valid_handling: process( clk )
	begin
		if( rising_edge(clk) ) then
			mem_valid <= i_valid;
		end if;
	end process;
	
	addr <= unsigned( i_data( addr'range ) );
	
	-- inferred bram:
	inferred_bram_inst : entity utilities.inferred_bram
		generic map( 
			G_RAM_CONTENT => C_MEMDATA,
			G_WIDTH => C_INFO_BITWIDTH,
			G_SIZE => C_INFO_NUMDATA,
			G_RESVAL_A => C_RESVAL
		)
		port map(
			i_clka => clk,
			i_ena => '1',
			i_wea => '0',
			i_resa => '0',
			i_addra => addr,
			i_dataa => ( C_INFO_BITWIDTH - 1 downto 0 => '0' ),
			o_dataa => mem_data
		);
	
	outp_data : process( clk )
	begin
		if( rising_edge(clk) ) then
			if( rst = '1' ) then
				buffer_valid <= '0';
			else
			
				if( i_enable = '1' ) then
					buffer_valid <= '0';
				elsif( buffer_valid = '0' ) then
					buffer_valid <= mem_valid;
					buffer_data <= mem_data;
				end if;
					
			end if;
		end if;
	end process;
	
						
end architecture;
