/******************************************************************************
 *
 *                                  Cpu_d
 *
 * This module contains the CPU driver for all CPU's. The different parts are
 * separated by ifdef's.
 *
 * Note that the SP register should never be touched. Always use the IS or US
 * (whichever current) instead.
 *
 * History:
 *   +----------+------------+------------------------------------------------+
 *   |   Date   |     by     |     Description                                |
 *   +----------+------------+------------------------------------------------+
 *   |          | Coby       | Written                                        |
 *   +----------+------------+------------------------------------------------+
 * 
 *****************************************************************************/


#include "cc_def.h"
#include "global_f.h"
#include "cpu_d.h"

/*-----------------------------------------------------------------------------
 * 				
 * 				Variable definitions
 * 
 *---------------------------------------------------------------------------*/


/*
 * Default values of DE_AVAILABLE and NON_DE_AVAILABLE
 * This values are used only if the constant are not previously defined
 * In the board definition file
 */




#ifdef	DEBUG
 /*
  * The following variables are used to accommodate the rom and ram intbases
  * when the monitor is compiled to ram.
  */

public address  ram_intbase__;
public address  rom_intbase__;

#endif
/*
 * The following variables are used by the functions which use the asm 
 * function. Asm reads from or writes to them. This is because we definitly 
 * know their name in assembly.
 */

private unsigned write_value;

/*
 * Define local functions
 */


/*^L*/

/*-----------------------------------------------------------------------------
 *
 *			get_sp__(val)
 *
 * This function returns in val the value of the sp register. Note that this
 * function is applicable only for 32K cpu. It checks wether the cpu is in
 * user mode or supervisor mode and accordingly retreives the value of the
 * user stack or the supervisor stack.
 * In Swordfish there is only one sp register so this function is not needed.
 *
 *---------------------------------------------------------------------------*/
# if (CPU_TYPE != NS32SF641)

public void get_sp__(val)
unsigned int *val;
{
    unsigned int psr;

    get_reg_val__(&PSR__, &psr);

    if (BIT_ON(PSR_S, psr))
	get_reg_val__(&US__, val);
    else
	get_reg_val__(&IS__, val);
}

#endif

/*^L*/

/*-----------------------------------------------------------------------------
 *
 *			mod_sp__(val)
 *
 * This function changes the value of the sp register to the value pinted by
 * val. Note that this function is applicable only for 32K cpu. It checks
 * wether the cpu is in user mode or supervisor mode and accordingly modifies
 * the value of the user stack or the supervisor stack.
 * In Swordfish there is only one sp register so this function is not needed.
 *
 *---------------------------------------------------------------------------*/
# if (CPU_TYPE != NS32SF641)

public void mod_sp__(val)
unsigned int *val;
{
    unsigned int psr = 0;

    get_reg_val__(&PSR__, &psr);

    if (BIT_ON(PSR_S, psr))
	put_reg_val__(&US__, val);
    else
	put_reg_val__(&IS__, val);
}

#endif

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *			mod_sb__(val)
 *
 * This function changes the value of the sb register to the value pinted by
 * val. Note that this function is applicable only for 32K cpu. It first
 * modifies the sb register copy. Then it has to modify the static base
 * field of the current module table entry (only if cpu is in non-direct
 * exception mode. In order to do that it retrieves the mod register value into
 * a mod table entry pointer and uses this pointer to modify the static base field
 * (the first field in the entry).
 * In Swordfish there is no sb register so this function is not needed.
 *
 *---------------------------------------------------------------------------*/
# if (CPU_TYPE != NS32SF641)

public void mod_sb__(val)
unsigned int *val;
{
    unsigned int *modptr = 0;
    unsigned int cfg;
    int  excp_mode = NON_DIRECT_EXCEPTION_MODE;

    save_SB__ = *val;

#if (DE_AVAILABLE)
    excp_mode = exception_mode__();
#endif

    if (excp_mode == NON_DIRECT_EXCEPTION_MODE) {
	get_reg_val__(&MO__, &modptr);
	*modptr = *val;
    }
}

#endif

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *		    exception_mode__()
 *
 * This function returns the cpu current exception mode is direct
 * FALSE otherwise.
 *
 *---------------------------------------------------------------------------*/

public int exception_mode__()
{
#if ( DE_AVAILABLE AND NON_DE_AVAILABLE )
    unsigned int cfg_val;

    get_reg_val__(&CFG__, &cfg_val);

    return(BIT_ON(CFG_DE, cfg_val) ? 
	   DIRECT_EXCEPTION_MODE : NON_DIRECT_EXCEPTION_MODE);

#endif

#if ( (NOT DE_AVAILABLE)  AND NON_DE_AVAILABLE )
    return(NON_DIRECT_EXCEPTION_MODE);
#endif

#if ( DE_AVAILABLE AND (NOT NON_DE_AVAILABLE) )
    return(DIRECT_EXCEPTION_MODE);
#endif

} /* exception_mode__ */



/*^L*/
/*-----------------------------------------------------------------------------
 *
 *		    Change_exception_mode__(mode)
 *
 * This function changes the cpu exception to mode.
 *
 *---------------------------------------------------------------------------*/

public boolean change_exception_mode__(mode)
int mode;
{
#if ( DE_AVAILABLE AND NON_DE_AVAILABLE )
    unsigned int cfg_val;

    get_reg_val__(&CFG__, &cfg_val);

    if (mode == DIRECT_EXCEPTION_MODE)
	SET_BIT(CFG_DE, cfg_val);
    else
	CLEAR_BIT(CFG_DE, cfg_val);

    put_reg_val__(&CFG__, &cfg_val);

#endif

} /* change_exception_mode__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *  Invalidate_cache__(cache_char, all_entries, hex_addr, bin_addr, available)
 *
 * This function invalidates a specific entry, or all entries of a specified 
 * cache.
 * It use hex_addr if it is not a null string bin_addr is used otherwise;
 *
 * Available specifies if the cache is availabe in the current CPU.
 *
 *---------------------------------------------------------------------------*/

public void invalidate_cache__(cache_char, all_entries, hex_addr, bin_addr, available)
    char    cache_char;
    boolean all_entries;
    str     hex_addr;
    address bin_addr;
    boolean *available;
{
    boolean  err;


    /*
     * There is no cache on older CPU's
     */

#if (CORE_TYPE == CG )

    *available = FALSE;
    return;

#else
#if (CORE_TYPE == SF )
#define INVALIDE_ALL_DATA		asm("	cinv	[d]");
#define INVALIDE_DATA_ENTRY		asm("	cinv	[d]");
#define INVALIDE_ALL_INSTRUCTION	asm("	cinv	[i]");
#define INVALIDE_INSTARUCTION_ENTRY	asm("	cinv	[i]");
#else
#define INVALIDE_ALL_DATA		asm("	cinv	[a,d] ,_write_value");
#define INVALIDE_DATA_ENTRY		asm("	cinv	[d] ,_write_value");
#define INVALIDE_ALL_INSTRUCTION	asm("	cinv	[a,i] ,_write_value");
#define INVALIDE_INSTARUCTION_ENTRY	asm("	cinv	[i] ,_write_value");
#endif

    *available = TRUE;

    /*
     * If a specific address is to be invalidated, translate it to binary.
     */

    if (NOT all_entries) {
	if (hex_addr[0] != '\0') {
	    hex_to_bin__( hex_addr, &write_value, 'D');
	}
	else {
	    write_value = (unsigned int)  bin_addr;
	}
    }

    /*
     * According to the cache, invalidate the appropriate entries.
     */

    if (cache_char == 'D') {
        if (all_entries)   {
	    INVALIDE_ALL_DATA
        }
        else {
	    INVALIDE_DATA_ENTRY
        }
    }
    else if (cache_char == 'I') {
        if (all_entries)   {
	    INVALIDE_ALL_INSTRUCTION
        }
        else {
	    INVALIDE_INSTARUCTION_ENTRY
        }
    }
    else {
        ERROR( e_syntax__);
    }

#endif

} /* invalidate_cache */        

