📄 pcache.c
字号:
if (ret != SUCCESS) { return ret; } else { ASSERT(setindex >=0 && setindex < DCACHE_ASSOC); goto hit; }hit: if ( !DCACHE_HIT_ALWAYS ) { if (useWriteBuffer && AddrIsInWriteBuffer(cpuNum, pAddr, size)) { /* * We currently don't implement any kind of load bypassing so * we stall when a load hits a buffered write word. */ return STALL; } } DATA_READ_EVENT(); FALSE_SHARING_ACCESS(cpuNum,set->fSharing[setindex],pAddr); lineindex = pAddr & (DCACHE_LINE_SIZE-1); switch (size) { case WORD_SZ: *(int *) data = *(int *) (set->data[setindex] + lineindex); if (VERBOSE_DEBUG) { CPUPrint("%d: Read D$ hit VA: 0x%8.8lx PA: 0x%8.8lx WORD data: 0x%8.8lx lineindex=%d\n", cpuNum, vAddr, pAddr, *(int *) (set->data[setindex] + lineindex), lineindex); } break; case BYTE_SZ: *(byte *) data = *(byte *) (set->data[setindex] + lineindex); if (VERBOSE_DEBUG) { CPUPrint("%d: Read D$ hit VA: 0x%8.8lx PA: 0x%8.8lx BYTE data: 0x%2.2x lineindex=%d\n", cpuNum, vAddr, pAddr, *(char *) (set->data[setindex] + lineindex), lineindex); } break; case HALF_SZ: *(short *) data = *(short *) (set->data[setindex] + lineindex); if (VERBOSE_DEBUG) { CPUPrint("%d: Read D$ hit VA: 0x%8.8lx PA: 0x%8.8lx HALF data: 0x%8.8lx lineindex=%d\n", cpuNum, vAddr, pAddr, *(short *) (set->data[setindex] + lineindex), lineindex); } break; case DOUBLE_SZ: *(uint64 *) data = *(uint64 *) (set->data[setindex] + lineindex); if (VERBOSE_DEBUG) {#ifdef __alpha CPUPrint("%d: Read D$ hit VA: 0x%8.8lx PA: 0x%8.8lx DOUBLE data: 0x%16.16lx lineindex=%d\n", cpuNum, vAddr, pAddr, *(uint64 *) (set->data[setindex] + lineindex), lineindex);#else CPUPrint("%d: Read D$ hit VA: 0x%8.8lx PA: 0x%8.8lx DOUBLE data: 0x%16.16llx\n", cpuNum, vAddr, pAddr, *(uint64 *) (set->data[setindex] + lineindex));#endif } break; default: CPUError("Bad size %d passed to ReadDCache\n", size); break; } return SUCCESS;}/***************************************************************** * DCacheReadMiss * *****************************************************************/static Result DCacheReadMiss(int cpuNum, VA vAddr, PA pAddr, void *data, RefSize size, RefFlavor flavor, int *indPtr){ PA writebackAddr; int cacheNum = GET_CACHE_NUM(cpuNum); int ind = (pAddr/DCACHE_LINE_SIZE) % DCACHE_INDEX; int mhtind; int lru; SCacheCmd cmd; MHTStatus mhtret; SCResult sret; if (noUpgrades) { cmd = (flavor == LL_FLAVOR ? SC_DLLGETX : SC_DGETX); } else { cmd = (flavor == LL_FLAVOR ? SC_DLLGET : SC_DGET); } lru = DCACHE_LRU(CACHE[cacheNum].DCache.set[ind].LRU); mhtret = AllocMHT(cpuNum, cmd, vAddr, pAddr, DCACHE_LINE_SIZE, lru, &mhtind); switch (mhtret) { case MHTFULL: return FAILURE; case MHTCONFLICT: return FAILURE; case MHTMERGE: (*indPtr) = mhtind; return STALL; default: ASSERT(mhtret == MHTSUCCESS); break; } if (VERBOSE_DEBUG) { CPUPrint("%d: DCacheReadMiss: VA: %8.8lx PA: %8.8lx\n",cpuNum, vAddr, pAddr); } if (CACHE[cacheNum].DCache.set[ind].tags[lru] & EXCLUSIVE_TAG) { CACHE[cacheNum].stats.DCache.Writebacks++;#ifdef DATA_HANDLING { int way; char *scacheData; /* Generate writeback address */ writebackAddr = DTAG_TO_PA(CACHE[cacheNum].DCache.set[ind].tags[lru], ind); if (!(IsInSCache(cacheNum, writebackAddr, MEMSYS_EXCLUSIVE, &scacheData, &way))) { CPUError("DCacheReadMiss didn't find excl. line in SCache for WB"); } }#endif { uint type = E_L1 | E_D | E_READ | E_WRITEBACK; PA replPA = DTAG_TO_PA(CACHE[cacheNum].DCache.set[ind].tags[lru], ind); L1_LINE_TRANS_EVENT(cpuNum, replPA, type, lru, IS_KUSEG(CURRENT_PC(cpuNum))); } } else { if (!(CACHE[cacheNum].DCache.set[ind].tags[lru] & INVALID_TAG)) { /* Generate "replacement" address */ writebackAddr = DTAG_TO_PA(CACHE[cacheNum].DCache.set[ind].tags[lru], ind); if (VERBOSE_DEBUG) { CPUPrint("%d: dcache discarding clean line %8.8lx\n", cpuNum,writebackAddr); } } if (!(CACHE[cacheNum].DCache.set[ind].tags[lru] & INVALID_TAG)) { uint type = E_L1 | E_D | E_READ | E_FLUSH_CLEAN; PA replPA = DTAG_TO_PA(CACHE[cacheNum].DCache.set[ind].tags[lru], ind); L1_LINE_TRANS_EVENT(cpuNum, replPA, type, lru, IS_KUSEG(CURRENT_PC(cpuNum))); } } CACHE[cacheNum].DCache.set[ind].tags[lru] = INVALID_TAG; sret = SCacheFetch(cpuNum, vAddr, pAddr, cmd, mhtind); if (sret == SCRETRY) { /* * We must of conflicted with a data miss. Clean MHT and * stall. * XXX should we reissue this ourselves? */ FreeMHT(cpuNum, mhtind); return FAILURE; } else if (sret == SCBUSERROR) { FreeMHT(cpuNum, mhtind); return BUSERROR; } CACHE[cacheNum].stats.DCache.ReadMisses++; if (sret == SCSTALL) { (*indPtr) = mhtind; return STALL; } /* * SCacheFetch may return SUCCESS if zero latency misses * are configured. Record this as a miss but don't stall. */ (*indPtr) = lru; return SUCCESS;}/***************************************************************** * DCachePUT *****************************************************************/static voidDCachePUT(int cpuNum, MHT *mht, int mode){ int cacheNum = GET_CACHE_NUM(cpuNum); PA pAddr = mht->pAddr; int ind = DCACHE_INDEXOF(pAddr); int lru = mht->lru; int way = 0; PA tag = DCACHE_TAG(pAddr); char *data; /* 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 */ if (!(IsInSCache(cpuNum, pAddr, mode, &data, &way))) { CPUError("DCachePUT didn't find line in SCache (with IsInSCache())"); } if (mode & MEMSYS_EXCLUSIVE) tag |= EXCLUSIVE_TAG; if (mht->cmd == SC_DSCUGETX && (CACHE[cacheNum].DCache.set[ind].tags[lru] & INVALID_TAG)) { CPUVec.ClearLockFlag(cpuNum); /* SC fails due to a race */ } /* We don't want to copy data if it is already in the DCache * exclusive. */ if (!((CACHE[cacheNum].DCache.set[ind].tags[lru] & EXCLUSIVE_TAG) && ((CACHE[cacheNum].DCache.set[ind].tags[lru] & ~EXCLUSIVE_TAG) == (tag & ~EXCLUSIVE_TAG)))) { CACHE[cacheNum].DCache.set[ind].tags[lru] = tag; #ifdef DATA_HANDLING CACHE[cacheNum].DCache.set[ind].data[lru] = data+((pAddr&(SCACHE_LINE_SIZE-1)&~(PA)(DCACHE_LINE_SIZE-1))); /* Point L1 to data location in L2 */#else CACHE[cacheNum].DCache.set[ind].data[lru] = (byte*)CPUVec.PAToHostAddr(cpuNum, pAddr&~(PA)(DCACHE_LINE_SIZE-1), mht->vAddr);#endif CACHE[cacheNum].DCache.set[ind].fSharing[lru] = SCacheLineToFalseSharing(cacheNum,pAddr,way); } if (mht->writeBuffer->active) { ASSERT(CACHE[cacheNum].DCache.set[ind].tags[lru] & EXCLUSIVE_TAG); RetireWriteBuffer(cpuNum, mht, CACHE[cacheNum].DCache.set[ind].data[lru]); } DCACHE_TOUCH(CACHE[cacheNum].DCache.set[ind].LRU, lru); }/*************************************************************** * DCacheFlush * * This routine now takes two parameters: writeback and discard. * Writeback: Should I write the line back to the scache if * it is dirty? * Retain: After this call, should the line be retained in my * cache? (If the line was exclusive and writeback * is set, the line is downgraded to Shared). * * NOTE: writeback==0 && retain==1 is effectively a NOP. We'll * support that, but I don't see why it should ever be used. ****************************************************************//* FIXTHIS: These statistics are mimimally correct, but not much more */static void DCacheFlush(int cpuNum, int writeback, int retain, PA paddr, int size){ int cacheNum = GET_CACHE_NUM(cpuNum); PA a; int ind, set; ASSERT (writeback || !retain); /* One of these two should be set */ /* ASSERT for now */ ASSERT((paddr & (DCACHE_LINE_SIZE-1)) == 0); if (writeback && retain) { CACHE[cacheNum].stats.DCache.Downgrade++; } else if (!writeback && !retain) { CACHE[cacheNum].stats.DCache.Inval++; } for (a = paddr; a < paddr + size; a += DCACHE_LINE_SIZE) { ind = DCACHE_INDEXOF(a); if ((CACHE[cacheNum].DCache.set[ind].tags[0] & (~EXCLUSIVE_TAG)) == DCACHE_TAG(a)) { set = 0; goto foundit; } #if DCACHE_ASSOC > 1 if ((CACHE[cacheNum].DCache.set[ind].tags[1] & (~EXCLUSIVE_TAG)) == DCACHE_TAG(a)) { set = 1; goto foundit; }#endif#if DCACHE_ASSOC > 2 if ((CACHE[cacheNum].DCache.set[ind].tags[2] & (~EXCLUSIVE_TAG)) == DCACHE_TAG(a)) { set = 2; goto foundit; }#endif#if DCACHE_ASSOC > 3 if ((CACHE[cacheNum].DCache.set[ind].tags[3] & (~EXCLUSIVE_TAG)) == DCACHE_TAG(a)) { set = 3; goto foundit; }#endif continue; /* not present, go around the loop */ foundit: if ((CACHE[cacheNum].DCache.set[ind].tags[set] & EXCLUSIVE_TAG) != 0) { /* Line is exclusive */ if (writeback) { CACHE[cacheNum].stats.DCache.LinesWriteback++; CACHE[cacheNum].DCache.set[ind].tags[set] = DCACHE_TAG(a);#ifdef DATA_HANDLING { char *data; int way; /* NOTE: This call is not optional for DATA_HANDLING..we use it to find the scache line that will be used to receive the writeback */ if (!(IsInSCache(cpuNum, a, 0, &data, &way))) { CPUError("DCacheFlush didn't find line in SCache"); } /* Write the line back to the scache */ }#endif L1_LINE_TRANS_EVENT(cpuNum, a, (E_L1 | E_D | E_EXTERNAL | E_DOWNGRADE), 0, IS_KUSEG(CURRENT_PC(cpuNum))); } } if (!writeback && !retain) { uint type; CACHE[cacheNum].stats.DCache.LinesInval++; if (CACHE[cacheNum].DCache.set[ind].tags[set] & EXCLUSIVE_TAG) { type = E_L1 | E_D | E_EXTERNAL | E_WRITEBACK; } else { type = E_L1 | E_D | E_EXTERNAL | E_FLUSH_CLEAN; } L1_LINE_TRANS_EVENT(cpuNum, a, type, 0, IS_KUSEG(CURRENT_PC(cpuNum))); } if (retain) { CACHE[cacheNum].DCache.set[ind].tags[set] &= ~EXCLUSIVE_TAG; /* Take away exclusive ownership */ } else { CACHE[cacheNum].DCache.set[ind].tags[set] = INVALID_TAG; } DCACHE_MAKE_LRU(CACHE[cacheNum].DCache.set[ind].LRU, set); }}/**************************************************************** * MemRefWriteData * Return values: * SUCCESS - Request hit in the cache, data written. * 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. * SCFAILURE - Was an SC and it failed. * * Main entry into 1st level data cache writing from the CPU *****************************************************************/ResultMemRefWriteData(int cpuNum, VA vAddr, PA pAddr, uint64 data, RefSize size, RefFlavor flavor){ int cacheNum = GET_CACHE_NUM(cpuNum); PA tag = DCACHE_TAG_EX(pAddr); struct DCacheSet* set; bool upgrade; int way; int mhtind = -1; int lineindex; int ind = DCACHE_INDEXOF(pAddr); set = & CACHE[cacheNum].DCache.set[ind]; /* See if weve been stalled on the MHT, update stats if so */ if (useWriteBuffer) { STATS_ADD_INTERVAL(cpuNum, writeBufferStats.writeMHTStallTime, writeMHTStallStart); } if ( DCACHE_HIT_ALWAYS ) { way = 0; set->data[way] = (byte*)CPUVec.PAToHostAddr(cpuNum, pAddr&~(PA)(DCACHE_LINE_SIZE-1), vAddr); goto foundit; } if (!DCACHE_MISS_ALWAYS ) { if (set->tags[0] == tag) { way = 0; goto foundit; }#if DCACHE_ASSOC > 1 if (set->tags[1] == tag) { way = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -