📄 scache.c
字号:
QUICK_ICACHE_CLEAR(cpuNum);#ifndef SOLO ASSERT (IS_VALID_PA(M_FROM_CPU(cpuNum), pAddr));/* ASSERT( tag < SCACHE_TAG( MEM_SIZE(M_FROM_CPU(cpuNum))));*/#endif#ifdef DATA_HANDLING ASSERT( SCACHE[scacheNum].set[ind].tags[way] == tag || fillData); /* We either have the data already, and */ /* this is an upgrade, or fillData is set */ /* so we can get the correct data*/#endif if (mode & MEMSYS_EXCLUSIVE) { tag |= EXCLUSIVE_TAG; } SCACHE[scacheNum].set[ind].tags[way] = tag; SCacheLRUTouch(&SCACHE[scacheNum].set[ind].LRU, way); /* WARNING: I think this was too restrictive: ASSERT(fillData != 0); */ /* This parameter should never be zero when I get here */#ifdef DATA_HANDLING if (fillData != 0) { ASSERT(smht->lineData != (char *) 0xffffffff); bcopy(fillData, smht->lineData, SCACHE_LINE_SIZE); if (VERBOSE_DEBUG) { CPUPrint("%d: SCacheMiss: filling %8.8lx (from flashlite) ",cpuNum, smht->pAddr); CPUPrint("%d: bcopy %x -> %x (%d) Data: ",cpuNum, fillData, smht->lineData, SCACHE_LINE_SIZE); DumpCacheLine(smht->lineData, SCACHE_LINE_SIZE); } smht->lineData = (char *) 0xffffffff; /* Set lineData to be invalid to prevent erroneous reuse of this */ /* pointer, such as occured in our heinous bug of 3/28/95 */ }#endif #ifdef CC_CHECKER CacheChecker(pAddr, cpuNum, (tag & EXCLUSIVE_TAG)!=0); #endif}/**************************************************************** * SCacheFlush * * See DCacheFlush, the semantics is identical ****************************************************************/static FlushStatusSCacheFlush(int cpuNum, int writeback, int retain, PA paddr, int size, byte *data){ int scacheNum = GET_SCACHE_NUM(cpuNum); PA a; uint ind; struct SCacheSet* set; int way; FlushStatus s = FLUSH_NOTFOUND; if (interest(paddr)) { LogEntry("flush",cpuNum,"%x state=%d\n",paddr, MSCacheState(cpuNum, paddr)); } ASSERT(writeback || !retain); /* One of these two should be set */ if (writeback && retain) { SCACHE[scacheNum].stats.Downgrade++; } for (a = (paddr & ~(PA)(SCACHE_LINE_SIZE-1)); a < (paddr & ~(PA)(SCACHE_LINE_SIZE-1)) + size; a += SCACHE_LINE_SIZE) { ind = SCACHE_INDEXOF(a); set = & SCACHE[scacheNum].set[ind]; /* * Direct-mapped caches. We do not rely on presence in the * cache to determine the success of the SC, but rather * on the LLbit. */ if (SCACHE_ASSOC == 1 && CPUVec.GetLockAddr(cpuNum) == a) { if (!retain) { /* invalidated from the cache */ CPUVec.ClearLockFlag(cpuNum); } } for (way=0; way<SCACHE_ASSOC; ++way) { if (set->tags[way] == SCACHE_TAG_EX(a)) { goto ScFlush_Exclusive; } if ((set->tags[way] & ~EXCLUSIVE_TAG) == SCACHE_TAG(a)) { goto ScFlush_Shared; } } if (way==SCACHE_ASSOC) { uint type; /* not found */ if (writeback & retain) { type = E_L2 | E_WRITEBACK | E_FAKE_EXTERNAL; } else { type = E_L2 | E_FLUSH_CLEAN | E_FAKE_EXTERNAL; } L2_LINE_TRANS_EVENT(cpuNum, a, type, 0, 0,IS_KUSEG(CURRENT_PC(cpuNum))); continue; } ASSERT(0); /* Control should never reach this point */ return s;ScFlush_Exclusive: /* Found an exclusive line in the flush */ /* region...handle it based on the flags*/ s = FLUSH_EXCLUSIVE; PrimaryFlush(cpuNum, writeback, retain, a, SCACHE_LINE_SIZE); SCACHE[scacheNum].stats.LinesWriteback++; /* WARNING: I don't require the user to writeback the line if it's */ /* dirty since I want to support invalidations of dirty lines for */ /* memory copy, where I squash a line regardless of its state */ if (retain) { /* Remove exclusive ownership */ set->tags[way] &= SCACHE_TAG(a);#ifndef SOLO ASSERT(IS_VALID_PA(M_FROM_CPU(cpuNum), STAG_TO_PA(set->tags[way],0)));/* ASSERT( (set->tags[way]&~EXCLUSIVE_TAG) < SCACHE_TAG(MEM_SIZE(M_FROM_CPU(cpuNum))));*/#endif L2_LINE_TRANS_EVENT(cpuNum, a, E_L2 | E_EXTERNAL | E_DOWNGRADE, 0, way, CURRENT_PC(cpuNum)); } else { set->tags[way] = INVALID_TAG; L2_LINE_TRANS_EVENT(cpuNum, a, E_L2 | E_EXTERNAL | E_WRITEBACK, 0, way, IS_KUSEG(CURRENT_PC(cpuNum))); }#ifdef DATA_HANDLING if (writeback) { ASSERT(data != NULL); if (data != NULL) { /* If I want a data reply */ bcopy(set->data[way], data, SCACHE_LINE_SIZE); } /* SAH: Why isn't there a writeback here? */ if (VERBOSE_DEBUG) { CPUPrint("%d: bcopy %x -> %x (%d) (flashlite) Data:\n", cpuNum, set->data[way],(char *)data,SCACHE_LINE_SIZE); DumpCacheLine(set->data[way],SCACHE_LINE_SIZE); } }#endif /* DATA_HANDLING */ continue;ScFlush_Shared: if (!retain) { if (VERBOSE_DEBUG) { CPUPrint("%d: SCacheMiss: spilling (shared) PA: %8.8lx \n",cpuNum, paddr); } PrimaryFlush(cpuNum, writeback, retain, a, SCACHE_LINE_SIZE); SCACHE[scacheNum].stats.LinesInval++; s = FLUSH_SHARED; set->tags[way] = INVALID_TAG; SCacheLRUMake(&set->LRU, way); L2_LINE_TRANS_EVENT(cpuNum, a, (E_L2 | E_EXTERNAL | E_FLUSH_CLEAN), 0, way,IS_KUSEG(CURRENT_PC(cpuNum))); } continue; } return s;}/**************************************************************** * SCacheFlushIndex * * Similar to SCacheFlush, but flushes one of the cached lines at * an index matching the one of the given paddr. Used to implement * the CACH_SD option to the CACHE instruction. ****************************************************************/static FlushStatusSCacheFlushIndex(int cpuNum, int writeback, int retain, PA paddr, PA *real_paddr, int size, byte *data){ int scacheNum = GET_SCACHE_NUM(cpuNum); PA a, aa; uint ind; struct SCacheSet* set; int way; FlushStatus s = FLUSH_NOTFOUND; if( interest(paddr)) LogEntry("flush index",cpuNum,"%x \n",paddr); ASSERT(writeback || !retain); /* One of these two should be set */ if (writeback && retain) SCACHE[scacheNum].stats.Downgrade++; for (a = (paddr & ~(PA)(SCACHE_LINE_SIZE-1)); a < (paddr & ~(PA)(SCACHE_LINE_SIZE-1)) + size; a += SCACHE_LINE_SIZE) {#ifndef SOLO ASSERT (IS_VALID_PA(M_FROM_CPU(cpuNum), paddr));#endif ind = SCACHE_INDEXOF(a); set = & SCACHE[scacheNum].set[ind]; /* * Direct-mapped caches. We do not rely on presence in the * cache to determine the success of the SC, but rather * on the LLbit. */ if (SCACHE_ASSOC == 1 && CPUVec.GetLockAddr(cpuNum) == a) { if (!retain) { /* invalidated from the cache */ CPUVec.ClearLockFlag(cpuNum); } } for (way=0; way<SCACHE_ASSOC; ++way) if (set->tags[way] != INVALID_TAG) { if ((set->tags[way] & EXCLUSIVE_TAG) != 0) { s = FLUSH_EXCLUSIVE; aa = STAG_TO_PA(set->tags[way], ind); if (real_paddr) *real_paddr = aa; #ifndef SOLO ASSERT (IS_VALID_PA(M_FROM_CPU(cpuNum), aa));#endif PrimaryFlush(cpuNum, writeback, retain, aa, SCACHE_LINE_SIZE); SCACHE[scacheNum].stats.LinesWriteback++; /* WARNING: I don't require the user to writeback the line if it's */ /* dirty since I want to support invalidations of dirty lines for */ /* memory copy, where I squash a line regardless of its state */ if (retain) { /* Remove exclusive ownership */ set->tags[way] &= ~EXCLUSIVE_TAG; L2_LINE_TRANS_EVENT(cpuNum, aa, E_L2|E_EXTERNAL|E_DOWNGRADE, 0, way, IS_KUSEG(CURRENT_PC(cpuNum))); } else { set->tags[way] = INVALID_TAG; L2_LINE_TRANS_EVENT(cpuNum, aa, E_L2|E_EXTERNAL|E_WRITEBACK, 0, way, IS_KUSEG(CURRENT_PC(cpuNum))); }#ifdef DATA_HANDLING if (writeback) { ASSERT(data != NULL); if (data != NULL) { /* If I want a data reply */ bcopy(set->data[way],data, SCACHE_LINE_SIZE); } if (VERBOSE_DEBUG) { CPUPrint("%d: bcopy %x -> %x (%d) (flashlite) Data:\n", cpuNum, set->data[way],(char *)data,SCACHE_LINE_SIZE); DumpCacheLine(set->data[way],SCACHE_LINE_SIZE); } }#endif /* DATA_HANDLING */ return s; /* invalidate only one line */ } else { aa = STAG_TO_PA(set->tags[way], ind); if (real_paddr) *real_paddr = aa; if (!retain) { if (VERBOSE_DEBUG) { CPUPrint("%d: SCacheMiss: spilling (shared) PA: %8.8lx \n", cpuNum, paddr); } PrimaryFlush(cpuNum, writeback, retain, aa, SCACHE_LINE_SIZE); SCACHE[scacheNum].stats.LinesInval++; s = FLUSH_SHARED; set->tags[way] = INVALID_TAG; SCacheLRUMake(&set->LRU, way); L2_LINE_TRANS_EVENT(cpuNum, aa, (E_L2 | E_EXTERNAL | E_FLUSH_CLEAN), 0, way,IS_KUSEG(CURRENT_PC(cpuNum))); } return s; /* invalidate only one line */ } } } return s;}/***************************************************************** * CacheFakeInvalidate * Called when a line has been invalidated by a cpu, and is known not * to be in the cache of cpuNum. This allows Memstat to maintain its * state machine. This is never called in perfectmem. * *****************************************************************/voidCacheFakeInvalidate(int cpuNum,PA paddr, int size){ int scacheNum = GET_SCACHE_NUM(cpuNum); PA a; uint ind; struct SCacheSet* set; int way; for (a = paddr; a < paddr + size; a += SCACHE_LINE_SIZE) { ind = SCACHE_INDEXOF(a); /* (a/SCACHE_LINE_SIZE) % SCACHE_INDEX; */ set = & SCACHE[scacheNum].set[ind]; if( SCACHE_ASSOC == 1 && CPUVec.GetLockAddr(cpuNum) == (a & ~(SCACHE_LINE_SIZE-1)) ) { /* Direct-mapped cache. Invalidate it */ CPUVec.ClearLockFlag(cpuNum); } for(way=0;way<SCACHE_ASSOC;++way ) { if ((set->tags[way] & ~EXCLUSIVE_TAG) == SCACHE_TAG(a)) break; } if (way==SCACHE_ASSOC) { /* not in the cache */ L2_LINE_TRANS_EVENT(cpuNum, a, (E_L2 | E_FAKE_EXTERNAL), 0, 0, IS_KUSEG(CURRENT_PC(cpuNum))); continue; } ASSERT( 0 ); }}/*************************************************************** * Cacheinvalidate * * This routine destructively invalidates a line from the cache. * In the case of shared data, the line is removed, and this * operation is equivalent to CacheExtract. * * In the case of dirty data, this routine PERMANENTLY DISCARDS * the dirty copy and removes the line from the cache. While * this violates most cache coherence protocols, for block * transfer this is a useful performance optimization. ***************************************************************/intCacheInvalidate(int cpuNum, PA paddr, int size, bool writeback, int *wasDirty) { FlushStatus s; if (VERBOSE_DEBUG) { CPUPrint("%d: CacheInvalidate for paddr %8.8lx\n", cpuNum, paddr); } if (writeback) { /* writeback == TRUE retain == FALSE */ s = SCacheFlush(cpuNum, TRUE, FALSE, paddr, size, NULL); } else { /* writeback == FALSE retain == FALSE */ s = SCacheFlush(cpuNum, FALSE, FALSE, paddr, size, NULL); } *wasDirty = (s == FLUSH_EXCLUSIVE); if (s == FLUSH_NOTFOUND) { return 0; } return 1;}/*************************************************************** * CacheinvalidateIndex * * Invoked through the "cache" op. Stalling the processor * is a little messy here... I assume that if it was a writeback and * it was found, then I'll need to stall the processor.. ***************************************************************/intCacheInvalidateIndex(int cpuNum, PA paddr, int size, bool writeback, int *wasDirty) { FlushStatus s; if (VERBOSE_DEBUG) { CPUPrint("%d: CacheInvalidateIndex for paddr %8.8lx\n", cpuNum, paddr); } if (writeback) { /* writeback == TRUE retain == FALSE */ s = SCacheFlushIndex(cpuNum, TRUE, FALSE, paddr, NULL, size, NULL); } else { /* writeback == FALSE retain == FALSE */ s = SCacheFlushIndex(cpuNum, FALSE, FALSE, paddr, NULL, size, NULL); } *wasDirty = (s == FLUSH_EXCLUSIVE); if (s == FLUSH_NOTFOUND) { return 0; } return 1;}/**************************************************************** * CacheWriteback * * This routine forces a line in the cache to be written back, * if it is dirty. The line loses its ownership but remains in * the cache. (This is a GET operation) ****************************************************************/intCacheWriteback(int cpuNum, PA paddr, int size, byte *data)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -