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

📄 cache.c

📁 一个用在mips体系结构中的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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.  * *//**************************************************************** * cache.c *  * $Author: bosch $ * $Date: 1998/02/10 00:30:09 $ *****************************************************************/#include <bstring.h>#include <sys/types.h>#include <sys/mman.h>#include <unistd.h>#include <stdlib.h>#include "annotations.h"#include "embra.h"#include "cache.h"#include "directory.h"#include "decoder.h"#include "mem_control.h"#include "driver.h"#include "main_run.h"#include "qc.h"#include "translator.h"#include "clock.h"#include "callout.h"#include "stats.h"#include "hw_events.h"#include "simutil.h"#include "addr_layout.h"#ifdef MEM_ANNOTATIONS#include "annotations.h"#include "clock.h"#endif#include "addr_layout.h"#define NOT_LAST_IN_SLINE(_Addr) (((uint)(_Addr)+INST_SIZE) & (SCACHE_LINE_SIZE - 1 ))#define SCACHE_TAG_BASE_ADDR(_cpu) ((PLN*) \(CACHE_TAG_START + ((_cpu) * CACHE_TAG_SIZE) ) )  /* Replacement Hints are no longer implemented, but with     Directory_Elimitate they could be  *//* NOTE: these can not be used in parallel cache simulation *//*--------------------------------------*//* cache & qc_p/Physarray debug support *//* log all cache misses *//* #define LOG_MISS_ALL *//* log all misses on cacheline xxx, stop at PC, CC=EMP.cycleCount*//* #define LOG_MISS    #define STOP_PC 0x60007078   #define STOP_CC 305448   *//* count misses for every cacheline *//* #define DEBUG_PA *//* insert cache consistency checks *//* #define DEBUG_CACHE *//*--------------------------------------*/static void Cache_CommitRef(int cpuNum, PA pAddr, VA vAddr, PA pcPAddr,                            EmVQCMemState state, int flags);void cache_consistency_check( int cpuNum );/* Data Structures */static SimTime cachePrevInstrCount[SIM_MAXCPUS];#ifdef gone_cleanupstatic int lastMissState[SIM_MAXCPUS];static int64 lastInstrCount[SIM_MAXCPUS];#endifstatic int64 iCount;/* Miss handing table allocated in shared memory.  Only need 1 per CPU */EmSMHT *emSMHT;#ifdef DEBUG_PAint *misscount;#endifvoid Cache_Init( int cpuNum ){   int i;   if( embra.emode == EMBRA_PAGE ) {	  return;   }   /* Clear the cache */   if( embra.sequential ) {      int cpu;      for( cpu = 0; cpu<TOTAL_CPUS; cpu++) {         /* To bootstrap the cache miss strategy MPinUP */         emSMHT[cpu].state = MEM_I_SHARED;         emSMHT[cpu].pAddr = INVALID_TAG;         if (EMP[cpu].cache_tag ) continue;         EMP[cpu].cache_tag = (PLN*) ZALLOC_PERM(CACHE_TAG_SIZE,"EmbraTags");#ifdef DEBUG_PA         misscount = (int *) ZALLOC_PERM((sizeof(int)*LINES_PER_CACHE),"EmbraTags");#endif         CPUPrint("0x%x D CACHE_TAG_BASE_%d 0x%x\n",                   EMP[cpu].cache_tag, cpu,                  (uint)EMP[cpu].cache_tag + CACHE_TAG_SIZE );         for( i = 0; i < LINES_PER_CACHE; i++ ) {            EMP[cpu].cache_tag[i] = INVALID_TAG;#ifdef DEBUG_PA	    misscount[i]=0;#endif         }      }   } else {       ASSERT (0);   }}/* Called when another processor steals a line  *//* or called by EmbraDMAInval on a DMA transfer *//* Pass the directory entry, so we only clobber possible conflicts *//* Invalidate cache then pQC, then vQC because we have the directory   lock & therefore avoid race conditions */void Cache_Clobber( int machine, int cpuNum, PA pAddr, Dir_Entry cpu_bits,                     EmVQCMemState state ){   uint type = E_L2;    int i;    if (!VQC_EXCL(state) ) {      type |= E_DOWNGRADE;   }   ASSERT (!(cpu_bits>>cpuNum & 0x1));   for(i = FIRST_CPU(machine); i <= LAST_CPU(machine); i++ ) {       /*        * No transition on invalidating CPU and on downgrades!       */      if (i!=cpuNum && !(type&E_DOWNGRADE)) {          if (CACHE_PLINE( EMP[i].cache_tag[SCACHE_INDEXOF(pAddr)] ) ==             ADDR2SLINE( pAddr )) {  /* pAddr is in cache */            ASSERT ((cpu_bits>>i) & 0x1);            if (CACHE_SHARED(EMP[i].cache_tag[SCACHE_INDEXOF(pAddr)])) {               L2_LINE_TRANS_EVENT(i, pAddr,type | E_EXTERNAL | E_FLUSH_CLEAN,0,				   0,IS_KUSEG(EMP[i].PC));            } else {                L2_LINE_TRANS_EVENT(i, pAddr,type | E_EXTERNAL | E_WRITEBACK,0,				   0,IS_KUSEG(EMP[i].PC));            }        } else { #if should_work_does_not             ASSERT (!((cpu_bits>>i)&0x1));#endif            L2_LINE_TRANS_EVENT(i, pAddr,type | E_FAKE_EXTERNAL,0,0,                                IS_KUSEG(EMP[i].PC));         }      }      if( (cpu_bits>>i) & 0x1 ) {           if ( CACHE_PLINE( EMP[i].cache_tag[SCACHE_INDEXOF(pAddr)] ) ==              ADDR2SLINE( pAddr ) ){  /* pAddr is in cache */                      if( VQC_EXCL(state) ) {                EMP[i].cache_tag[SCACHE_INDEXOF(pAddr)] = INVALID_TAG;               /* If the intervener is getting exclusive control, then                  fail the subsequent sc */               if( ADDR2SLINE(EMP[i].LLAddr) ==                    ADDR2SLINE(PHYS_TO_MEMADDR(M_FROM_CPU(i), pAddr)) )                  EMP[i].LLAddr = 0;               {                  PA pPCAddr;                  uint pc = EMP[i].PC;                  pc = IN_BD(pc)?CLEAR_BD(pc)+INST_SIZE:pc;                  pPCAddr = K0_TO_PHYS( non_excepting_tv(i,pc) );                  if( ADDR2SLINE(pPCAddr) == ADDR2SLINE(pAddr) ) {                     /* Ballsy */                     EMP[i].jumpPC = (uint) continue_run_without_chaining;                  }               }            } else {               /* Downgrade doesn't invalidate chance of SC suceeding */               /* RG: external line transition to shared. Is downgrade                  ok if its state is already shared? I'll double check                  just to make sure */                              EMP[i].cache_tag[SCACHE_INDEXOF(pAddr)] =                  CACHE_SET_SHARED(CACHE_PLINE(EMP[i].cache_tag[SCACHE_INDEXOF(pAddr)]));            }            qc_clobber( pAddr, i, state );         }      }   } }/* This is called on a QC miss.  It drives all cache state transitions */void UPCache_Ref( int cpuNum,                  PA pAddr,                   VA vAddr,                   EmVQCMemState state ){   uint line_no           = SCACHE_INDEXOF( pAddr );   uint pline             = ADDR2SLINE(pAddr);   K0A  pcK0Addr          = non_excepting_tv(cpuNum, CLEAR_BD(EMP[cpuNum].PC));   PA   pcPAddr;   int pcConflict         = 0;   int miss_handling_time = 0;   uint type = E_L2;   if (VQC_SHARED(state)) {      type |= E_READ;   } else {      type |= E_WRITE;   }   ASSERT( NUM_CPUS(M_FROM_CPU(cpuNum)) == 1 );   /* Otherwise our PC is not mapped! */   ASSUME( pcK0Addr );   if( pcK0Addr ) {      /* We have to take action on a conflict if our PC is mapped data         reference and our PC map to the same line */      pcPAddr    = K0_TO_PHYS_REMAP( pcK0Addr, cpuNum );      pcConflict = ( !VQC_INST(state) ) &&         (line_no == SCACHE_INDEXOF( pcPAddr ) );   }#ifdef DEBUG_CACHE   static int miss_count;   miss_count++;   if( miss_count > 100000 && (miss_count % 10000) == 0 ) {      cache_consistency_check( cpuNum );   }#endif   /*******************/#ifdef COMMENTOUT   CPUPrint("Cache Entry PC 0x%x st 0x%x vAddr 0x%x pAddr 0x%x pline 0x%x ln %d ctag 0x%x\n",            EMP[cpuNum].PC,            state,            vAddr,            pAddr,            pline,            line_no            EMP[cpuNum].cache_tag[line_no] );#endif   if( pline == CACHE_PLINE( EMP[cpuNum].cache_tag[line_no] ) &&        CACHE_VALID( EMP[cpuNum].cache_tag[line_no] ) ) {      /* If permissions match, then its a cache hit, and vQC miss */      /* By above test cache_tag is valid, so only need to check excl */      VASSERT( !VQC_SHARED( state ) ||                CACHE_VALID( EMP[cpuNum].cache_tag[line_no] ),               ("State 0x%x, line_no %d pline 0x%x\n",                 state, line_no, pline) );      if( VQC_SHARED( state ) ||          ( VQC_EXCL( state) &&             CACHE_EXCL( EMP[cpuNum].cache_tag[line_no] ) ) ) {         /* real cache hit, vQC miss */         set_qc_state( cpuNum, ADDR2SLINE(vAddr), pline, state );         return;      } else {         /* Upgrade--Free on a uniprocessor */         /* RG upgrading from shared to exclusive. For a UP,            this is simply a transition.... */         CACHE_SINC( cpuNum, CURRENT_MODE(EMP), upgrades );         miss_handling_time += 0;#ifdef  LOG_MISS         if (line_no == LOG_MISS){            CPUPrint("Cache MISS-upgrade on %d , PC = %x, cycleCount = %lld\n",LOG_MISS,EMP[cpuNum].PC,EMP[cpuNum].cycleCount);         }#endif         goto accountingDone;      }   }   miss_handling_time += MEM_CYCLE_TIME;   ASSERT (MEM_CYCLE_TIME);   CACHE_INC( cpuNum, CURRENT_MODE(&EMP[cpuNum]), i_miss, d_miss, state );#ifdef  LOG_MISS   if (line_no == LOG_MISS)      CPUPrint("Cache MISS on %d , PC = %x, cycleCount = %lld\n",LOG_MISS,EMP[cpuNum].PC,EMP[cpuNum].cycleCount);   if ((EMP[cpuNum].PC==STOP_PC)&&(EmbraCpuCycleCount(cpuNum)==STOP_CC))       ASSERT(0);#endif      { #ifdef DEBUG_PA      misscount[line_no]++;#endif#ifdef LOG_MISS_ALL      CPUPrint("Cache MISS on %x , PC = %x, cycleCount = %lld\n",line_no,EMP[cpuNum].PC,EmbraCpuCycleCount(cpuNum));      if ((EMP[cpuNum].PC==STOP_PC)&&(EmbraCpuCycleCount(cpuNum)==STOP_CC))          ASSERT(0);#endif      /* RG Record the miss after the transition */      if( CACHE_VALID( EMP[cpuNum].cache_tag[line_no] ) ) {         /* RG: The current entry is booted, regardless of if it's            correct or not. */         uint type = E_L2;         uint oldAddr;                  if (CACHE_EXCL( EMP[cpuNum].cache_tag[line_no])) {            type |= E_WRITEBACK;         } else {            type |= E_FLUSH_CLEAN;         }                  /* Kick out previous line. Need to do a transition here */         oldAddr = SLINE2ADDR(CACHE_PLINE(EMP[cpuNum].cache_tag[line_no]));         L2_LINE_TRANS_EVENT(cpuNum,oldAddr,type, vAddr, 0,                             IS_KUSEG(EMP[cpuNum].PC));      }              if (VQC_INST(state)) {         L2_IMISS_EVENT( EmbraCpuCycleCount(cpuNum),                         cpuNum, vAddr, pAddr, miss_handling_time,                         type | E_I);       } else {         VA pc = CLEAR_BD(EMP[cpuNum].PC);               L2_DMISS_EVENT( EmbraCpuCycleCount(cpuNum),                         cpuNum, pc, vAddr, pAddr, miss_handling_time,                         type | E_D, 0);      }   }accountingDone:   /* If there is a previous entry in this line, kick it out */   if( CACHE_VALID( EMP[cpuNum].cache_tag[line_no] ) ) {      /* This could be an upgrade which means we are kicking out the         shared entry, but that is just redundant work, not incorrect */      if (embra.useVQC){         set_qc_state(                       cpuNum,                      PQC_VLINE(                                EMP[cpuNum].qc_p[                                            CACHE_PLINE(                                                        EMP[cpuNum].cache_tag[line_no])]),                      CACHE_PLINE( EMP[cpuNum].cache_tag[line_no] ),                       MEM_INVALID );      } else { /* !embra.useVQC */         set_qc_state(                       cpuNum,0,                      CACHE_PLINE( EMP[cpuNum].cache_tag[line_no] ),                       MEM_INVALID );      }   }   /* Set the qc entry and the cache tags. */   /* If we had a conflict then set the qc and tags to the I entry  */   /* XXX - This means that UP MUST return the */   /* address so the QC does not rewind (that will infinite loop) */   if( pcConflict &&        !IN_BD( EMP[cpuNum].PC )  &&       NOT_LAST_IN_SLINE( EMP[cpuNum].PC ) ) {      /* We have detected a conflict. Between the PC and the miss address. */      /* What should happen here is          1. PC line is present in cache         2. l/s is executed, cache miss and PC line evicted         3. l/s completes even though PC line is not in cache         4. If l/s in delay slot then l/s owns line, else          Imiss, and PC owns line         However, we don't emit an icache check after every l/s for         performance. Therefore, just count the I miss, and assign the         qc to the proper party         */      /* Data miss was charged earlier, charge I miss */      /* Going with what emmett says--charge I miss now.         Use original miss_handling time--don't charge twice. */      /* Transition to evict vaddr (data),         IMiss needs to bring in next pc +4.. */      if ( VQC_EXCL(state)) {         type = E_L2 | E_WRITEBACK;      } else {         type = E_L2 | E_FLUSH_CLEAN;      }

⌨️ 快捷键说明

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