solo_cp0.c 6.1 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. 
 *
 */

/****************************************************************
 * solo_cp0.c
 * 
 * $Author: blythe $
 * $Date: 2002/05/29 01:09:11 $
 *****************************************************************/
#include "mipsy.h"
#include "cp0.h"
#include "sim_error.h"
#include "solo_anl.h"
#include "solo_interface.h"
#include "cpu_interface.h"
#include "solo.h"
#include "solo_interface.h"
#include "solo_page.h"
#include "simtypes.h"
#include "cpu_stats.h"

static int libcOwner = -1;
static int libcWaiters = 0;

Result
TranslateVirtualNoSideeffect(CPUState *P, VA vAddr, PA *pAddr)
{
   uint flavor = 0;
   void *bdoorAddr = 0;
   return TranslateVirtual(P, vAddr, pAddr, &flavor,&bdoorAddr);
}

/*****************************************************************
 * TranslateVirtual
 *
 * Now that we're in solo mipsy, just return the virtual address
 *****************************************************************/
Result 
TranslateVirtual(CPUState *P, VA vAddr, PA *pAddr, uint *tlbFlavor, void **bdoorAddr)
{
   int i, p;
   bool icache; 
   int cpuNum = P->myNum;
   SoloPA soloPA;

   icache = (bool) TLB_IS_IFETCH(*tlbFlavor);   

   /* Setting this to 0 means that by this is not a backdoor reference */
   *tlbFlavor = 0;
   
   if (((void *)vAddr >= (void*)SOLO_STACK_TOP) &&
       ((void *)vAddr < (void*)0x90000000)) {
				/* WARNING: ALL references above the top of */
				/* the application's stack top are backdoor. */
      *tlbFlavor = TLB_BDOOR_DATA;
      *bdoorAddr = (void *)vAddr;
      *pAddr = (PA)vAddr;
   } else {
      if (icache) {
         /* Make sure that only one processor at a time is allowed to */
         /* be executing in the libc code. The start of libc is found */
         /* by linking in an object file with a single function in it. */ 
         if ((void *)vAddr >= (void *)CommAreaPtr->libcStart) {
            if ((libcOwner != P->myNum) && (libcOwner != -1)) {
               P->cpuStatus = cpu_libc_blocked;
               STATS_SET(cpuNum, libcWaitStart, MipsyReadTime(cpuNum));
               libcWaiters++;
               return FAILURE;
            } else {
               libcOwner = P->myNum;
            }
         } else {
            if (libcOwner == P->myNum) {
               if (libcWaiters > 0) {
                  libcWaiters--;
                  for (i=1; i < TOTAL_CPUS; i++) {
                     p = (P->myNum + i) % TOTAL_CPUS;
                     if (PE[p].cpuStatus == cpu_libc_blocked) {
                        STATS_ADD_INTERVAL(p, libcWaitTime, libcWaitStart);
                        libcOwner = p;
                        PE[p].cpuStatus = cpu_running;
			break;
                     }
                  }
                  ASSERT(libcOwner != P->myNum);
               } else {
                  libcOwner = -1;
               }
            }
         }
      } 
      if (IS_STACK_REF(vAddr)) {
         soloPA = SoloV_to_P(P->myNum, vAddr, P->myNum, TRUE, tlbFlavor);
      } else {
         soloPA = SoloV_to_P(P->myNum, vAddr, P->myNum, FALSE, tlbFlavor);
      }
      if ((*tlbFlavor) == TLB_UNCACHED) {
         *pAddr = vAddr;   /* This will be translated by the memsys command */
      } else {


#if 0
	 /* JH: This is the safe, default version that doesn't provide the lock hack.
	    In case the lock code crashes for you badly, this is a saving grace you
	    can use*/
         *pAddr = SoloCompressAddr(soloPA);
#else
/* Check for accesses in the lock space, and remap them into the special range*/
	 if (SOLO_PA_SPACE(soloPA) == 1) {

	    /* Lock space.  Remove space bit, add base in mipsy VA range so */
	    /* compress maintains hidden notion of this address */
#ifdef DEBUG_PAGE_VERBOSE
	    CPUPrint("Lock address detected, pAddr = %llx\n",soloPA);	    
#endif
	    soloPA += soloLockBase;

/*	    soloPA &= ~((unsigned long long) 0xe0000000LL);  */
	    soloPA = SOLO_FORM_PA( SOLO_PA_NODE(soloPA), 0LL, /* Space 0! */  
				   SOLO_PA_OFFSET(soloPA));

#ifdef DEBUG_PAGE_VERBOSE
	    CPUPrint("After address munging, pAddr = %llx\n",soloPA);	    
	    /* Remove the space bit.  Not strictly necessary, since compress will */
	    /* throw it away anyway... */
#endif
	 } else if (SOLO_PA_SPACE(soloPA) == 2) {
            /* Check for accesses in the barrier space, and remap them into
               the special range*/

	    /* Lock space.  Remove space bit, add base in mipsy VA range so */
	    /* compress maintains hidden notion of this address */
#ifdef DEBUG_PAGE_VERBOSE
	    CPUPrint("Barrier address detected, pAddr = %llx\n",soloPA); 
#endif
	    soloPA += soloBarrierBase;

/*	    soloPA &= ~((unsigned long long) 0xe0000000LL);  */
	    soloPA = SOLO_FORM_PA( SOLO_PA_NODE(soloPA), 0LL, /* Space 0! */  
				   SOLO_PA_OFFSET(soloPA));

#ifdef DEBUG_PAGE_VERBOSE
	    CPUPrint("After address munging, pAddr = %llx\n",soloPA);	    
	    /* Remove the space bit.  Not strictly necessary, since compress will */
	    /* throw it away anyway... */
#endif
	 }

         *pAddr = SoloCompressAddr(soloPA);
#ifdef DEBUG_PAGE_VERBOSE
	 CPUPrint("Before compression, pAddr = %llx\n",soloPA);	    
	 CPUPrint("After compression, pAddr = %x\n",*pAddr);	    
#endif
#endif


      }
   }

   return SUCCESS;
}


/*****************************************************************
 * EXCEPTION 
 ****************************************************************/
void EXCEPTION(CPUState *P, int code)
{
   CPUError("EXCEPTION %d occurred on cpu %d @ PC 0x%x\n", 
            code, P->myNum, P->PC);
}

/*****************************************************************
 * ExceptionReturn
 ****************************************************************/
void 
ExceptionReturn(int cpuNum)
{
   CPUPrint("RFE - you shouldn't be here\n");
}


void MipsyCheckForInterrupts(CPUState *P)
{
   /* SOLO doesn't do interrupts */
}

void UpdateCPUMode(CPUState *P)
{
   CPUWarning("SOLO in UpdateCPUMode\n");
}

int
ExecuteC0Instruction(CPUState *P, Inst instr)
{
   CPUWarning("WriteC0Reg - you shouldn't be here\n");
   return C0_CONTINUE;
}