callout.h 9.61 KB
/*
 * Copyright (C) 1996-1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * 
 * This file is part of the SimOS distribution. 
 * See LICENSE file for terms of the license. 
 *
 */

#ifndef CALLOUT_H
#define CALLOUT_H

/*
 * In order to support 64bit mips we defined symbols for 
 * opcodes depending on the SIM_MIPS32 flag. We have
 * REG_ST_OP store a register opcode. 
 * REG_LD_OP load a register opcode.
 * ADDR_ADD_OP  add a register to an VA opcode.
 * ADDR_ADDI_OP add a immediate to a VA opcode.
 */

#ifdef SIM_MIPS32

#define VC_REG_ST_OP  VC_sw_op_
#define VC_REG_LD_OP  VC_lw_op_
#define REG_ST_OP v_stui
#define REG_LD_OP v_ldui
#define VC_ADDR_ADD_OP VC_addu_op_
#define VC_ADDR_ADDI_OP VC_addiu_op_

#else /* Support 64bit so must use ld/sd/daddu ops */

#ifndef _ABIN32
ERROR - 64bit Embra only currently works on SGIN32
#endif


#define VC_REG_ST_OP   VC_sd_op_
#define VC_REG_LD_OP   VC_ld_op_
#define REG_ST_OP v_stli
#define REG_LD_OP v_ldli
#define VC_ADDR_ADD_OP VC_daddu_op_
#define VC_ADDR_ADDI_OP VC_daddiu_op_

#endif /* ifndef SIM_MIPS32 */



/* Callout Notes:

   This file has been rewritten to use vcode to generate the
   code at run-time. That is why routines are function pointers.
   
   Callout trashes temps
   Callout routines run on simulator stack.

   See target_table in main_run.c for a list of the function addresses
   actually stored at these offsets...
*/

#define CALLOUT_TLBR 1*4
#define CALLOUT_TLBWI 2*4
#define CALLOUT_TLBWR 3*4
#define CALLOUT_TLBP 4*4
#define CALLOUT_RFE 5*4
#define CALLOUT_ERET 6*4
#define CALLOUT_RAISE_C1_UNUSABLE 7*4
#define CALLOUT_MTC0 8*4
#define CALLOUT_EXCEPTION 9*4
#define CALLOUT_TNS 10*4
#define CALLOUT_DEBUGER_BREAK 11*4
#define CALLOUT_KERN_DEBUGER_BREAK 12*4
#define CALLOUT_PC_ANN 13*4
#define CALLOUT_GRAB_LOCK 14*4
#define CALLOUT_RELEASE_LOCK 15*4
#define CALLOUT_UTIL_FUNC 16*4
#define CALLOUT_MFC0 17*4
#define CALLOUT_PREPC_ANN (18*4)
#define CALLOUT_CACHEOP (19*4)

#ifndef _LANGUAGE_ASSEMBLY

/* Types */

typedef void (*vfptr)();	/* Pointer to function returning void */

/* Also see translator.h */
C_LINK void     (*callout)( unsigned, unsigned, unsigned, unsigned );
C_LINK void     do_periodic_callout( unsigned, unsigned, unsigned, unsigned);
C_LINK void     embra_sync_barrier(void);
C_LINK unsigned MoveToC0_wrapper( unsigned, unsigned, unsigned, unsigned);
C_LINK unsigned raise_c1_unusable( unsigned, unsigned, unsigned, unsigned);


typedef unsigned (*mr_ptr)(unsigned, int); /* pointer to mem_ref_wrapper */
typedef unsigned (*mar_ptr)(unsigned, int, K0A);
/* pointer to mem_ref_wrapper */

C_LINK unsigned (*mem_ref_wrapper)( unsigned int, int new_state );
C_LINK unsigned (*phys_mem_ref_wrapper)( unsigned int, int new_state, K0A );
C_LINK unsigned (*pa_mem_ref_wrapper)( unsigned int, int new_state, K0A );

#endif /* _LANGUAGE_ASSEMBLY */


/* ***************************************************************
 * Callout stack management
 * ***************************************************************/

#define STOFF_CC_CORR   (4*4)
#define STOFF_BRANCHREG (6*4)
#define STOFF_SHADOW    (8*4)
#define SHADOW_SIZE     (8*8)
#define STOFF_RA        (STOFF_SHADOW+SHADOW_SIZE)
#define STOFF_SIMOS_RA  (252)

/* *********************************************************************
 * Assembly macros used by main_run.s and callout.s 
 * *********************************************************************/


/* ********************************************************************
 * Cycle count correction and IHIT/DHIT counters. 
 * 
 * 2 values of the countdown are saved in the EMP structure,
 * before and after the adjustment.  The former one is
 * used to determine if we will finish the quantum before
 * the end of the BB and therefore need to CX.
 * 
 * Note also that the callout might modify the cycleCountdown and
 * then return (in the presence of a cache miss) so that we need
 * to restore the value from the EMP structure.
 * The same can also be true of IHIT and DHIT depending on how
 * these are handled. 
 *
 * ********************************************************************/

#define CORRECT_OUTGOING_CC(_corr)   \
    v_stui(_corr, sp, STOFF_CC_CORR);		\
    v_stui(clock_reg, vss_base, BCCD_OFF);	\
    v_addu(clock_reg, clock_reg, _corr);	\
    v_subu(ihit_reg, ihit_reg, _corr);		\
    v_stui(clock_reg, vss_base, CCD_OFF);	\
    v_stui(dhit_reg, vss_base, SDHIT_OFF);	\
    v_stui(ihit_reg, vss_base, SIHIT_OFF);


#define CORRECT_INCOMING_CC          \
    v_ldui(clock_reg, vss_base, CCD_OFF);	\
    v_ldui(dhit_reg, vss_base, SDHIT_OFF);	\
    v_ldui(ihit_reg, vss_base, SIHIT_OFF);	\
    v_ldui(a3, sp, STOFF_CC_CORR);		\
    v_subu(clock_reg, clock_reg, a3);		\
    v_addu(ihit_reg, ihit_reg, a3);

/* ***********************************************************************
 * Some registers have to be saved on the stack only, and restored after
 * the callout. 
 * 
 * Note that this code is highly dependent on which underlying registers
 * are used. For example caller saved registers need NOT be saved and
 * restored. On the other hand, callee saved registers need to be
 * saved and restored.
 * 
 * Specifically, we need to 
 *     store and restore the volatile registers from EMP (even if callee saved!)
 *     store and restore the shadow registers   from the stack
 *     restored only     the common variables   from EMP
 * (unless they are callee saved. 
 * ***********************************************************************/

#define STACK_SAVE_REGS                      \
    REG_ST_OP(branchreg, sp, STOFF_BRANCHREG);  \
    v_stui(ra, sp, STOFF_RA);


#define STACK_RESTORE_REGS                   \
    REG_LD_OP(branchreg, sp, STOFF_BRANCHREG);  \
    v_ldui(ra, sp, STOFF_RA);		     \
    v_ldui(qc_reg, vss_base, CACHE_AX_OFF);  \
    v_ldui(mmumask_reg, vss_base, SSREG2_OFF); \
    v_ldui(mmu_reg, vss_base, MMU_OFF);

#define LOAD_COMMON_VARS                     \
    v_ldui(qc_reg, vss_base, CACHE_AX_OFF);  \
    v_ldui(mmumask_reg, vss_base, SSREG2_OFF); \
    v_ldui(mmu_reg, vss_base, MMU_OFF);


#if defined(SHADOW8)
<< -- additional register. >>
<<   -- Please make sure to add these to the macros below >>
#endif



/* !!! this highly depends on the allocation of registers
 * SHADOW0,SHADOW1,SHADOW2,SHADOW3 are callee saved --> optimize
 * Note that this will NOT work if we context switch within
 * a block. 
 */

