pcache.h 7.42 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. 
 *
 */

/*****************************************************************
 * pcache.h
 * 
 * This is the interface into the 2level cache-based memory 
 * subsystem. We currently support two first level caches: Split I and D 
 * All caches have controllable associativity from 1->4.
 * 
 * $Author: blythe $
 * $Date: 2002/05/29 01:09:09 $
 *******************************************************************/

#ifndef _PCACHE_H
#define _PCACHE_H

#ifdef SIM_ALPHA  /* hack */ 
extern int iAddrDivisor;
extern int dAddrDivisor;
#endif /* SIM_ALPHA */

#include "machine_params.h"
#include "eventcallback.h"

#ifndef NDEBUG
#define error CPUError    /* Make ASSERT()s happy */
#endif

/* Currently hardcoded. Supported values are 1,2,4 */
#define ICACHE_ASSOC             (2) 
#define DCACHE_ASSOC             (2)

/* Quickly checking if an instruction is in the same line as the last
 * instruction can be an enormous performance gain. Each cache that is
 * implemented should supply these calls. Eventually the actual
 * handling of a quick hit should be handled here, too.
 */

#if defined(SIM_MIPS32) || defined(SIM_MIPS64)
#include "../../cpus/mipsy/mipsy.h"
# define QUICK_ICACHE_CLEAR(_num)   (pePtr[_num]->cachedILine = BAD_CACHED_LINE)
# define QUICK_ICACHE_SET(_num, _addr, _set, _setindex) \
{  pePtr[_num]->cachedILine      = ICACHE_ONE_LINE(_addr);  \
   pePtr[_num]->cachedILineData  = (_set)->data[_setindex]; \
}
#else
# define QUICK_ICACHE_CLEAR(_num)
# define QUICK_ICACHE_SET(_num, _addr, _set, _setindex) 
#endif

/*
 * Data handling flags:
 * BLOCKING_WRITES- Writes block until the line is returned in exclusive mode.
 * BUFFER_WRITES- When writes on non-blocking, buffer them in the MHT until 
 *                ownership of the line is returned. Otherwise the changes are 
 *                given immediately to the memory system.
 */
#define BLOCKING_WRITES 
#ifndef BLOCKING_WRITES
#define BUFFER_WRITES     1 
#endif

#ifdef MIPSY_MXS
/*

 * MXS does it own write buffer and handling of blocking writes.
 */
#undef BUFFER_WRITES
#ifndef BLOCKING_WRITES
#define BLOCKING_WRITES
#endif
#endif

#if (defined PA_IS_LL)
# define INVALID_TAG     (0x8000000000000000LL) /* Line is not valid */
# define EXCLUSIVE_TAG   (0x4000000000000000LL) /* Line is exclusive */
# define BAD_CACHED_LINE (0x8fffffffffffffffLL) /* Line is invalid */
#elif (defined PA_IS_UINT)
# define INVALID_TAG     0x80000000     /* Line is not valid */
# define EXCLUSIVE_TAG   0x40000000     /* Line is in exclusive mode */
# define BAD_CACHED_LINE 0x8fffffff     /* Line is invalid */
#else
# error You must define either PA_IS_LL or PA_IS_UINT
#endif /* PA_IS_LL */

/* Cache configuation. 
 * For now, the assoc is hardcoded. 
 * Everything else is a run-time option
 */

#define WORD_SIZE               4

/*
 * Number of miss-handling-table entries below primary caches.  This
 * value is shared by the primary and secondary cache structures.
 */

#define MHT_SIZE 4

/*
 * First level miss handling table.
 */   

typedef struct MHT { 
   EventCallbackHdr evthdr; /* So we can make this an event callback */
   int  status;             /* Used for bus event */
   bool inuse;              /* TRUE if entry active */
   SimTime startTime;     /* When request was started */
   /* First level data */
   PA cmd;                  /* SCache command causing miss */
   VA vAddr;                /* Virtual address of miss */
   PA pAddr;                /* Phsyical address of miss */
   VA PC;                   /* PC causing miss */
#ifdef MIPSY_MXS
   int   cpu_action;	    /* Action to take when transaction completes */
   void *cpu_action_param;  /* An argument to pass */
#endif
   int ind;                  /* Index into the smallest cache */
   short lru;                /* First level cache LRU bit */

   struct {
      char data[128];
      char mask[128];
      int active;
   } *writeBuffer;

   /* Second level cache - usage */
   short smhtEntry;          /* SMHT entry for request. */
   int   mode;               /* Return mode. */
#define SECOND_LEVEL_HIT_ENTRY   -1
#define SECOND_LEVEL_INVALID_ENTRY -2
} MHT; 

#define ICACHE_TAG(a)         ((a) >> (iTagShift))
#define ICACHE_ONE_LINE(a)    ((a) >> (log2ICACHE_LINE_SIZE))
#define ITAG_TO_PA(t,i)       ((((t)*iAddrDivisor) + ((i)*ICACHE_LINE_SIZE)))
#define ICACHE_INDEXOF(a)     ((a>>log2ICACHE_LINE_SIZE) & (iIndexMask))

#define DCACHE_TAG(a)         ((a) >> (dTagShift))
#define DCACHE_TAG_EX(a)      (DCACHE_TAG(a)|EXCLUSIVE_TAG)
#define DCACHE_ONE_LINE(a)    ((a) >> (log2DCACHE_LINE_SIZE))
#define DTAG_TO_PA(t,i)       ((((~EXCLUSIVE_TAG)&(t))*(dAddrDivisor)) \
                               + ((i)*DCACHE_LINE_SIZE))
#define DCACHE_INDEXOF(a)     ((a>>log2DCACHE_LINE_SIZE) & (dIndexMask))

/* Figure out which word in an ICache line a VA refers to */
#define I_LINE_WORD(_va)      ((_va & iWordMask) >> 2)

typedef struct Cache { 

   struct ICache {
      struct ICacheSet {
         PA tags[ICACHE_ASSOC];
         uint LRU;
	 byte *data[ICACHE_ASSOC]; 
      } *set;  /* [ICACHE_INDEX]; */
   } ICache;

   struct DCache {
      struct DCacheSet {
         PA tags[DCACHE_ASSOC];
         uint LRU;
	 byte *data[DCACHE_ASSOC]; 
         struct FalseSharingEntry *fSharing[DCACHE_ASSOC];
      } *set; /*  [DCACHE_INDEX]; */
      int memSample;
   } DCache;

   MHT MHT[MHT_SIZE];
   int MHTnumInuse;            /* Number of active MHT entries */
   int activeWriteBuffers;

  struct { 

    SimCounter mhtOccupancyHist[MHT_SIZE+1];

    struct { 
      SimCounter Reads;
      SimCounter ReadMisses;
      SimCounter Inval;
      SimCounter LinesInval;
      SimCounter RetriedIGets;
      SimTime    BusOccupiedTime;
    } ICache;

    struct {
      SimCounter Reads;
      SimCounter Writes;
      SimCounter ReadMisses;
      SimCounter WriteMisses;
      SimCounter UpgradeMisses;
      SimCounter MergeMisses;
      SimCounter Writebacks;
      SimCounter Inval;
      SimCounter Downgrade;
      SimCounter LinesInval;
      SimCounter LinesWriteback;
      SimCounter WriteWriteStall;
      SimCounter WriteWriteHoldoff;
      SimCounter WriteHoldoffRetry;
      SimCounter RetriedDGets;
      SimCounter RetriedDGetXs;
      SimTime    BusOccupiedTime;
    } DCache;

  } stats;
}  Cache;

extern Cache *CACHE;

extern bool skipCaches;

extern unsigned long verboseDebugEnabled;
#ifdef DEBUG_DATA_VERBOSE
#define VERBOSE_DEBUG verboseDebugEnabled
#else
#define VERBOSE_DEBUG FALSE
#endif

#ifdef MIPSY_MXS
extern Result DCacheFetchShared(int cpuNum, VA vAddr, PA pAddr, int flags,
				char **dataPtr);
extern Result DCacheFetchExclusive(int cpuNum, VA vAddr, PA pAddr, int size,
				   char **dataPtr);

extern int MxsClassifyMiss(int cpuNum, VA vAddr, PA pAddr, bool isICache);

#endif

/* Interface from SCache */
extern void PrimaryFlush(int cpuNum, int writebackonly, int retain,
			 PA paddr, int size);
extern void MHTReqDone(int cpuNum, MHT *mht, int mode, int status);
extern void MHTReqDoneCallback(int cpuNum, EventCallbackHdr *hdr, void *arg);
extern void MHTRemoveReq(int cpuNum, PA  pAddr, int size);

/* Some shared functions for cache manipulation */
extern int SameCacheLine(PA addr1, PA addr2, unsigned cacheLineSize);
extern PA QuadWordAlign(PA offset);

/* This macro is here so we can experiment with shared caches */
#define GET_CACHE_NUM(_cpunum)  (_cpunum)

#endif /* _PCACHE_H */