📄 pcache.c
字号:
if ( !ICACHE_MISS_ALWAYS ) { if (set->tags[0] == tag) { ICACHE_TOUCH(set->LRU, 0); setindex=0; MS_INSTRUCTION_SET(cpuNum,0); QUICK_ICACHE_SET(cpuNum, pAddr, set, setindex); goto hit; }#if ICACHE_ASSOC > 1 if (set->tags[1] == tag) { ICACHE_TOUCH(set->LRU, 1); setindex=1; MS_INSTRUCTION_SET(cpuNum,1); QUICK_ICACHE_SET(cpuNum, pAddr, set, setindex); goto hit; }#endif#if ICACHE_ASSOC > 2 if (set->tags[2] == tag) { ICACHE_TOUCH(set->LRU, 2); setindex=2; MS_INSTRUCTION_SET(cpuNum,2); QUICK_ICACHE_SET(cpuNum, pAddr, set, setindex); goto hit; }#endif#if ICACHE_ASSOC > 3 if (set->tags[3] == tag) { ICACHE_TOUCH(set->LRU, 3); setindex=3; MS_INSTRUCTION_SET(cpuNum,3); QUICK_ICACHE_SET(cpuNum, pAddr, set, setindex); goto hit; }#endif } ret = ICacheMiss(cpuNum, vAddr, pAddr, &setindex); if (ret != SUCCESS) { return ret; } else { goto hit; }hit: MS_INSTRUCTION(cpuNum, pAddr); lineindex = pAddr & (ICACHE_LINE_SIZE-1); *inst = *(Inst *) (set->data[setindex] + lineindex); return SUCCESS;}/***************************************************************** * ICacheMiss * * XXX - Should make this virtually index, physically tagged. *****************************************************************/Result ICacheMiss(int cpuNum, VA vAddr, PA pAddr, int *setindex){ int cacheNum = GET_CACHE_NUM(cpuNum); int mhtind; int ind = ICACHE_INDEXOF(pAddr); int lru; MHTStatus mhtret; SCResult sret; if (VERBOSE_DEBUG) { CPUPrint("%d: ICacheMiss: VA: %8.8lx PA: %8.8lx\n",cpuNum, vAddr, pAddr); }#ifdef MIPSY_MXS if (!MxsApproveImiss(PE[cpuNum].st, pAddr)) { /* This means that the current Imiss could cause a previous load or * store to be aborted due to a coherency exception. We stall the * miss until the condition clears. This is a performance optimization * that becomes necessary if we speculate through SC instructions. */ return FAILURE; }#endif /* MIPSY_MXS */ /* * Check the second level cache for the line. Before we * record the miss in the ICache MHT entry make sure * this isn't a re-issued ICache miss from a CONFLICT case. */ lru = ICACHE_LRU(CACHE[cacheNum].ICache.set[ind].LRU); mhtret = AllocMHT(cpuNum, SC_IGET, vAddr, pAddr, ICACHE_LINE_SIZE, lru, &mhtind); switch (mhtret) { case MHTFULL: return FAILURE; case MHTCONFLICT: return FAILURE; case MHTMERGE: /* * This can occur if someone does a data acces to a line * and then jumps to it. */ return STALL; default: ASSERT(mhtret == MHTSUCCESS); break; } if (CACHE[cacheNum].ICache.set[ind].tags[lru] != INVALID_TAG) { uint type = E_L1 | E_I | E_READ | E_FLUSH_CLEAN; PA replPA = ITAG_TO_PA(CACHE[cacheNum].ICache.set[ind].tags[lru], ind); L1_LINE_TRANS_EVENT(cpuNum, replPA, type, lru, IS_KUSEG(CURRENT_PC(cpuNum))); } CACHE[cacheNum].ICache.set[ind].tags[lru] = INVALID_TAG; /* * Forward the request on to the secondary cache. */ sret = SCacheFetch(cpuNum, vAddr, pAddr, SC_IGET, mhtind); if (sret == SCRETRY) { /* * We must of conflicted with a data miss. Deallocate * MHT entry and stall waiting for the SMHT to clear up. * XXX - Should me reissue this ourselves? */ FreeMHT(cpuNum, mhtind); return FAILURE; } else { if (sret == SCBUSERROR) { FreeMHT(cpuNum, mhtind); return BUSERROR; } } /* Due to the MHT and the fact that the scache will call ICachePUT and will fill in the pcache, this routine will only be called on once on the miss to the icache line. */ CACHE[cacheNum].stats.ICache.ReadMisses++; if (sret == SCSTALL) { return STALL; } /* SCacheFetch may return SCSUCCESS if zero latency misses * are configured. Record this as a miss but don't stall. */ (*setindex) = lru; ASSERT(sret == SCSUCCESS); return SUCCESS;} /***************************************************************** * ICacheFlush *****************************************************************/void ICacheFlush(int cpuNum, PA paddr, int size){ int cacheNum = GET_CACHE_NUM(cpuNum); PA a; int ind; int set; QUICK_ICACHE_CLEAR(cpuNum); CACHE[cacheNum].stats.ICache.Inval++; for (a = paddr; a < paddr + size; a += ICACHE_LINE_SIZE) { ind = ICACHE_INDEXOF(a); if (CACHE[cacheNum].ICache.set[ind].tags[0] == ICACHE_TAG(a)) { set = 0; goto foundit; }#if ICACHE_ASSOC > 1 if (CACHE[cacheNum].ICache.set[ind].tags[1] == ICACHE_TAG(a)) { set = 1; goto foundit; }#endif#if ICACHE_ASSOC > 2 if (CACHE[cacheNum].ICache.set[ind].tags[2] == ICACHE_TAG(a)) { set = 2; goto foundit; }#endif#if ICACHE_ASSOC > 3 if (CACHE[cacheNum].ICache.set[ind].tags[3] == ICACHE_TAG(a)) { set = 3; goto foundit; }#endif continue; /* not found, go around loop */ foundit: CACHE[cacheNum].stats.ICache.LinesInval++; CACHE[cacheNum].ICache.set[ind].tags[set] = INVALID_TAG; ICACHE_MAKE_LRU(CACHE[cacheNum].ICache.set[ind].LRU, set); L1_LINE_TRANS_EVENT(cpuNum, a, (E_L1 | E_I | E_READ | E_EXTERNAL | E_FLUSH_CLEAN), 0, IS_KUSEG(CURRENT_PC(cpuNum))); }}/***************************************************************** * AllocMHT * * Allocate an entry in the miss handling table for the * specified first level miss. This routine is responsible for * checking for conflict and merge miss as well. *****************************************************************/static MHTStatusAllocMHT(int cpuNum, SCacheCmd cmd, VA vAddr, PA pAddr, int size, int lru, int *mhtind){ int cacheNum = GET_CACHE_NUM(cpuNum); int entry; int ind,cacheLineSize; if (cmd == SC_IGET) { ind = ICACHE_INDEXOF(pAddr); cacheLineSize = ICACHE_LINE_SIZE; } else { ind = DCACHE_INDEXOF(pAddr); cacheLineSize = DCACHE_LINE_SIZE; } ASSERT( size == cacheLineSize ); if (CACHE[cacheNum].MHTnumInuse == 0) { entry = 0; /* Special case for speed: allocate when MHT is empty */ } else { int numChecked = CACHE[cacheNum].MHTnumInuse; int i; entry = -1; for (i = 0; (i < MHT_SIZE) && numChecked; i++) { if (!CACHE[cacheNum].MHT[i].inuse) { entry = i; } else { numChecked--; if (CACHE[cacheNum].MHT[i].ind == ind) { if ( (cmd==SC_IGET && CACHE[cacheNum].MHT[i].cmd==SC_IGET) || (cmd!=SC_IGET && CACHE[cacheNum].MHT[i].cmd!=SC_IGET) ) { *mhtind = i; if (!SameCacheLine(CACHE[cacheNum].MHT[i].pAddr, pAddr, cacheLineSize)) { /* Currently we only support one miss per cache index */ return MHTCONFLICT; } /* Except we call them merges if two misses happen to the same * line */ if (CACHE[cacheNum].MHT[i].cmd != cmd) { /* Call it a conflict if we need a GETX and only a * GET is outstanding. */ return MHTCONFLICT; } return MHTMERGE; } } } } if (entry == -1) { if (i == MHT_SIZE) { /* MHT is full */ return MHTFULL; } else { entry = i; } } } CACHE[cacheNum].MHTnumInuse++; CACHE[cacheNum].MHT[entry].inuse = TRUE; CACHE[cacheNum].MHT[entry].startTime = CPUVec.CycleCount(cpuNum); CACHE[cacheNum].MHT[entry].cmd = cmd; CACHE[cacheNum].MHT[entry].vAddr = vAddr; CACHE[cacheNum].MHT[entry].pAddr = pAddr; CACHE[cacheNum].MHT[entry].PC = CURRENT_PC(cpuNum); CACHE[cacheNum].MHT[entry].ind = ind; CACHE[cacheNum].MHT[entry].lru = lru; CACHE[cacheNum].MHT[entry].writeBuffer->active = FALSE; *mhtind = entry;#ifdef MIPSY_MXS CACHE[cacheNum].MHT[entry].cpu_action = GetMxsAction (PE[cpuNum].st);#endif return MHTSUCCESS;} /***************************************************************** * FreeMHT - Delete a MHT entry * *****************************************************************/static voidFreeMHT(int cpuNum, int entryNum){ int cacheNum = GET_CACHE_NUM(cpuNum); ASSERT(CACHE[cacheNum].MHT[entryNum].inuse); CACHE[cacheNum].MHT[entryNum].inuse = 0; CACHE[cacheNum].MHTnumInuse--; ASSERT(CACHE[cacheNum].MHTnumInuse >= 0); ASSERT(CACHE[cacheNum].MHT[entryNum].writeBuffer->active == FALSE);}/***************************************************************** * ICachePUT * Since this is the ICache, no real writing. *****************************************************************/static voidICachePUT(int cpuNum, MHT *mht, int mode){ int result; int cacheNum = GET_CACHE_NUM(cpuNum); PA paddr = mht->pAddr; int ind = ICACHE_INDEXOF(paddr); PA tag = ICACHE_TAG(paddr); int lru = mht->lru; char *data; int way =0; ASSERT(mht->cmd & SC_IGET); ASSERT(CACHE[cacheNum].ICache.set[ind].tags[lru] == INVALID_TAG); /* NOTE: This call is no longer optional! We use it to find the scache line that will be used to satisfy the data part of the miss */ result = IsInSCache(cpuNum, paddr, MEMSYS_SHARED, &data, &way); if (!result) { CPUError("ICachePUT didn't find line in SCache (with IsInSCache())"); } CACHE[cacheNum].ICache.set[ind].tags[lru] = tag; #ifdef DATA_HANDLING CACHE[cacheNum].ICache.set[ind].data[lru] = data+((paddr&(SCACHE_LINE_SIZE-1)&~(PA)(ICACHE_LINE_SIZE-1))); /* Point L1 to data location in L2 */#else CACHE[cacheNum].ICache.set[ind].data[lru] = (byte*)CPUVec.PAToHostAddr(cpuNum, (paddr&~(PA)(ICACHE_LINE_SIZE-1)), 0);#endif}/***************************************************************** * MemRefReadData * Return values: * SUCCESS - Request hit in the cache, data returned. * STALL - Request missed in the cache, sent to the 2nd-level or memsys. * FAILURE - Request missed but couldn't be issued to 2nd-level or * memory system. Caller must retry. * BUSERROR - Request suffered a bus error. * * Main entry into 1st level data cache from CPU. *****************************************************************/Result MemRefReadData(int cpuNum, VA vAddr, PA pAddr, void *data, RefSize size, RefFlavor flavor){ int cacheNum = GET_CACHE_NUM(cpuNum); PA tag = DCACHE_TAG(pAddr); int ind = DCACHE_INDEXOF(pAddr); struct DCache *dcache = &CACHE[cacheNum].DCache; struct DCacheSet *set = &(dcache->set[ind]); Result ret; int lineindex; int setindex; if ( DCACHE_HIT_ALWAYS ) { setindex = 0; set->data[setindex] = (byte*)CPUVec.PAToHostAddr(cpuNum, pAddr&~(PA)(DCACHE_LINE_SIZE-1), vAddr); goto hit; } if ( !DCACHE_MISS_ALWAYS ) { if (((~EXCLUSIVE_TAG) & (set->tags[0])) == tag) { DCACHE_TOUCH(set->LRU, 0); setindex=0; goto hit; }#if DCACHE_ASSOC > 1 if (((~EXCLUSIVE_TAG) & (set->tags[1])) == tag) { DCACHE_TOUCH(set->LRU, 1); setindex=1; goto hit; }#endif#if DCACHE_ASSOC > 2 if (((~EXCLUSIVE_TAG) & (set->tags[2])) == tag) { DCACHE_TOUCH(set->LRU, 2); setindex=2; goto hit; }#endif#if DCACHE_ASSOC > 3 if (((~EXCLUSIVE_TAG) & (set->tags[3])) == tag) { DCACHE_TOUCH(set->LRU, 3); setindex=3; goto hit; }#endif } /* Cache misses go here */ if (VERBOSE_DEBUG) { CPUPrint("%d: Read D$ MISS VA: 0x%8.8lx PA: 0x%8.8lx\n", cpuNum, vAddr, pAddr); } ret = DCacheReadMiss(cpuNum, vAddr, pAddr, data, size, flavor, &setindex);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -