-- ********************************************************************/
-- 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 AHBLite wrapper logic
--				for intializing up to 16 clients from AHBLite master(s)
--
-- 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];
--
-- TODO: implement similar logic to slave stage and slave arbiter blocks
-- *********************************************************************/
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity 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 entity COREAHBLITE_INITCFG_AWRAP;

architecture COREAHBLITE_INITCFG_AWRAP_arch of COREAHBLITE_INITCFG_AWRAP 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;

function and_v (
   v : std_logic_vector) return std_logic is
   variable sl : std_logic := '1';
begin
   for i in v'range loop
      sl := sl and v(i);
   end loop;
   return(sl);
end and_v;

constant TRN_IDLE    : std_logic_vector(1 downto 0) := "00";
constant TRN_BUSY    : std_logic_vector(1 downto 0) := "01";
constant TRN_NSEQ    : std_logic_vector(1 downto 0) := "10";
constant TRN_SEQU    : std_logic_vector(1 downto 0) := "11";

constant RSP_OKAY    : std_logic := '0';
constant RSP_ERROR   : std_logic := '1';

constant SZ_BYTE        : std_logic_vector(2 downto 0) := "000";
constant SZ_HALFWORD    : std_logic_vector(2 downto 0) := "001";
constant SZ_WORD        : std_logic_vector(2 downto 0) := "010";

    signal HSEL_active        : std_logic;
    signal HREADYOUT_int      : std_logic;
    signal HREADYOUT_int_s1   : std_logic;
    signal HREADYOUT_int_rise : std_logic;
    signal nextAhbReq         : std_logic;
    signal nextAhbReq_s1      : std_logic;
    signal PSEL_flag          : std_logic;
    signal PENABLE_flag       : std_logic;
    signal INITADDR_r         : std_logic_vector(11 downto 0);
    signal INITDONE_r         : std_logic_vector(15 downto 0);
    signal HWRITE_save        : std_logic;
    signal HSEL_save          : std_logic_vector(15 downto 0);
    signal last_client_write  : std_logic;
    signal INITDATVAL_w       : std_logic_vector(15 downto 0);
    signal HSEL_and_HWRITE    : std_logic;
    signal HSEL_and_HWRITE_s1 : std_logic;
begin
    HRESP <= RSP_OKAY;
    HRDATA <= "00000000000000000000000000000000";
    HSEL_active <= (or_v(HSEL(15 downto 0)));
    nextAhbReq <= '1' when HREADYOUT_int='1' and HREADYIN='1' and
                           HSEL_active='1' and
                           ((HTRANS = TRN_NSEQ) or (HTRANS = TRN_SEQU)) else
                  '0';

    HSEL_and_HWRITE <= HSEL_active and HWRITE;

    process (HCLK, HRESETN)
    begin
        if ((not(HRESETN)) = '1') then
            nextAhbReq_s1 <= '0';
            HREADYOUT_int_s1 <= '0';
            INITADDR_r <= "000000000000";
            last_client_write <= '0';
            HWRITE_save <= '0';
            HSEL_save <= "0000000000000000";
            PSEL_flag <= '0';
            PENABLE_flag <= '0';
            INITDONE_r <= "0000000000000000";
            HSEL_and_HWRITE_s1 <= '0';
        elsif (HCLK'event and HCLK = '1') then
            HSEL_and_HWRITE_s1 <= HSEL_and_HWRITE;
            nextAhbReq_s1 <= nextAhbReq;
            HREADYOUT_int_s1 <= HREADYOUT_int;
            if (nextAhbReq = '1') then
                case HSIZE is
                    when SZ_BYTE =>
                        INITADDR_r(11 downto 0) <= HADDR(11 downto 0);
                        last_client_write <= (and_v(HADDR(11 downto 0))) and HWRITE;
                    when SZ_HALFWORD =>
                        INITADDR_r(11 downto 0) <= ('0' & HADDR(11 downto 1));
                        last_client_write <= (and_v(HADDR(11 downto 1))) and HWRITE;
                    when others =>
                        INITADDR_r(11 downto 0) <= ("00" & HADDR(11 downto 2));
                        last_client_write <= (and_v(HADDR(11 downto 2))) and HWRITE;
                end case;
                HWRITE_save <= HWRITE;
                HSEL_save <= HSEL;
            end if;
            if ((nextAhbReq and HWRITE) = '1') then
                PSEL_flag <= '1';
            elsif (PENABLE_flag = '1') then
                PSEL_flag <= '0';
            end if;

            PENABLE_flag <= (nextAhbReq_s1 and HWRITE_save);

            if ((PENABLE_flag and HWRITE_save) = '1') then
                for c in 0 to 15 loop
                    if ((HSEL_save(c)) = '1') then
                        if (last_client_write = '1') then
                            INITDONE_r(c) <= '1';
                        else
                            INITDONE_r(c) <= '0';
                        end if;
                    end if;
                end loop;
            end if;
        end if;
    end process;
    
    HREADYOUT_int_rise <= HREADYOUT_int and not(HREADYOUT_int_s1);
    HREADYOUT_int <= not((not(HSEL_and_HWRITE_s1) and HSEL_and_HWRITE) or
                         (PSEL_flag and not(PENABLE_flag)));
    HREADYOUT <= HREADYOUT_int;
    INITADDR(11 downto 0) <= INITADDR_r(11 downto 0);
    INITDATVAL_w(15 downto 0) <= PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag & PENABLE_flag and HSEL_save(15 downto 0);
    INITDATVAL(15 downto 0) <= INITDATVAL_w(15 downto 0);
    INITDONE(15 downto 0) <= INITDONE_r(15 downto 0);
    INITDATA(31 downto 0) <= HWDATA(31 downto 0);
    
end architecture COREAHBLITE_INITCFG_AWRAP_arch;