#define SAVE_SHADOW_REGS                 \
/*  REG_ST_OP SHADOW0,STOFF_SHADOW+0*8(sp); */  \
/*  REG_ST_OP SHADOW1,STOFF_SHADOW+1*8(sp); */  \
/*  REG_ST_OP SHADOW2,STOFF_SHADOW+2*8(sp); */  \
/*  REG_ST_OP SHADOW3,STOFF_SHADOW+3*8(sp); */  \
/*  REG_ST_OP SHADOW4,STOFF_SHADOW+4*8(sp); */  \
/*  REG_ST_OP SHADOW5,STOFF_SHADOW+5*8(sp); */  \
/*  REG_ST_OP SHADOW6,STOFF_SHADOW+6*8(sp); */  \
/*    REG_ST_OP(shadow7, sp, STOFF_SHADOW+7*8);  */


#define RESTORE_SHADOW_REGS          \
/*    REG_LD_OP SHADOW0,STOFF_SHADOW+0*8(sp); */ \
/*    REG_LD_OP SHADOW1,STOFF_SHADOW+1*8(sp); */ \
/*    REG_LD_OP SHADOW2,STOFF_SHADOW+2*8(sp); */ \
/*    REG_LD_OP SHADOW3,STOFF_SHADOW+3*8(sp); */ \
/*    REG_LD_OP SHADOW4,STOFF_SHADOW+4*8(sp); */ \
/*    REG_LD_OP SHADOW5,STOFF_SHADOW+5*8(sp); */ \
/*    REG_LD_OP SHADOW6,STOFF_SHADOW+6*8(sp); */ \
/*     REG_LD_OP(shadow7, sp, STOFF_SHADOW+7*8); */


#if EMBRA_MPCACHE
/* For parallel cache mode */
/* These insure that when we are called out of the translation */
/*cache, our CPU state reflects this fact */
/* Since none of these functions */
/*  ever waits on a line, setting this bit is only a performance */
/* enhancer */ 
/* This is useful if one cpu hits a breakpoint while the other */
/* is executing because we could deadlock if the executing cpu */
/* needs to perform an intervention */
/* It needs to be set here and in main_run.s as well.  */
/* It is not necessary for the page mode stubs, because it is used */
/*for interventions  */
/* If VSS_BASE is zero, we are in a lot of trouble */
#define OUT_OF_TC v_stui(vss_base, vss_base, OUTTC_OFF);

#define ENTERING_TC  v_stui(VREGS[0], vss_base, OUTTC_OFF);
    /* Store information to rewind QC.  We need to rewind it because */
    /* there is a race condition between when we update our QC, and */
    /* when we actually execute the load or store.  In the */
    /* meantime, the line could have been stolen */
#define SAVE_QC_REWIND  v_stui(sim_t2, sp, 16*4);

#define RESTORE_QC_REWIND v_ldui(sim_t2, sp, 16*4);

        
    /* This saves the address of the beginning of the quick check
	array in the jumpPC field so if we return non-locally we can redo
	the quick check and continue */
#define SAVE_JUMPPC v_movu(t0, ra); v_addu(t0, t0, sim_t2); v_stui(t0, vss_base, JUMPPC_OFF);


#else
#define OUT_OF_TC 
#define ENTERING_TC
#define SAVE_QC_REWIND
#define RESTORE_QC_REWIND
#define SAVE_JUMPPC
#endif    


/* ***************************************************************
 * Management of the FP register file. We use the underlying registers
 * to cache the register file. Obviously, these need to be 
 * spilled on callouts and restored before use.
 *
 * A flag in the CPUState structure tell whether the fp register
 * file has been loaded. On use (see the translator), we 
 * check this flag and load the file if necessary. On 
 * callouts and context switches, we save the file is the 
 * flag is set and then clear the flag.
 *
 * ***************************************************************/

/* XXX note: this macro is non-reentrant; can only be called once per
 * generated function
 */
#define SPILL_FP_IF_ENABLED		\
{					\
  spill_fp_label = v_genlabel();	\
  v_ldui(t1, vss_base, FPLOADED_OFF);	\
  v_beqii(t1, 0, spill_fp_label);	\
  v_stui(zero, vss_base, FPLOADED_OFF);\
  v_jalpi(ra,SpillFP);			\
  v_label(spill_fp_label);		\
}



#endif /* CALLOUT_H */