/* * Copyright (c) 2003-2005 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Erik Hallnor */ /** * @file * Definitions of LRU tag store. */ #include #include "mem/cache/base.hh" #include "base/intmath.hh" #include "mem/cache/tags/lru.hh" #include "sim/core.hh" #include "cacheset.hh" using namespace std; // create and initialize a LRU/MRU cache structure LRU::LRU(unsigned _numSets, unsigned _blkSize, unsigned _assoc, unsigned _hit_latency) : numSets(_numSets), blkSize(_blkSize), assoc(_assoc), hitLatency(_hit_latency) { // Check parameters if (blkSize < 4 || !isPowerOf2(blkSize)) { fatal("Block size must be at least 4 and a power of 2"); } if (numSets <= 0 || !isPowerOf2(numSets)) { fatal("# of sets must be non-zero and a power of 2"); } if (assoc <= 0) { fatal("associativity must be greater than zero"); } if (hitLatency <= 0) { fatal("access latency must be greater than zero"); } blkMask = blkSize - 1; setShift = floorLog2(blkSize); setMask = numSets - 1; tagShift = setShift + floorLog2(numSets); warmedUp = false; /** @todo Make warmup percentage a parameter. */ warmupBound = numSets * assoc; sets = new CacheSet[numSets]; blks = new BlkType[numSets * assoc]; // allocate data storage in one big chunk numBlocks = numSets * assoc; dataBlks = new uint8_t[numBlocks * blkSize]; unsigned blkIndex = 0; // index into blks array for (unsigned i = 0; i < numSets; ++i) { sets[i].assoc = assoc; sets[i].blks = new BlkType*[assoc]; // link in the data blocks for (unsigned j = 0; j < assoc; ++j) { // locate next cache block BlkType *blk = &blks[blkIndex]; blk->data = &dataBlks[blkSize*blkIndex]; ++blkIndex; // invalidate new cache block blk->status = 0; //EGH Fix Me : do we need to initialize blk? // Setting the tag to j is just to prevent long chains in the hash // table; won't matter because the block is invalid blk->tag = j; blk->whenReady = 0; blk->isTouched = false; blk->size = blkSize; sets[i].blks[j]=blk; blk->set = i; } } } LRU::~LRU() { delete [] dataBlks; delete [] blks; delete [] sets; } LRU::BlkType* LRU::accessBlock(Addr addr, int &lat, int context_src) { Addr tag = extractTag(addr); unsigned set = extractSet(addr); BlkType *blk = sets[set].findBlk(tag); lat = hitLatency; if (blk != NULL) { // move this block to head of the MRU list sets[set].moveToHead(blk); DPRINTF(CacheRepl, "set %x: moving blk %x to MRU\n", set, regenerateBlkAddr(tag, set)); if (blk->whenReady > curTick && blk->whenReady - curTick > hitLatency) { lat = blk->whenReady - curTick; } blk->refCount += 1; } return blk; } LRU::BlkType* LRU::findBlock(Addr addr) const { Addr tag = extractTag(addr); unsigned set = extractSet(addr); BlkType *blk = sets[set].findBlk(tag); return blk; } LRU::BlkType* LRU::findVictim(Addr addr, PacketList &writebacks) { unsigned set = extractSet(addr); // grab a replacement candidate BlkType *blk = sets[set].blks[assoc-1]; if (blk->isValid()) { replacements[0]++; totalRefs += blk->refCount; ++sampledRefs; blk->refCount = 0; // deal with evicted block if (blk->contextSrc != -1) { occupancies[blk->contextSrc % cache->numCpus()]--; blk->contextSrc = -1; } else { occupancies[cache->numCpus()]--; } DPRINTF(CacheRepl, "set %x: selecting blk %x for replacement\n", set, regenerateBlkAddr(blk->tag, set)); } return blk; } void LRU::insertBlock(Addr addr, BlkType *blk, int context_src) { if (!blk->isTouched) { tagsInUse++; blk->isTouched = true; if (!warmedUp && tagsInUse.value() >= warmupBound) { warmedUp = true; warmupCycle = curTick; } } // Set tag for new block. Caller is responsible for setting status. blk->tag = extractTag(addr); // deal with what we are bringing in if (context_src != -1) { occupancies[context_src % cache->numCpus()]++; } else { occupancies[cache->numCpus()]++; } blk->contextSrc = context_src; unsigned set = extractSet(addr); sets[set].moveToHead(blk); } void LRU::invalidateBlk(BlkType *blk) { if (blk) { blk->status = 0; blk->isTouched = false; blk->clearLoadLocks(); tagsInUse--; if (blk->contextSrc != -1) { occupancies[blk->contextSrc % cache->numCpus()]--; blk->contextSrc = -1; } else { occupancies[cache->numCpus()]--; } } } void LRU::clearLocks() { for (int i = 0; i < numBlocks; i++){ blks[i].clearLoadLocks(); } } void LRU::cleanupRefs() { for (unsigned i = 0; i < numSets*assoc; ++i) { if (blks[i].isValid()) { totalRefs += blks[i].refCount; ++sampledRefs; } } }