solo_extras.c 7.78 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_extras.c
 *
 * Author: $Author: blythe $
 *****************************************************************/
#ifdef sgi
#define _BSD_SIGNALS
#ifndef _LONGLONG
#define _LONGLONG
#endif
#endif

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/signal.h>
#include <sys/time.h>
#include "annotations.h"
#include "solo.h"
#include "mipsy.h"
#include "cpu.h"
#include "cpu_stats.h"
#include "sim_error.h"
#include "cpu_interface.h"
#include "simutil.h"
#include "solo_anl.h"
#include "solo_extras.h"
#include <sys/types.h>
#include <malloc.h>
#include <bstring.h>
#include "simtypes.h"
#include "../../memsystems/memsys.h"
#include "../../caches/memref.h"
#include "annotations.h"
#include "solo.h"
#include "cp0.h"
#include "hw_events.h"
#include "gdb_interface.h"
#include "tcl_init.h"
#include "params.h"

#define WORDS_IN_CACHELINE 16

/*FIXTHIS: Need a prototype in an include file, eventually! */
extern int FlashWriteQueueFull(unsigned ProcNum);
extern void FlashliteStopCPU(unsigned cpu);
extern void CPUVectorInit(void);
extern void MipsyInitStats(void);
extern void MipsyDumpAllStats(void);
void *appAmallocArena;		

/* Local Functions */
static void ReadConfiguration(void);
static void SigInit(void);
static void SoloDebug(void);
static void DebugCallback(int cpuNum, EventCallbackHdr *hdr, void *arg);

/* Solo Mipsy Variables */
Reg     holdSP, holdRA, holdPE, holdGP;
CPUType simosCPUType=MIPSY;

/* Used from within mipsy */
int intrBits = 0; /* We never want interrupts going off */
int FlashLiteMemModel = FALSE;

/*****************************************************************
 * MipsySoloInit
 *****************************************************************/
void
MipsySoloInit(void)
{
   int i;
   CPUState *p;
   StatusReg statusReg;

   SigInit();
   Simdebug_init();
   ReadConfiguration();

   MipsyInitStats();

   for (i=0; i<TOTAL_CPUS; i++) {
      p = &PE[i];
      p->intrBitsPtr = &intrBits;
      p->myNum = i; 
      /* We need the cpu's in kernel mode to avoid triggering problems
         with unusable coprocessors, debugging, etc. */
      p->cpuMode = KERNEL_MODE;
      p->cpuStatus = cpu_halted;
      STATS_SET(i, numInstructions, 0);

      machineState[i].syscallNum = -1;
      machineState[i].syscallState[0] = -1;
      machineState[i].syscallState[1] = -1;
      machineState[i].inBarrier = FALSE;

      p->inBarrier = FALSE;
      statusReg.ts_data = p->CP0[C0_SR]; 
      /* Enable FPU */
      statusReg.s32.ts_cu1 = 1;
      p->CP0[C0_SR] = statusReg.ts_data;
   }
}

/*****************************************************************
 * SigInit
 *
 * Set up any signal handlers that may be needed.
 *****************************************************************/
static void
SigInit(void)
{
   struct sigvec sigvecarg;
   int signo;

   signo = SIGTRAP;
   sigvecarg.sv_handler = (void (*)())SoloDebug;

   if (sigvec(signo, &sigvecarg, (struct sigvec *) 0) < 0) {
      perror("Sigvec");
   }
}

static void
SoloDebug(void)
{
   CPUWarning("DEBUGGER: Received SIGTRAP at cycle %lld\n", 
                (uint64)MipsyReadTime(0) );
   MipsyDebug(0,0);
}

static struct DebugHdr {
    EventCallbackHdr hdr;
} debugEvent[MIPSY_MAX_CPUS];


static void
DebugCallback(int cpuNum, EventCallbackHdr *hdr, void *arg)
{
   CPUWarning("DEBUGGER: Invoked as callback at cycle %lld\n", 
                (uint64)MipsyReadTime(0));
   MipsyDebug(0,0);
}

/*****************************************************************
 * ReadConfiguration
 *****************************************************************/
static void
ReadConfiguration(void)
{
   mipsyCurrentTime = 0;   

   mipsySkipCaches  = 0;
   CPUVec.singleEventQueue  = TRUE;
   CPUVec.CycleCount        = MipsyCycleCount;

   CPUVectorInit();
}


static void 
SyncRetry(int cpuNum, EventCallbackHdr *hdr, void *arg)
{
   MipsySoloSync(cpuNum);
}

void
MipsySoloSync(int cpuNum)
{
   Result ret;
   static struct { 
           bool active;
           EventCallbackHdr syncRetryCallback;
           CPUStatus origState;
   } state[SIM_MAXCPUS];


   ret = MemRefSync(cpuNum);

   if (ret == STALL) {
      if (!state[cpuNum].active) { 
         state[cpuNum].origState = PE[cpuNum].cpuStatus;
         PE[cpuNum].cpuStatus = cpu_bdoor_stalled;
         state[cpuNum].active = TRUE;
      }
      EventDoCallback(cpuNum,SyncRetry,&state[cpuNum].syncRetryCallback,0,1);
   } else {
      if (state[cpuNum].active) { 
         PE[cpuNum].cpuStatus = state[cpuNum].origState;
         state[cpuNum].active = FALSE;
      }
      SoloBackdoorSyncFinish(cpuNum); 
   }
   return;
}

int
MipsyFlushCacheLine(int cpuNum, VA vAddr)
{
   PA pAddr;
   CPUState *P;
   Result ret = SUCCESS;
   int wasDirty;
   uint tlbFlavor = TLB_DFETCH;
   long long lclData[WORDS_IN_CACHELINE];
   void *bdoorAddr;

   if (SoloCachesAreOn()) {
      P = &PE[cpuNum];
      
      vAddr = vAddr & (~(SCACHE_LINE_SIZE-1));
      /* WARNING: this code is not cool, it's temporary */
      /* Extract only cache line aligned addresses */
      
      ret = TranslateVirtual(P, vAddr, &pAddr,  &tlbFlavor,&bdoorAddr);
      if (ret != SUCCESS) {
         CPUError("Translation failed in SoloFlush!\n");
      }
      if (tlbFlavor & TLB_BDOOR) {
         CPUError("SoloFlush on backdoor address!\n");
      }
      
      CPUPrint("Flush for VA: %x, PA: %llx\n",vAddr, pAddr);
      
#ifdef USE_FLASHLITE
      if (FlashWriteQueueFull(soloCPUNum)) { 
         return 0;
				/* There's a race here..another unit could */
				/* steal the apparent space out from */
				/* under me...causing me to crash. Where's */
				/* the flow control!!!*/
      }
#endif
      
      ret = CacheExtract(soloCPUNum, pAddr, SCACHE_LINE_SIZE, &wasDirty,
                         (char *) lclData);
      /* Flush with writeback=1, retain=0 */

      if (ret) {		/* If line found */
	 /* Issue bogus command (get won't occur because of the -1), but with */
	 /* an associated writeback */ 
	 ret = memsysVec.MemsysCmd(soloCPUNum, MEMSYS_GET, 0LL, -1,
                                   pAddr, wasDirty, (char *) lclData);
	 /* wasDirty indicates writeback or replacement hint */
      }
   } else {
      CPUPrint("MipsyFlushCacheLine called when NO_CACHES defined\n");
   }
   return 1;
}

void
MipsyStartCPU(int cpuNum, VA pc, VA ra, VA stackTop)
{
   CPUState *p = &PE[cpuNum];

   /* I'm just subtracting 8 meg from the previous stack. This won't */
   /* catch the previous processor if it overflows onto my stack */
   p->PC = (Reg)pc;
   p->nPC = (Reg)pc + (Reg)4;

   p->R[REG_RA] = (Reg)ra;
   p->R[REG_SP] = stackTop;
   p->R[REG_GP] = PE[0].R[REG_GP];
   p->cpuStatus = cpu_running;
   ASSERT(p->inBarrier == FALSE);
}

void
MipsyStopCPU(int cpuNum)
{
   CPUState *p = &PE[cpuNum];

   p->cpuStatus = cpu_halted;
}


void 
SoloTurnOnCaches(void)
{
   MipsyTurnOnCaches();
}

void 
SoloTurnOffCaches(void)
{
   MipsyTurnOffCaches();
}

bool
SoloCachesAreOn(void)
{
   return MipsyCachesAreOn();
}


/* Random commands */
void sim_console_has_char(int foo)
{
}
void HiveCmd(ClientData a, Tcl_Interp *b, int c, char **d)
{
}

/*****************************************************************
 * SoloExit
 *****************************************************************/
void
SoloExit(void)
{
   struct timeval t;
   gettimeofday(&t, (struct timezone*)0);
 
   CPUPrint("Simulation End: %ld s %ld us\n", t.tv_sec, t.tv_usec);

   if (SoloCachesAreOn()) {
#ifdef USE_FLASHLITE
      FlashliteStopCPU(0);
#endif
      memsysVec.MemsysDone();
   }
   MipsyDumpAllStats();
   CPUPrint("Thank you for flying Mipsy\n");
   AnnExec(AnnFind("simos","exit"));
   CPUWarning("SoloExit has completed\n");
}