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

library work;
    use work.reg32.all;
    use work.avalon_slave.all;

entity avalon_slave_transitions is
    generic (
        REG_COUNT : natural;
        REG_ACCESS_TYPES : work.reg32.AccessArray
    );
    port (
        address : in std_logic_vector( 3 downto 0 );
        read : in std_logic;
        write : in std_logic;

        current_state : in work.avalon_slave.State;
        next_state : out work.avalon_slave.State;
        reg_index : out integer range  0 to REG_COUNT - 1
    );
end entity avalon_slave_transitions;

architecture rtl of avalon_slave_transitions is

    signal is_access : boolean;
    signal is_read : boolean;
    signal is_write : boolean;
    signal address_index : integer range 0 to 2 ** address'high - 1;
    signal is_valid_reg_index : boolean;
    signal access_type : work.reg32.AccessType;
    signal is_valid_access : boolean;
    signal is_valid_access_type : boolean;
    signal index : integer range  0 to REG_COUNT - 1;

begin

    c_is_access: is_access <= ( read or write ) = '1';
    c_is_read: is_read <= read = '1';
    c_is_write: is_write <= write = '1' and not is_read;

    c_address_index: address_index <= to_integer( unsigned( address ) );

    c_is_valid_reg_index: is_valid_reg_index <= address_index <= ( REG_COUNT - 1 );

    c_index: index <= address_index when is_valid_reg_index else 0;
    c_reg_index: reg_index <= index;

    c_access_type: access_type <= REG_ACCESS_TYPES( index );

    c_is_valid_access_type: is_valid_access_type <= true when
        ( is_read and work.reg32.allows_read( access_type ) ) or
        ( is_write and work.reg32.allows_write( access_type ) )
        else false;

    c_is_valid_access: is_valid_access <= is_access and is_valid_reg_index and
        is_valid_access_type;

    transition : process( all ) is
    begin
        case current_state is
        when SLAVE_IDLE =>
            if ( is_valid_access and is_read ) then
                next_state <= SLAVE_READ;
            elsif ( is_valid_access and is_write ) then
                next_state <= SLAVE_WRITE;
            else
                next_state <= SLAVE_IDLE;
            end if;

        when SLAVE_READ =>
            next_state <= SLAVE_READ_DATA;

        when SLAVE_READ_DATA =>
            if ( is_valid_access and is_read ) then
                next_state <= SLAVE_READ;
            elsif ( is_valid_access and is_write ) then
                next_state <= SLAVE_WRITE;
            else
                next_state <= SLAVE_IDLE;
            end if;

        when SLAVE_WRITE =>
            next_state <= SLAVE_IDLE;
        end case;
    end process transition;

end architecture rtl;
