cpu_state.h 10.5 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. 
 *
 */

/*****************************************************************
 * cpu_state.h
 *
 * Complete state of a PE... this structure is to be used by all cpu 
 * simulators so that switching between them is simple.
 *
 * Author: $Author: blythe $
 * Date: $Date: 2002/05/29 01:09:10 $
 *****************************************************************/

#ifndef CPU_STATE_H
#define CPU_STATE_H

#include "mips_arch.h"
#include "simtypes.h"
#include "cpu_interface.h"

#define LOG_TLB_HASH_SIZE       12
#define TLB_HASH_SIZE           (1<<LOG_TLB_HASH_SIZE)

#if defined(SIM_MIPS64)
#define EMBRA_USE_QC64    
#define QC64_INVALID_VPN     -1
#define QC64_NUM_ENTRIES   4096
#define QC64_READ            0
#define QC64_WRITE           2
#endif

#ifndef _LANGUAGE_ASSEMBLY

#if defined(SIM_MIPS64)
typedef struct {
   VA      vpn;
   MA      ma;
   uint    writable;
}  QC64HashEntry;
#endif

#include "list.h"

typedef enum BranchStatus {
   BranchStatus_none,
   BranchStatus_nottaken,
   BranchStatus_taken,
   BranchStatus_bd} BranchStatus;

/* Used for TLB hashing */
typedef struct {
   List_Links links;
   short index;
   short onList;
} IndexListLink;

typedef List_Links IndexHeaders[TLB_HASH_SIZE];

typedef union {
   int    fgrInt[2];
   float  fgr[2];
   double fpr;
   uint64 fgrLL;
} FPReg;

typedef struct CPUState {
   Reg R[NUM_GP_REGS];
   Reg FPR[NUM_FP_REGS];
   Reg32 FCR[NUM_FC_REGS];
   Reg CP0[NUM_CP0_REGS];
   Reg PC;                      /* Current Program Counter */
   Reg HI;
   Reg LO;

   /**** EMBRA Specific ****/

   volatile int cycleCountdown;	/* Used to optimize interventions & timing */
   volatile int blockCycleCountdown; /* cycleCountdown at end of block */
   int  timeQuantum;            /* Interleave procs in MPinUP by this amt */

   /* These are memory areas to save certain embra registers */
   /* We restore all of them (because we want to return to the TC from */
   /* any point in C code which could have trashed our values), but we */
   /* only store a couple (like the clock and cache hit counts) on callout */
#ifdef EMBRA_USE_QC64
   QC64HashEntry *mmu;        /* 64bit MMU hash table */
#else
   MA *mmu;                   /* MMU relocation array */
#endif
   PLN*  cache_tag;             /* Embra cache tags */
   uint Sdhit_count;
   uint Sihit_count;
   /* This is the original stack pointer.  We restore this as a crude, */
   /* but effective way of unwinding the stack when C code calls back */
   /* into the TC */ 
   uint Sstack_base;
   uint Ssreg2;
   uint Sorig_stack;
   int  myNum;                  /* Processor number */
   struct CPUState *next;       /* Fast processor switch (really CPUState*)*/
   Reg   oldPC;                 /* Used to make chaining decisions */
   uint  jumpPC;                /* Translation cache address of last jump */
   SimTime *eventQueueTimePtr;  /* Addr of event Q time */
   /* XXX - Achtung. DONT put an odd number of 4 byte fields above */
   /* this value because then its not 8 byte aligned and the compiler */
   /* alignment invalidates my assembly offsets down below */
   uint64 cycleCount;/* Total number of cycles executed */
   uint  qcra;                  /* Save ra here for outlined QC */
   uint  stalled;               /* Boolean, are we stalled? */
   char* cache_ax;              /* Base for a Physarray or qc_v access */
   int  _pad0;                  /* Allow LLC to start on dbl word allignment */
   Reg LLContents;              /* Embra: Contents of location of last
                                   LL */
   Reg hackedSavedVaddr;        /* Embra: used in 64bit hacked MMU lookup */
   PA LLAddr;                   /* Memory Address address of last LL */
   int LLBit;                   /* Set when an LL has been issued */
   bool fpLoaded;               /* Embra: is FP reg file loaded? */
   volatile int outTC;	        /* Embra: Used to optimize interventions */
#ifdef EMBRA_USE_QC64
   QC64HashEntry  *kernelMMU; 
   QC64HashEntry  *userMMU;
   VA *QC64TLBBackMap;
#else
   MA  *kernelMMU;              /* Embra: starting addresses of the mmus */
   MA  *userMMU;
#endif
   Reg  nPC;
   int  myBit;                  /* Processor number in bitmask format */
   int  outOfSlaveLoop;         /* Damn slave loop */
   struct CPUState *prev;       /* Complement to next */

   bool clockStarted;
   uint clockInterval;

   int *intrBitsPtr;
   uint cp0savearea[5];         /* Base mode stores the kregs here */
   
   uint clockTimeLeft;
   uint memSize;               /* Size of main memory in bytes */
   char	*memoryPtr;            /* Main memory array */

   TLBEntry tlbEntry[MAX_NTLBENTRIES]; /* All of the CPU's TLB entries */

   IndexListLink indexList[MAX_NTLBENTRIES]; /* Hash table for TLB */
   IndexHeaders  tlbIndexHeaders;        /* Hash table for TLB */

   char* pa_p;                  /* Base of physarray */
   char* qc_v;                  /* Base of virt quick check */
   uint* qc_p;                  /* XXX - really phys_info_t* */


  /*************************
   *    MIPSY ADDITIONS    *
   *************************/

   SimTime timerCycleCount;        /* Used for the R4000 timer counter */

   CPUStatus cpuStatus;
   Inst stalledInst;

   BranchStatus branchStatus; /* Used to keep main loop clean... if this stuff */
   VA   branchTarget;         /* isn't set, you just move PC forward by 4 */

   bool takeInterrupt;        /* Take interrupt when cache stall completes */

   /*
    * We speed up ICache references by caching the last line.
    */
   PA   cachedILine;          /* Cache of current Icache line - quick check */
   byte *cachedILineData;
   uint cachedSetIndex;

   /* 
    * We speed up all references by caching the last translation.
    */
   uint pcVPNcache;           /* Cache of last PC translation VPN */
   PA   pcPaddrcache;         /* Cache of last PC translation PPN */

   int LLbit;		       /* True if an LL instruction is active. */
   uint cpuMode;               /* Mode of the CPU - KERNEL or USER or IDLE */


   int numTlbEntries;                            /* Number of TLB entries */
   unsigned char tlbEntrySize[MAX_NTLBENTRIES]; /* Size index of TLB entry */

   /**********************************
    * Parameters for supporting SOLO *
    **********************************/

   /* Flag to charge stall time to barrier rather than to the locks from which
   the barrier is constructed */
   uint      inBarrier;
   /* need the next two variables to track the return status from the 
      solo emulation of system calls. syscallResult will probably have
      to become an union eventually */

   int syscallResult;
   int syscallStatus;

   FPReg fpReg[32];
   int   is32bitMode; /* true in running in 32bit mode */
   int   notFRbit;    /* inverse of the FR bit in the status reg - 
                       * tell us if we have 32 or 16 FP regs.  */

   /**********************************
    * Parameters for supporting MXS. *
    **********************************/
   struct s_cpu_state *st;	/* MXS CPU state	*/
   int inMXS;   /* TRUE if we should use MXS otherwise MIPSY does the work */
   int switchToMXS; /* Should we switch to MXS */
   int switchToMIPSY; /* Should we switch to MIPSY */
#define MAX_NUM_EXCEPTIONS 128  /* This needs to be bigger than the IWIN */
   int lastException;
   struct {          /* LAST exception buffer */
      Reg32 cause;
      Reg vec;
      Reg badaddr;
      Reg hireg;
      Reg ctxtreg;
      Reg xctxtreg;
   } exception[MAX_NUM_EXCEPTIONS];
} CPUState;

/* Macros used by both mipsy and embra */
#define SET_CPU_MODE(_proc, _mode) ((_proc)->cpuMode = (_mode))
#define CURRENT_MODE(_proc)        ((_proc)->cpuMode)

#define IS_KERNEL_MODE(_proc)      ((_proc)->cpuMode == KERNEL_MODE)
#define IS_USER_MODE(_proc)        ((_proc)->cpuMode == USER_MODE)
#define IS_SUPERV_MODE(_proc)      ((_proc)->cpuMode == SUPERVISOR_MODE)

#define SET_CPU_STATUS(_cpuNum, _status) (pePtr[_cpuNum]->cpuStatus = _status)

/* Routines for supporting MXS. */
extern bool InterruptIsPending(struct s_cpu_state *st);
extern void HandleException(struct s_cpu_state *st, int exnum, int in_delay);
extern void PrintException(struct s_cpu_state *st, int exnum);
extern int  GetLastException(struct s_cpu_state *st);
extern bool DoPrivInst(struct s_cpu_state *st, uint instr, 
		       uint srcreg, uint *dstreg, bool *hack);
extern int  DoUncachedRead(struct s_cpu_state *st, uint vAddr, uint pAddr,
                           int size,void *dataPtr);
extern int  DoUncachedWrite(struct s_cpu_state *st, uint vAddr, uint pAddr,
                            int size, int accel, void *dataPtr);
extern int FPusable(struct s_cpu_state *st);
extern void CopyFromMXS(CPUState *P);
extern void CopyToMXS(CPUState *P);
extern void RecordMxsMemsysStall(struct s_cpu_state *st, SimTime stallTime);

#endif /* _LANGUAGE_ASSEMBLY */

#define _INT_SIZE         4
#define _PTR_SIZE         4

#define GP_OFF          (0 * REG_SIZE)
#define FP_OFF          (NUM_GP_REGS * REG_SIZE)
#define FCR_OFF         (FP_OFF + (NUM_FP_REGS * REG_SIZE))
#define CP0_OFF         (FCR_OFF + (NUM_FC_REGS * _INT_SIZE))
#define PC_OFF          (CP0_OFF + (NUM_CP0_REGS * REG_SIZE))
#define HI_OFF          (PC_OFF + REG_SIZE)
#define LO_OFF          (HI_OFF + REG_SIZE)
#define CCD_OFF         (LO_OFF + REG_SIZE)
#define BCCD_OFF        (CCD_OFF + _INT_SIZE)
#define TQ_OFF          (BCCD_OFF + _INT_SIZE)
#define MMU_OFF         (TQ_OFF + _INT_SIZE)
#define CACHE_OFF       (MMU_OFF + _PTR_SIZE)
#define SDHIT_OFF       (CACHE_OFF + _PTR_SIZE)
#define SIHIT_OFF       (SDHIT_OFF + _INT_SIZE)
#define SSTACK_OFF      (SIHIT_OFF + _INT_SIZE)
#define SSREG2_OFF      (SSTACK_OFF + _INT_SIZE)
#define SORIGSTACK_OFF  (SSREG2_OFF + _INT_SIZE)
#define MYNUM_OFF       (SORIGSTACK_OFF + _PTR_SIZE)
#define NEXT_OFF        (MYNUM_OFF + _INT_SIZE)
#define OLDPC_OFF       (NEXT_OFF + _PTR_SIZE)
#define JUMPPC_OFF      (OLDPC_OFF + REG_SIZE)
#define CALL_OFF        (JUMPPC_OFF + _INT_SIZE)
#define HICC_OFF        (CALL_OFF + _INT_SIZE)
#define LOCC_OFF        (HICC_OFF + _INT_SIZE)
#define QCRA_OFF        (LOCC_OFF + _INT_SIZE)
#define STALLED_OFF     (QCRA_OFF + _INT_SIZE)
#define CACHE_AX_OFF    (STALLED_OFF + _INT_SIZE)
#define LLCONTENTS_OFF  (CACHE_AX_OFF + _PTR_SIZE+_INT_SIZE)
#define HACKADDR_OFF    (LLCONTENTS_OFF + REG_SIZE)
#define LLADDR_OFF      (HACKADDR_OFF + REG_SIZE)
#define LLBIT_OFF       (LLADDR_OFF + PHYS_ADDR_SIZE)
#define FPLOADED_OFF    (LLBIT_OFF + _INT_SIZE)
#define OUTTC_OFF       (FPLOADED_OFF + _INT_SIZE)

#endif /* CPU_STATE_H */