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

📄 cache.c

📁 一个用在mips体系结构中的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
      L2_LINE_TRANS_EVENT(cpuNum, pAddr, type, EMP[cpuNum].PC, 0,                          IS_KUSEG(EMP[cpuNum].PC));      L2_IMISS_EVENT( EmbraCpuCycleCount(cpuNum) + miss_handling_time,                      cpuNum, EMP[cpuNum].PC, pcPAddr, miss_handling_time,                      type | E_I);       miss_handling_time += MEM_CYCLE_TIME;      CACHE_INC( cpuNum, CURRENT_MODE(&EMP[cpuNum]), i_miss, d_miss, MEM_I_SHARED );         /* Set the data QC to inaccessible */      set_qc_state( cpuNum, ADDR2SLINE(vAddr), pline, MEM_INVALID );      /* No need to CLEAR_BD */      /* Set the instr QC to accessible */      set_qc_state( cpuNum, ADDR2SLINE(CLEAR_BD(EMP[cpuNum].PC)),                     ADDR2SLINE(pcPAddr),                     MEM_I_SHARED );      EMP[cpuNum].cache_tag[line_no] = CACHE_SET_SHARED( ADDR2SLINE(pcPAddr) );   } else {      /* Set the new line's quick check to the proper, accesible state */      /* Note that this invalidates phys_info[pline].virt_line */      /* Since the new entry could be the same as the old ( like on an */      /* upgrade the invalidate happens first */      set_qc_state( cpuNum, ADDR2SLINE(vAddr), pline, state );      /* Update Mshade tags */      if( VQC_SHARED( state ) ) {         EMP[cpuNum].cache_tag[line_no] = CACHE_SET_SHARED( pline );         /* RG here are the transitions... */      } else {         ASSERT( VQC_EXCL( state ) );         EMP[cpuNum].cache_tag[line_no] = CACHE_SET_EXCL( pline );         /* RG here are the transitions... */      }   }   EMP[cpuNum].cycleCountdown -= miss_handling_time;   CACHE_INC_BY(cpuNum, CURRENT_MODE(&EMP[cpuNum]),                 i_stall_cyc, d_stall_cyc, state,                miss_handling_time );}void MPinUPCache_Ref( int cpuNum,                       PA pAddr,                       VA vAddr,                       EmVQCMemState state ){   uint pline             = ADDR2SLINE(pAddr);   uint line_no           = SCACHE_INDEXOF(pAddr);   int smht_flags         = 0;   int miss_handling_time = 0;   MA  maPCAddr           = 0;     if (interest(pAddr)) {      LogEntry("ref",cpuNum,"pAddr=%08x state=%x msstate=%d \n",pAddr,state,               MSCacheState(cpuNum,pAddr));   }   /* no sc in delay slot */   if( !IN_BD( EMP[cpuNum].PC ) ){      maPCAddr =         K0_TO_MEMADDR(M_FROM_CPU(cpuNum),                       non_excepting_tv(cpuNum,EMP[cpuNum].PC));      ASSERT(maPCAddr);      if( MAJOR_OPCODE(*(uint*)maPCAddr) == sc_op ) {         smht_flags |= SMHT_SC;      }   } else {      smht_flags |= SMHT_BD;   }   if( pline == CACHE_PLINE( EMP[cpuNum].cache_tag[line_no] ) &&        CACHE_VALID( EMP[cpuNum].cache_tag[line_no] ) ) {      /* If permissions match, then this is a real cache hit, and a qc */      /* 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 %d, line_no %d\n", state, line_no) ); */      if( VQC_SHARED( state ) ||          ( VQC_EXCL( state) &&             CACHE_EXCL( EMP[cpuNum].cache_tag[line_no] ) ) ) {         /* Cache hit */         /* Update qc to present access status.  I could do this based            on the cache tag value, but why bother? */         set_qc_state( cpuNum, ADDR2SLINE(vAddr), pline, state );         if (interest(pAddr)) {            LogEntry("ref_qc",cpuNum,"pAddr=%08x state=%x msstate=%d\n",pAddr,state,                     MSCacheState(cpuNum,pAddr));         }                return;      } else {         /* Upgrade */         smht_flags |= SMHT_UPGRADE;         if (interest(pAddr)) {            LogEntry("ref_upg",cpuNum,"pAddr=%08x state=%x msstate=%d\n",pAddr,state,                     MSCacheState(cpuNum,pAddr));         }         /* Remove xfer time */         miss_handling_time += UPGRADE_TIME;         goto accountingDone;      }   }   miss_handling_time += MEM_CYCLE_TIME;accountingDone:#ifdef notdef   CPUPrint("R %d %-4lld 0x%-8x VA 0x%-8x PA 0x%-8x 0x%-2x\n",          cpuNum,          EmbraCpuInstrCount(cpuNum),          EMP[cpuNum].PC,          vAddr,pAddr, state);#endif   iCount = EmbraCpuInstrCount(cpuNum);   ASSERT( iCount >= cachePrevInstrCount[cpuNum]);   cachePrevInstrCount[cpuNum] = iCount;/*  * XXX Emmett has this commented out, but told me to execute it. (ed) *//* do we need this ? */#ifdef notdef     if( !iCount ) {      /* Update vQC and cache tags */      Cache_CommitRef( cpuNum, pAddr, vAddr, 0, state, smht_flags);      if( interest(pAddr)) {          LogEntry("cc_ref_0",cpuNum,"pAddr=%08x state=%x msstate=%d\n",pAddr,state,                  MSCacheState(cpuNum,pAddr));      }   }#endif   if( emSMHT[cpuNum].iCount == iCount ) {      /* Commit the previous reference */#ifdef notdef        CPUPut("EMBRA SMHT %d %-4lld 0x%-8x VA 0x%-8x PA 0x%-8x 0x%-2x 0x%-8x PA 0x%-8x 0x%-2x\n",             cpuNum,             emSMHT[cpuNum].iCount,             EMP[cpuNum].PC,             emSMHT[cpuNum].vAddr,             emSMHT[cpuNum].pAddr,             emSMHT[cpuNum].state,             vAddr,             pAddr,             state);#endif      if( !( VQC_INST( emSMHT[cpuNum].state ) &&             VQC_DATA(state)) ) {         /* ASSERT(!iCount || state == emSMHT[cpuNum].state);*/         if (emSMHT[cpuNum].pAddr != INVALID_TAG) {             Cache_CommitRef(cpuNum,                             emSMHT[cpuNum].pAddr,                             emSMHT[cpuNum].vAddr,                             emSMHT[cpuNum].pcPAddr,                            (EmVQCMemState)emSMHT[cpuNum].state,                            emSMHT[cpuNum].smht_flags);                        /*             * We used the MHT, now get rid of it (ed)              */            if (interest(emSMHT[cpuNum].pAddr)) {                LogEntry("cc_ref_1",cpuNum,"pAddr=%08x state=%x msstate=%d\n",pAddr,state,                        MSCacheState(cpuNum,emSMHT[cpuNum].pAddr));                }             emSMHT[cpuNum].pAddr = INVALID_TAG;         }         if( VQC_DATA(state) ) {            if( !(smht_flags & SMHT_BD) ){               if( NOT_LAST_IN_SLINE(EMP[cpuNum].PC) ){                  /* not in bd and NLISL means not last on page */                  PA pPCAddr = MEMADDR_TO_PHYS(M_FROM_CPU(cpuNum),                                               maPCAddr) + INST_SIZE;                   uint tag = EMP[cpuNum].cache_tag[SCACHE_INDEXOF(pPCAddr)];                  /* if( line_no == SCACHE_INDEXOF(MEMADDR_TO_PHYS(maPCAddr)) ){ */                   if( !CACHE_VALID(tag) ||                      CACHE_PLINE(tag) != ADDR2SLINE(pPCAddr) ) {                                          EMP[cpuNum].cycleCountdown -= MEM_CYCLE_TIME;                      smht_flags = 0;                      if( MAJOR_OPCODE(*(uint*)(maPCAddr + INST_SIZE)) == sc_op )                         smht_flags = SMHT_SC;                      Cache_CommitRef( cpuNum,                                      pPCAddr,                                      /* dref completed and we are not in bd */                                      EMP[cpuNum].PC + INST_SIZE,                                      0,                                      MEM_I_SHARED,                                      smht_flags);                     emSMHT[cpuNum].iCount++;                     emSMHT[cpuNum].state = MEM_I_SHARED;                     if (interest(EMP[cpuNum].PC + INST_SIZE)) {                         LogEntry("cc_ref_2",cpuNum,"pAddr=%08x state=%x msstate=%d\n",                                 EMP[cpuNum].PC + INST_SIZE ,state,                                 MSCacheState(cpuNum,EMP[cpuNum].PC + INST_SIZE));                          }                  }               }            }         }         if (interest(pAddr)) {            LogEntry("refret",cpuNum,"pAddr=%08x state=%x msstate=%d\n",pAddr,state,                     MSCacheState(cpuNum,pAddr));         }         return;      }   }   EMP[cpuNum].cycleCountdown -= miss_handling_time;   if( (EMP[cpuNum].blockCycleCountdown - miss_handling_time) <= 0 ) {      if( !(smht_flags & SMHT_BD) ) {         emSMHT[cpuNum].pAddr   = pAddr;         emSMHT[cpuNum].vAddr   = vAddr;         emSMHT[cpuNum].pcPAddr = 0;         emSMHT[cpuNum].state   = state;         emSMHT[cpuNum].smht_flags   = smht_flags;         emSMHT[cpuNum].iCount  = iCount;         EMP[cpuNum].jumpPC = (uint)continue_run_without_chaining;         if (interest(pAddr)) {            LogEntry("ref_tc",cpuNum,"pAddr=%08x state=%x msstate=%d\n",pAddr,state,                     MSCacheState(cpuNum,pAddr));         }              ReenterTC_CX(&EMP[cpuNum]);         /* NOT REACHED */      }   }   /* Update vQC and cache tags */   Cache_CommitRef( cpuNum, pAddr, vAddr, 0, state, smht_flags);   emSMHT[cpuNum].iCount = iCount;   if (interest(pAddr)) {      LogEntry("refend",cpuNum,"pAddr=%08x state=%x msstate=%d \n",pAddr,state,               MSCacheState(cpuNum,pAddr));   }}#ifdef OLD_VERSION_EBvoid MPinUPCache_Ref_old( int cpuNum,                       PA pAddr,                       VA vAddr,                       EmVQCMemState state ){   uint line_no           = SCACHE_INDEXOF( pAddr );   uint pline             = ADDR2SLINE(pAddr);   VA   vpc               = CLEAR_BD(EMP[cpuNum].PC);   K0A  pcK0Addr          = non_excepting_tv(cpuNum, CLEAR_BD(EMP[cpuNum].PC));   PA   pcPAddr;   int smht_flags         = 0;   int miss_handling_time = 0;   int cx_me              = 0;      /* Otherwise our PC is not mapped! */   ASSUME( pcK0Addr );   if( pcK0Addr ) {      if( MAJOR_OPCODE( *(uint*)K0_TO_MEMADDR( M_FROM_CPU(cpuNum),                                               pcK0Addr ) ) == sc_op ) {         smht_flags |= SMHT_SC;      }      pcPAddr    = K0_TO_PHYS_REMAP( pcK0Addr, cpuNum );      if( ( !VQC_INST(state) ) &&          (line_no == SCACHE_INDEXOF( pcPAddr ) ) ) {         /* PC and data ref map to same cache line */         smht_flags |= SMHT_PCCONFLICT;      }   }   if( pline == CACHE_PLINE( EMP[cpuNum].cache_tag[line_no] ) &&        CACHE_VALID( EMP[cpuNum].cache_tag[line_no] ) ) {      /* If permissions match, then this is a real cache hit, and a qc */      /* 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 %d, line_no %d\n", state, line_no) ); */      if( VQC_SHARED( state ) ||          ( VQC_EXCL( state) &&             CACHE_EXCL( EMP[cpuNum].cache_tag[line_no] ) ) ) {         /* Cache hit */         /* Update qc to present access status.  I could do this based            on the cache tag value, but why bother? */         set_qc_state( cpuNum, ADDR2SLINE(vAddr), pline, state );         return;      } else {         /* Upgrade */         smht_flags |= SMHT_UPGRADE;         miss_handling_time += UPGRADE_TIME;         goto accountingDone;      }   }   miss_handling_time += MEM_CYCLE_TIME;accountingDone:   /* XXX - Lasciate ogni speranza      If the cost of handling the miss, plus the rest of the      instructions in the block is larger than the current quantum,      then we should context switch and let more time pass.  There are      a couple of exceptions      1. Translator/pc_tc lookup can't deal with delay slot instructions      2. Give priority to sc that can succeed, otherwise livelock      3. Livelock can still occur.  Livelock is detected by multiple      misses without the instruction count increasing.  There are two      cases--an intra-cpu conflict or an inter-cpu conflict.      Notes:      cx  - processor context switch      ret - return to emitted code, allowing reference to succeed,            independent of vQC state      I assume that processor timeQuantum < MemCycleTime      XXX - I assume direct mapped cache      a. Intra-cpu conflict--this is a pc/data conflict.      Note: pc/data conflicts in the delay slot or on the last      instruction of a cache line are not conflicts.      Reality: data miss, then the instr miss on the next instruction      (if that is in the same line as the data ref, and we are not in      a delay slot).      Simulator (format--action, cache simulator response):      data miss        cx      instr miss (guaranteed b/c of cx) part I        charge & set QC only if !BD(pc) && NOT_LAST_IN_SLINE(pc) & ret      data miss part II        no charge, don't set QC & ret      Detection: part I  data then instr miss                 part II instr then data miss      Problem: If a line branches back to itself, we do not register      the miss.  This is solved by having lines branch back to      their icache check.      b. Inter-cpu conflict--e.g. two cpus want the same line, at      least one of them exclusively      Reality: p1 data miss, p2's data miss, p1 succeeds/advances pc      Simulator:      p1 i|d shared miss        cx      p2 data excl miss        cx      p1 (i|d) shared miss        no charge, set QC, ret      Detection: last_miss_state == this_miss_state      Note, p1's first reference could be data, and its second could      be instr (indicating both an intra and inter cpu conflict), in      that case, intra-cpu processing is still correct      4. Final wrinkle--Intra-cpu conflicts that are possibly      successful sc instructions can't cx the processor       Reality: see 3a      Simulator:      data miss        charge data,         if !BD(pc) && !NOT_LAST_IN_SLINE          charge instr, set QC to instr        ret      */   iCount = EmbraCpuInstrCount(cpuNum);   if( lastInstrCount[cpuNum] != iCount ) {      if( (EMP[cpuNum].blockCycleCountdown - miss_handling_time) < 0 &&          !IN_BD(EMP[cpuNum].PC) ) {          if( !(smht_flags & SMHT_SC) || EMP[cpuNum].LLAddr == 0){             cx_me = 1;          } else {             if( smht_flags & SMHT_PCCONFLICT ) {                /* ASSERT( !IN_BD(EMP[cpuNum].PC ); */                if( NOT_LAST_IN_SLINE(EMP[cpuNum].PC) ){                   /* This is to catch case 4 */                   smht_flags |= SMHT_DOUBLECOUNT;                   miss_handling_time += MEM_CYCLE_TIME;                }             }          }      }   } else {      if( lastMissState[cpuNum] == state ) {         /* Inter-cpu conflict */         miss_handling_time = 0;      } else {         if( VQC_DATA(lastMissState[cpuNum]) &&             VQC_INST(state) ) {            /* Intra-cpu conflict part I (possibly inter-cpu conflict) */            uint pc = EMP[cpuNum].PC;            if( IN_BD(pc) || !NOT_LAST_IN_SLINE(pc) ){               /* Spurious callout--no ireference in reality */               lastMissState[cpuNum] = MEM_INVALID;               return;            }         } else {            if( VQC_INST(lastMissState[cpuNum]) &&                VQC_DATA(state) ) {               /* Intra-cpu conflict part II */               /* Spurious callout--no dreference in reality */               lastMissState[cpuNum] = MEM_INVALID;               return;            }         }      }   }   /* If this is a real miss, count it and charge stall time */   if( miss_handling_time ) {      uint type = E_L2;            if (VQC_SHARED(state)) {         type |= E_READ;      } else {         type |= E_WRITE;      }            EMP[cpuNum].cycleCountdown -= miss_handling_time;      if( smht_flags & SMHT_UPGRADE ) {         CACHE_SINC( cpuNum, CURRENT_MODE(&EMP[cpuNum]), upgrades );

⌨️ 快捷键说明

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