-- ********************************************************************/
-- Microsemi Corporation Proprietary and Confidential
-- Copyright 2011 Microsemi Corporation.  All rights reserved.
--
-- ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
-- ACCORDANCE WITH THE ACTEL LICENSE AGREEMENT AND MUST BE APPROVED
-- IN ADVANCE IN WRITING.
--
-- Description:	Implements indirect address registers for CoreAPB3
--
--
-- SVN Revision Information:
-- SVN $Revision: 16159 $
-- SVN $Date: 2012-01-13 12:15:19 -0800 (Fri, 13 Jan 2012) $
--
--
-- Notes:
-- 1. best viewed with tabstops set to "4" (tabs used throughout file)
--
-- *********************************************************************/
library ieee;
use ieee.std_logic_1164.all;

entity coreapb3_iaddr_reg is
    generic (
        APB_DWIDTH      : integer range 8 to 32 := 32
    );
    port (
        PCLK            : in  std_logic;
        PRESETN         : in  std_logic;
        PENABLE         : in  std_logic;
        PSEL            : in  std_logic;
        PADDR           : in  std_logic_vector(31 downto 0);
        PWRITE          : in  std_logic;
        PWDATA          : in  std_logic_vector(APB_DWIDTH-1 downto 0);
        PRDATA          : out std_logic_vector(APB_DWIDTH-1 downto 0);
        --PREADY          : out std_logic;
        --PSLVERR         : out std_logic;
        IADDR_REG       : out std_logic_vector(31 downto 0)
    );
end entity coreapb3_iaddr_reg;

architecture rtl of coreapb3_iaddr_reg is

    signal IADDR_REG_i      : std_logic_vector(31 downto 0);

begin
    -----------------------------------------------------------------
    process (PRESETN, PCLK)
    begin
        if (PRESETN = '0') then
            IADDR_REG_i <= (others => '0');
        elsif (PCLK'event and PCLK = '1') then
            if (PSEL = '1' and PENABLE = '1' and PWRITE = '1') then
                if (APB_DWIDTH = 32) then
                    IADDR_REG_i <= PWDATA;
                end if;
                if (APB_DWIDTH = 16) then
                    case PADDR(1) is
                        when '0' => IADDR_REG_i(15 downto  0) <= PWDATA(15 downto 0);
                        when '1' => IADDR_REG_i(31 downto 16) <= PWDATA(15 downto 0);
                        when others => null;
                    end case;
                end if;
                if (APB_DWIDTH =  8) then
                    case PADDR(1 downto 0) is
                        when "00" => IADDR_REG_i( 7 downto  0) <= PWDATA(7 downto 0);
                        when "01" => IADDR_REG_i(15 downto  8) <= PWDATA(7 downto 0);
                        when "10" => IADDR_REG_i(23 downto 16) <= PWDATA(7 downto 0);
                        when "11" => IADDR_REG_i(31 downto 24) <= PWDATA(7 downto 0);
                        when others => null;
                    end case;
                end if;
            end if;
        end if;
    end process;

    IADDR_REG <= IADDR_REG_i;

    process (IADDR_REG_i, PADDR)
    begin
        if (APB_DWIDTH = 32) then
            PRDATA <= IADDR_REG_i;
        end if;
        if (APB_DWIDTH = 16) then
            case PADDR(1) is
                when '0' => PRDATA(15 downto 0) <= IADDR_REG_i(15 downto  0);
                when '1' => PRDATA(15 downto 0) <= IADDR_REG_i(31 downto 16);
                when others => null;
            end case;
        end if;
        if (APB_DWIDTH =  8) then
            case PADDR(1 downto 0) is
                when "00" => PRDATA(7 downto 0) <= IADDR_REG_i( 7 downto  0);
                when "01" => PRDATA(7 downto 0) <= IADDR_REG_i(15 downto  8);
                when "10" => PRDATA(7 downto 0) <= IADDR_REG_i(23 downto 16);
                when "11" => PRDATA(7 downto 0) <= IADDR_REG_i(31 downto 24);
                when others => null;
            end case;
        end if;
    end process;

end architecture rtl;
