-- ********************************************************************/
-- Actel Corporation Proprietary and Confidential
-- Copyright 2010 Actel 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:	CoreAHBLite Init/Config interface logic
--				for intializing up to 16 clients from AHBLite master(s)
--				instantiates the following modules:
--				COREAHBLITE_SLAVEARBITER, COREAHBLITE_INITCFG_AWRAP
--
-- Revision Information:
-- Date			Description
-- ----			-----------------------------------------
-- 10Feb10		Production Release Version 3.1
--
-- SVN Revision Information:
-- SVN $Revision: 11955 $
-- SVN $Date: 2010-01-30 15:35:13 -0800 (Sat, 30 Jan 2010) $
--
-- Resolved SARs
-- SAR      Date     Who   Description
--
-- Notes:
-- 1. best viewed with tabstops set to "4" (tabs used throughout file)
-- 2. INITADDR[11:0] outputs depend on registered HSIZE[2:0], i.e.:
--		32-bit word write:		INITADDR[11:0] <= {2'b00,HADDR[11:2]};
--		16-bit halfword write:	INITADDR[11:0] <= {1'b0,HADDR[11:1]};
--		8-bit byte write:		INITADDR[11:0] <= HADDR[11:0];
--
-- *********************************************************************/
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity COREAHBLITE_INITCFG is
    generic (
        MODE_CFG             : integer range 0 to 1:= 0;
        M0_INITCFGENABLE     : integer range 0 to (2**16)-1:= 0;
        M1_INITCFGENABLE     : integer range 0 to (2**16)-1:= 0
    );
    port (
        HCLK                 : in std_logic;
        HRESETN              : in std_logic;
        HREADYOUT            : out std_logic;
        CLADDRSEL_M0         : in std_logic_vector(15 downto 0);
        CLADDRSEL_M1         : in std_logic_vector(15 downto 0);
        MADDRSEL             : in std_logic_vector(1 downto 0);
        MDATASEL             : in std_logic_vector(1 downto 0);
        MPREVDATASLAVEREADY  : in std_logic_vector(1 downto 0);
        MADDRREADY           : out std_logic_vector(1 downto 0);
        MDATAREADY           : out std_logic_vector(1 downto 0);
        MHRESP               : out std_logic_vector(1 downto 0);
        M0GATEDHADDR         : in std_logic_vector(31 downto 0);
        M0GATEDHMASTLOCK     : in std_logic;
        M0GATEDHSIZE         : in std_logic_vector(2 downto 0);
        M0GATEDHTRANS        : in std_logic;
        M0GATEDHWRITE        : in std_logic;
        M1GATEDHADDR         : in std_logic_vector(31 downto 0);
        M1GATEDHMASTLOCK     : in std_logic;
        M1GATEDHSIZE         : in std_logic_vector(2 downto 0);
        M1GATEDHTRANS        : in std_logic;
        M1GATEDHWRITE        : in std_logic;
        HWDATA_M0            : in std_logic_vector(31 downto 0);
        HWDATA_M1            : in std_logic_vector(31 downto 0);
        INITDATVAL           : out std_logic_vector(15 downto 0);
        INITDONE             : out std_logic_vector(15 downto 0);
        INITADDR             : out std_logic_vector(11 downto 0);
        INITDATA             : out std_logic_vector(31 downto 0)
    );
end entity COREAHBLITE_INITCFG;

architecture COREAHBLITE_INITCFG_arch of COREAHBLITE_INITCFG is

function or_v (
    v : std_logic_vector) return std_logic is
    variable sl : std_logic := '0';
begin
    for i in v'range loop
       sl := sl or v(i);
    end loop;
    return(sl);
end or_v;

constant CLIENTS              : integer := 16;
constant TRN_IDLE             : std_logic := '0';
constant MASTER_NONE          : std_logic_vector(1 downto 0) := "00";

constant M0_INITCFGENABLE_slv : std_logic_vector(15 downto 0):=
	std_logic_vector(to_unsigned(M0_INITCFGENABLE,16));
constant M1_INITCFGENABLE_slv : std_logic_vector(15 downto 0):=
	std_logic_vector(to_unsigned(M1_INITCFGENABLE,16));

    component COREAHBLITE_INITCFG_AWRAP is
        generic (
            MODE_CFG        : integer range 0 to 1:= 0
        );
        port (
            HCLK                 : in std_logic;
            HRESETN              : in std_logic;
            HADDR                : in std_logic_vector(31 downto 0);
            HSEL                 : in std_logic_vector(15 downto 0);
            HSIZE                : in std_logic_vector(2 downto 0);
            HREADYIN             : in std_logic;
            HTRANS               : in std_logic_vector(1 downto 0);
            HWRITE               : in std_logic;
            HWDATA               : in std_logic_vector(31 downto 0);
            HRDATA               : out std_logic_vector(31 downto 0);
            HRESP                : out std_logic;
            HREADYOUT            : out std_logic;
            INITDATVAL           : out std_logic_vector(15 downto 0);
            INITDONE             : out std_logic_vector(15 downto 0);
            INITADDR             : out std_logic_vector(11 downto 0);
            INITDATA             : out std_logic_vector(31 downto 0)
        );
    end component;
    
    component COREAHBLITE_SLAVEARBITER is
        port (
            HCLK                 : in std_logic;
            HRESETN              : in std_logic;
            MADDRSEL             : in std_logic_vector(1 downto 0);
            ADDRPHEND            : in std_logic;
            M0GATEDHMASTLOCK     : in std_logic;
            M1GATEDHMASTLOCK     : in std_logic;
            MASTERADDRINPROG     : out std_logic_vector(1 downto 0)
        );
    end component;
    
    signal CLADDRSEL_int              : std_logic_vector(15 downto 0);
    signal CLHSEL_int                 : std_logic_vector(CLIENTS-1 downto 0);
    signal HSEL_int                   : std_logic;
    signal HADDR_int                  : std_logic_vector(31 downto 0);
    signal HSIZE_int                  : std_logic_vector(2 downto 0);
    signal HWRITE_int                 : std_logic;
    signal HMASTLOCK_int              : std_logic;
    signal HTRANS_int                 : std_logic_vector(1 downto 0);
    signal HREADYIN_int               : std_logic;
    signal HREADYOUT_int              : std_logic;
    signal masterAddrInProg           : std_logic_vector(1 downto 0);
    signal masterDataInProg           : std_logic_vector(1 downto 0);
    signal addrPhMasterHREADY         : std_logic;
    signal addrPhMasterDataPhComplete : std_logic;
    signal preHTRANS                  : std_logic;
    signal HRESP_int                  : std_logic;
    signal HWDATA_int                 : std_logic_vector(31 downto 0);
    signal CLADDRSEL_M0_gated         : std_logic_vector(15 downto 0);
    signal CLADDRSEL_M1_gated         : std_logic_vector(15 downto 0);
    
    -- Declare intermediate signals for referenced outputs
    signal INITDATVAL_xhdl2           : std_logic_vector(15 downto 0);
    signal INITDONE_xhdl3             : std_logic_vector(15 downto 0);
    signal INITADDR_xhdl0             : std_logic_vector(11 downto 0);
    signal INITDATA_xhdl1             : std_logic_vector(31 downto 0);
begin
    -- Drive referenced outputs
    INITDATVAL <= INITDATVAL_xhdl2;
    INITDONE <= INITDONE_xhdl3;
    INITADDR <= INITADDR_xhdl0;
    INITDATA <= INITDATA_xhdl1;

    init_cfg_client_arbiter : COREAHBLITE_SLAVEARBITER
        port map (
            HCLK              => HCLK,
            HRESETN           => HRESETN,
            MADDRSEL          => MADDRSEL,
            ADDRPHEND         => HREADYOUT_int,
            M0GATEDHMASTLOCK  => M0GATEDHMASTLOCK,
            M1GATEDHMASTLOCK  => M1GATEDHMASTLOCK,
            MASTERADDRINPROG  => masterAddrInProg
        );
    g01 : for i in 0 to CLIENTS-1 generate
        xhdl4 : if (M0_INITCFGENABLE_slv(i) = '0') generate
            CLADDRSEL_M0_gated(i) <= '0';
        end generate;
        xhdl5 : if (not(M0_INITCFGENABLE_slv(i) = '0')) generate
            xhdl6 : if (M0_INITCFGENABLE_slv(i) = '1') generate
                CLADDRSEL_M0_gated(i) <= CLADDRSEL_M0(i);
            end generate;
        end generate;
        xhdl7 : if (M1_INITCFGENABLE_slv(i) = '0') generate
            CLADDRSEL_M1_gated(i) <= '0';
        end generate;
        xhdl8 : if (not(M1_INITCFGENABLE_slv(i) = '0')) generate
            xhdl9 : if (M1_INITCFGENABLE_slv(i) = '1') generate
                CLADDRSEL_M1_gated(i) <= CLADDRSEL_M1(i);
            end generate;
        end generate;
    end generate;
    process (masterAddrInProg, CLADDRSEL_M0_gated, M0GATEDHTRANS, M0GATEDHSIZE, M0GATEDHWRITE, M0GATEDHADDR, M0GATEDHMASTLOCK, MPREVDATASLAVEREADY, CLADDRSEL_M1_gated, M1GATEDHTRANS, M1GATEDHSIZE, M1GATEDHWRITE, M1GATEDHADDR, M1GATEDHMASTLOCK)
    begin
        case masterAddrInProg is
            when "01" =>
                HSEL_int <= '1';
                CLADDRSEL_int <= CLADDRSEL_M0_gated;
                preHTRANS <= M0GATEDHTRANS;
                HSIZE_int <= M0GATEDHSIZE;
                HWRITE_int <= M0GATEDHWRITE;
                HADDR_int <= M0GATEDHADDR;
                HMASTLOCK_int <= M0GATEDHMASTLOCK;
                addrPhMasterHREADY <= MPREVDATASLAVEREADY(0);
            when "10" =>
                HSEL_int <= '1';
                CLADDRSEL_int <= CLADDRSEL_M1_gated;
                preHTRANS <= M1GATEDHTRANS;
                HSIZE_int <= M1GATEDHSIZE;
                HWRITE_int <= M1GATEDHWRITE;
                HADDR_int <= M1GATEDHADDR;
                HMASTLOCK_int <= M1GATEDHMASTLOCK;
                addrPhMasterHREADY <= MPREVDATASLAVEREADY(1);
            when others =>
                HSEL_int <= '0';
                CLADDRSEL_int <= "0000000000000000";
                preHTRANS <= TRN_IDLE;
                HSIZE_int <= "000";
                HWRITE_int <= '0';
                HADDR_int <= "00000000000000000000000000000000";
                HMASTLOCK_int <= '0';
                addrPhMasterHREADY <= '1';
        end case;
    end process;
    
    CLHSEL_int(15 downto 0) <= HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int & HSEL_int and CLADDRSEL_int(15 downto 0);
    addrPhMasterDataPhComplete <= or_v((masterAddrInProg and MDATASEL));
    HTRANS_int(1) <= preHTRANS and (addrPhMasterHREADY or addrPhMasterDataPhComplete);
    HREADYIN_int <= HREADYOUT_int;
    HREADYOUT <= HREADYOUT_int;
    process (HCLK, HRESETN)
    begin
        if ((not(HRESETN)) = '1') then
            masterDataInProg <= MASTER_NONE;
        elsif (HCLK'event and HCLK = '1') then
            if (HREADYIN_int = '1') then
                masterDataInProg <= masterAddrInProg;
            end if;
        end if;
    end process;
    
    process (masterDataInProg, HWDATA_M0, HWDATA_M1)
    begin
        case masterDataInProg is
            when "01" =>
                HWDATA_int <= HWDATA_M0;
            when "10" =>
                HWDATA_int <= HWDATA_M1;
            when others =>
                HWDATA_int <= "00000000000000000000000000000000";
        end case;
    end process;
    
    process (masterDataInProg, HRESP_int)
    begin
        MHRESP <= "00";
        case masterDataInProg is
            when "01" =>
                MHRESP(0) <= HRESP_int;
            when "10" =>
                MHRESP(1) <= HRESP_int;
            when others =>
                MHRESP <= "00";
        end case;
    end process;
    
    process (MADDRSEL, masterAddrInProg, HREADYOUT_int)
    begin
        if ((MADDRSEL(0) and not(masterAddrInProg(0))) = '1') then
            MADDRREADY(0) <= '0';
        elsif ((MADDRSEL(0) and masterAddrInProg(0)) = '1') then
            MADDRREADY(0) <= HREADYOUT_int;
        else
            MADDRREADY(0) <= '1';
        end if;
    end process;
    
    process (MADDRSEL, masterAddrInProg, HREADYOUT_int)
    begin
        if ((MADDRSEL(1) and not(masterAddrInProg(1))) = '1') then
            MADDRREADY(1) <= '0';
        elsif ((MADDRSEL(1) and masterAddrInProg(1)) = '1') then
            MADDRREADY(1) <= HREADYOUT_int;
        else
            MADDRREADY(1) <= '1';
        end if;
    end process;
    
    process (MDATASEL, masterDataInProg, HREADYOUT_int)
    begin
        if ((MDATASEL(0) and not(masterDataInProg(0))) = '1') then
            MDATAREADY(0) <= '0';
        elsif ((MDATASEL(0) and masterDataInProg(0)) = '1') then
            MDATAREADY(0) <= HREADYOUT_int;
        else
            MDATAREADY(0) <= '1';
        end if;
    end process;
    
    process (MDATASEL, masterDataInProg, HREADYOUT_int)
    begin
        if ((MDATASEL(1) and not(masterDataInProg(1))) = '1') then
            MDATAREADY(1) <= '0';
        elsif ((MDATASEL(1) and masterDataInProg(1)) = '1') then
            MDATAREADY(1) <= HREADYOUT_int;
        else
            MDATAREADY(1) <= '1';
        end if;
    end process;
    
    HTRANS_int(0) <= '0';
    
    
    init_cfg_awrap : COREAHBLITE_INITCFG_AWRAP
        generic map (
            MODE_CFG  => MODE_CFG
        )
        port map (
            HCLK        => HCLK,
            HRESETN     => HRESETN,
            HADDR       => HADDR_int,
            HSEL        => CLHSEL_int,
            HSIZE       => HSIZE_int,
            HREADYIN    => HREADYIN_int,
            HTRANS      => HTRANS_int,
            HWRITE      => HWRITE_int,
            HWDATA      => HWDATA_int,
            HRDATA      => open,
            HRESP       => HRESP_int,
            HREADYOUT   => HREADYOUT_int,
            INITDATVAL  => INITDATVAL_xhdl2,
            INITDONE    => INITDONE_xhdl3,
            INITADDR    => INITADDR_xhdl0,
            INITDATA    => INITDATA_xhdl1
        );
    
end architecture COREAHBLITE_INITCFG_arch;
