⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scache.c

📁 一个用在mips体系结构中的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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.  * *//***************************************************************** * scache.c * Secondary cache model *  * $Author: bosch $ * $Date: 1998/02/10 00:28:04 $ *****************************************************************/#include <assert.h>#include <malloc.h>#include "syslimits.h"#include "simutil.h"#include "sim_error.h"#include "scache.h"#include "memsys.h"#include "cpu_interface.h"#include "hw_events.h"#include "cpu_stats.h"#ifdef HWBCOPY#  include "hw_bcopy.h"#endif#include "arch_specifics.h"/* #define CC_CHECKER */#ifdef CC_CHECKERstatic int  CacheChecker(PA paddr, int cpuNum, int isExcl);#endif#if defined(SIM_MIPS32) || defined(SIM_MIPS64)extern int sim_magic_OSPC_access(int cpuNum, uint VA, byte *data);extern void sim_magic_OSPC_stalled(int cpuNum, uint VA, int stalled);/*#define DEBUG_OSPC_STALL*/#endif/* * Possible return status from the miss handling table. * SMHTSUCCESS - Entry allocated everything looks good. * SMHTMERGE   - This request merged with another. Returned other. * SMHTFULL    - Entry not allocated because table was full. * SMHTCONFLICT - Entry not allocated because it conflicted with one already *               allocated. */typedef enum { SMHTSUCCESS = 0, SMHTFULL, SMHTMERGE, SMHTCONFLICT} SMHTStatus;/* The second level caches for all of the processors */SCache *SCACHE;/* Local Functions */static void SCacheHitEvent(int cpuNum,EventCallbackHdr *event, void *arg);static SMHTStatus AllocSMHT(int cpuNum, MCMD mcmd, PA pAddr, int lru, int *smhtind);static void FreeSMHT(int cpuNum, int entryNum);static void SCacheUpdate(int cpuNum, SMHT *smht, int mode, int status,			 int result, byte *data);static FlushStatus SCacheFlush(int cpuNum, int writeback, int retain,			       PA pAddr, int size, byte *data);static SCResult SCacheUpgradeMiss(int cpuNum, VA vAddr, PA pAddr, SCacheCmd cmd, 				  int mhtind, int way, struct SCacheSet *set,				  SimCounter *missCntPtr);static SCResult SCacheMiss(int cpuNum, VA vAddr, PA pAddr, SCacheCmd cmd, int mhtind,			   struct SCacheSet* set, SimCounter *missCntPtr);static void SCacheLRUInit(uint *lruword);static void SCacheLRUMake(uint *lruword, int set);static int  SCacheLRU(uint lruword);static void SCacheLRUTouch(uint *lruword,int set);#ifdef DATA_HANDLINGstatic void DumpCacheLine(byte *data, int length);#endif/* Some shared functions for cache manipulation */int SameCacheLine(PA addr1, PA addr2, unsigned cacheLineSize);PA QuadWordAlign(PA offset);#define CURRENT_PC(_cpu) (CPUVec.CurrentPC(_cpu))/***************************************************************** * InitSCaches *****************************************************************/voidInitSCaches(void){   int i,j,k;#ifdef DATA_HANDLING   char *pool;#endif   SCACHE = (SCache *)calloc(TOTAL_CPUS,sizeof(SCache));    CPUPrint("SCACHE: Assoc = %d Size = %#x Line = %d HitTime %d\n",             SCACHE_ASSOC, SCACHE_SIZE, SCACHE_LINE_SIZE, SCACHE_HIT_TIME);      for (j=0; j < TOTAL_CPUS; j++) {      SCACHE[j].set = (struct SCacheSet *)	 calloc(SCACHE_INDEX, sizeof(struct SCacheSet));      if (SCACHE[j].set == NULL) {	 CPUError("calloc failed on scache allocation (%d bytes)\n",                  SCACHE_INDEX*sizeof(struct SCacheSet));      }#ifdef DATA_HANDLING      pool = (char *) calloc(SCACHE_LINE_SIZE * SCACHE_INDEX                              * SCACHE_ASSOC, sizeof(char));#endif       for (i=0; i < SCACHE_INDEX; i++) {	 for (k=0; k < SCACHE_ASSOC; k++) {	    SCACHE[j].set[i].tags[k] = INVALID_TAG;#ifdef DATA_HANDLING             {               if (pool == NULL) {                  CPUError("calloc failed on scache pool allocation\n");               }               /* Allocate the actual memory for the cache line's data */               SCACHE[j].set[i].data[k] = pool;               pool += SCACHE_LINE_SIZE;            }#endif         }	 SCacheLRUInit(&SCACHE[j].set[i].LRU);      }      for (i=0; i < SMHT_SIZE; i++) {	 SCACHE[j].SMHT[i].inuse = FALSE;      }      SCACHE[j].SMHTnumInuse = 0;   }}/***************************************************************** * SCacheFetch * * Process a first level cache miss. *****************************************************************/SCResultSCacheFetch(int cpuNum, VA vAddr, PA pAddr, SCacheCmd cmd, int mhtind){   struct SCacheSet*  set;   SimCounter *missCntPtr;   int way;   int cacheNum  = GET_CACHE_NUM(cpuNum);   int scacheNum = GET_SCACHE_NUM(cpuNum);   uint ind      = SCACHE_INDEXOF(pAddr);    PA tag        = SCACHE_TAG(pAddr);   if (interest(pAddr)) {      LogEntry("fetch",cpuNum,"pA=0%08x state=%d tag=0x%x foo=0x%x\n",pAddr,                MSCacheState(cpuNum, pAddr),tag,SCACHE[scacheNum].set[ind].tags[0]);   }   switch (cmd) {   case SC_IGET:      SCACHE[scacheNum].stats.Igets++;      missCntPtr = &SCACHE[scacheNum].stats.IgetMisses;      break;   case SC_DGET:   case SC_DLLGET:      SCACHE[scacheNum].stats.Dgets++;      missCntPtr = &SCACHE[scacheNum].stats.DgetMisses;#ifdef HWBCOPY      if ((SimConfigGetBool("Hwbcopy.Streaming")) &&          (SCACHE[scacheNum].get.last_index + 1) == ind) {        int run = ++SCACHE[scacheNum].get.consecutive;        int range = SimConfigGetInt("Hwbcopy.StreamRange");        int depth = SimConfigGetInt("Hwbcopy.StreamDepth");        int i;        for (i = 1; i < depth; i++) {           if ((run >= range*i) && (run <= range*(i+1))) {              PA pfAddr = pAddr + (i * SCACHE_LINE_SIZE);              VA vfAddr = vAddr + (i * SCACHE_LINE_SIZE);              if (IS_VALID_PA(M_FROM_CPU(cpuNum), pfAddr)) {                 SCACHE[scacheNum].stats.StreamGets[i]++;                 SCachePrefetch(cpuNum, vfAddr, pfAddr, MEMSYS_GET);              }           }        }        if (run >= range*depth) {           PA pfAddr = pAddr + (depth * SCACHE_LINE_SIZE);           VA vfAddr = vAddr + (depth * SCACHE_LINE_SIZE);           if (IS_VALID_PA(M_FROM_CPU(cpuNum), pfAddr)) {              SCACHE[scacheNum].stats.StreamGets[depth]++;              SCachePrefetch(cpuNum, vfAddr, pfAddr, MEMSYS_GET);           }        }      }      else if ((SCACHE[scacheNum].get.last_index) != ind)        SCACHE[scacheNum].get.consecutive = 0;      SCACHE[scacheNum].get.last_index = ind;#endif      break;   case SC_DGETX:   case SC_DLLGETX:      SCACHE[scacheNum].stats.DgetXs++;      missCntPtr = &SCACHE[scacheNum].stats.DgetXMisses;#ifdef HWBCOPY      if ((SimConfigGetBool("Hwbcopy.Streaming")) &&          (SCACHE[scacheNum].getx.last_index + 1) == ind) {        int run = ++SCACHE[scacheNum].getx.consecutive;        int range = SimConfigGetInt("Hwbcopy.StreamRange");        int depth = SimConfigGetInt("Hwbcopy.StreamDepth");        int i;        for (i = 1; i < depth; i++) {           if ((run >= range*i) && (run <= range*(i+1))) {              PA pfAddr = pAddr + (i * SCACHE_LINE_SIZE);              VA vfAddr = vAddr + (i * SCACHE_LINE_SIZE);              if (IS_VALID_PA(M_FROM_CPU(cpuNum), pfAddr)) {                 SCACHE[scacheNum].stats.StreamGetXs[i]++;                 SCachePrefetch(cpuNum, vfAddr, pfAddr, MEMSYS_GETX);              }           }        }        if (run >= range*depth) {           PA pfAddr = pAddr + (depth * SCACHE_LINE_SIZE);           VA vfAddr = vAddr + (depth * SCACHE_LINE_SIZE);           if (IS_VALID_PA(M_FROM_CPU(cpuNum), pfAddr)) {              SCACHE[scacheNum].stats.StreamGetXs[depth]++;              SCachePrefetch(cpuNum, vfAddr, pfAddr, MEMSYS_GETX);           }        }      }      else if ((SCACHE[scacheNum].getx.last_index) != ind)        SCACHE[scacheNum].getx.consecutive = 0;      SCACHE[scacheNum].getx.last_index = ind;#endif      break;   case SC_DUGETX:   case SC_DSCUGETX:      SCACHE[scacheNum].stats.Dupgrades++;      missCntPtr = &SCACHE[scacheNum].stats.DupgradeMisses;      break;   default:      CPUError("Unknown SC command 0x%x\n", cmd);      missCntPtr = 0;      break;   }/*   pAddr = pAddr & ~(PA)(SCACHE_LINE_SIZE-1);*/  set = & SCACHE[scacheNum].set[ind];  for( way=0;way<SCACHE_ASSOC;++way ) {     if((set->tags[way] & ~EXCLUSIVE_TAG) == tag) {        break;     }  }  if (way==SCACHE_ASSOC) {     /* A miss */     return SCacheMiss(cpuNum, vAddr, pAddr, cmd, mhtind, set, missCntPtr);  }  if ((cmd & EXCLUSIVE_CMD) &&      !(set->tags[way] & EXCLUSIVE_TAG)) {     if ((cmd == SC_DGETX) || (cmd == SC_DLLGETX)) {        /* A first level getx which requires an upgrade in the scache --  *         * change the statistics to record this as an upgrade, not a getx */        SCACHE[scacheNum].stats.DgetXs--;        SCACHE[scacheNum].stats.Dupgrades++;        missCntPtr = &SCACHE[scacheNum].stats.DupgradeMisses;     }     return SCacheUpgradeMiss(cpuNum, vAddr, pAddr, cmd, mhtind, way,			      set, missCntPtr);  }    if (VERBOSE_DEBUG) {      CPUPrint("%d: SCacheFetch: hit for %8.8lx\n",cpuNum,pAddr);   }   /* A hit in the second level, update LRU and PUT the line in the first    * level cache.    */    SCacheLRUTouch(&SCACHE[scacheNum].set[ind].LRU, way);      /*    * Return the line to the first level after the specified delay.    */   CACHE[cacheNum].MHT[mhtind].smhtEntry = SECOND_LEVEL_HIT_ENTRY;   if (set->tags[way] & EXCLUSIVE_TAG) {       CACHE[cacheNum].MHT[mhtind].mode = MEMSYS_EXCLUSIVE;    } else {       CACHE[cacheNum].MHT[mhtind].mode = MEMSYS_SHARED;    }   if (memsysVec.NoMemoryDelay || SCACHE_HIT_TIME == 0 || IN_MAGIC_SECTION(cpuNum)) {      MHTReqDone(cpuNum, CACHE[cacheNum].MHT + mhtind,                  CACHE[cacheNum].MHT[mhtind].mode,		 MEMSYS_STATUS_SUCCESS);      return SCSUCCESS;   } else {       EventDoCallback(cpuNum, SCacheHitEvent,		      (EventCallbackHdr *)(CACHE[cacheNum].MHT + mhtind),		      (void *)NULL, SCACHE_HIT_TIME);      return SCSTALL;   }}	 /***************************************************************** * SCacheMiss * 2nd level miss, forward to memory system. Start by allocating * space in the SMHT.  *****************************************************************/SCResultSCacheMiss(int cpuNum, VA vAddr, PA pAddr, SCacheCmd cmd, int mhtind,            struct SCacheSet* set, SimCounter *missCntPtr){   int cacheNum = GET_CACHE_NUM(cpuNum);   int scacheNum = GET_SCACHE_NUM(cpuNum);   PA replacePaddr;   int writeback;   MCMD mcmd;   int way;   int replace;   int waiter;   SMHTStatus ret;   Result mret;   int smhtind;   /* Quad-word align the miss */   pAddr = QuadWordAlign(pAddr);#ifndef SOLO   ASSERT (IS_VALID_PA(M_FROM_CPU(cpuNum), pAddr));#endif   /* Check if there are any lines marked INVALID and replace them    * rather than the LRU line     */    for (replace=0; replace<SCACHE_ASSOC; ++replace) {      if (set->tags[replace] & INVALID_TAG ) {         break;      }   }   if (replace == SCACHE_ASSOC) {      way = SCacheLRU(set->LRU);   } else {      way = replace;   }   mcmd = (cmd & EXCLUSIVE_CMD) ? MEMSYS_GETX : MEMSYS_GET;   if ((cmd == SC_DLLGET) || (cmd == SC_DLLGETX)) {      mcmd |= MEMSYS_LLFLAVOR;   }   if (cmd == SC_IGET) {      mcmd |= MEMSYS_IFFLAVOR;   }   ret = AllocSMHT(cpuNum, mcmd, pAddr, way, &smhtind);   if ((ret == SMHTFULL) || (ret == SMHTCONFLICT)) {      /*We've overrun or conflicted in the SMHT. Return        * a retry so we will try again.        */      if (VERBOSE_DEBUG) {         CPUPrint("%d: SCacheMiss:  VA: %8.8lx  PA: %8.8lx RETRY\n",                  cpuNum, vAddr, pAddr);      }      /* NOTE: I've already counted this reference as a L2 Ref. To make         the stats work, I need a count of these gets that have to         retry since the retry doesn't show up as an L1 Miss. */      switch (cmd) {      case SC_IGET:        SCACHE[scacheNum].stats.IGetMHTRetries++;        break;      case SC_DGET:      case SC_DLLGET:        SCACHE[scacheNum].stats.DGetMHTRetries++;        break;      case SC_DGETX:      case SC_DLLGETX:        SCACHE[scacheNum].stats.DGetXMHTRetries++;        break;      case SC_DUGETX:      case SC_DSCUGETX:        SCACHE[scacheNum].stats.DUGetXMHTRetries++;        break;      default:        CPUWarning("Bad cmd found at SMHT conflict\n");        ASSERT(0);      }      return SCRETRY;   }   ASSERT((ret == SMHTSUCCESS) || (ret == SMHTMERGE));	    /*    * Add the MHT entry to the lists of entries waiting    * for the line to be filled or upgraded.    */   ASSERT(SCACHE[scacheNum].SMHT[smhtind].numMHTwait < MHT_SIZE);   waiter = SCACHE[scacheNum].SMHT[smhtind].numMHTwait++;   SCACHE[scacheNum].SMHT[smhtind].mhtInd[waiter] = mhtind;   SCACHE[scacheNum].SMHT[smhtind].vAddr = vAddr;   CACHE[cacheNum].MHT[mhtind].smhtEntry = smhtind;   if (ret == SMHTMERGE) {      /*       * This line already has an outstanding miss of the right       * type.  Merge into it.       */      if (VERBOSE_DEBUG) {         CPUPrint("%d: SCacheMiss:  VA: %8.8lx  PA: %8.8lx MERGE\n",                  cpuNum, vAddr, pAddr);      }      SCACHE[scacheNum].stats.MergeMisses++;      return SCSTALL;   }   /* Now we need to allocate clear out space in the cache    * for it. If the entry we choose is valid we flush    * it from the primary cache(s). We pass the replaced    * address to the memory system so it can simulated writebacks    * and replacement hints, etc.     */    if (VERBOSE_DEBUG) {      CPUPrint("%d: SCacheMiss:  VA: %8.8lx  PA: %8.8lx\n",cpuNum, vAddr, pAddr);   }   if (!(set->tags[way] & INVALID_TAG)) {      replacePaddr = STAG_TO_PA(set->tags[way],set-SCACHE[scacheNum].set);      writeback = ((set->tags[way] & EXCLUSIVE_TAG) != 0);#ifndef SOLO      ASSERT (IS_VALID_PA(M_FROM_CPU(cpuNum), replacePaddr));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -