/* * 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 a fully associative LRU tagstore. */ #include #include #include "base/intmath.hh" #include "base/misc.hh" #include "mem/cache/tags/fa_lru.hh" using namespace std; FALRU::FALRU(unsigned _blkSize, unsigned _size, unsigned hit_latency) : blkSize(_blkSize), size(_size), hitLatency(hit_latency) { if (!isPowerOf2(blkSize)) fatal("cache block size (in bytes) `%d' must be a power of two", blkSize); if (!(hitLatency > 0)) fatal("Access latency in cycles must be at least one cycle"); if (!isPowerOf2(size)) fatal("Cache Size must be power of 2 for now"); // Track all cache sizes from 128K up by powers of 2 numCaches = floorLog2(size) - 17; if (numCaches >0){ cacheBoundaries = new FALRUBlk *[numCaches]; cacheMask = (1 << numCaches) - 1; } else { cacheMask = 0; } warmedUp = false; warmupBound = size/blkSize; numBlocks = size/blkSize; blks = new FALRUBlk[numBlocks]; head = &(blks[0]); tail = &(blks[numBlocks-1]); head->prev = NULL; head->next = &(blks[1]); head->inCache = cacheMask; tail->prev = &(blks[numBlocks-2]); tail->next = NULL; tail->inCache = 0; unsigned index = (1 << 17) / blkSize; unsigned j = 0; int flags = cacheMask; for (unsigned i = 1; i < numBlocks - 1; i++) { blks[i].inCache = flags; if (i == index - 1){ cacheBoundaries[j] = &(blks[i]); flags &= ~ (1<status = 0; blk->isTouched = false; tagsInUse--; } } FALRUBlk* FALRU::accessBlock(Addr addr, int &lat, int context_src, int *inCache) { accesses++; int tmp_in_cache = 0; Addr blkAddr = blkAlign(addr); FALRUBlk* blk = hashLookup(blkAddr); if (blk && blk->isValid()) { assert(blk->tag == blkAddr); tmp_in_cache = blk->inCache; for (unsigned i = 0; i < numCaches; i++) { if (1<inCache) { hits[i]++; } else { misses[i]++; } } hits[numCaches]++; if (blk != head){ moveToHead(blk); } } else { blk = NULL; for (unsigned i = 0; i <= numCaches; ++i) { misses[i]++; } } if (inCache) { *inCache = tmp_in_cache; } lat = hitLatency; //assert(check()); return blk; } FALRUBlk* FALRU::findBlock(Addr addr) const { Addr blkAddr = blkAlign(addr); FALRUBlk* blk = hashLookup(blkAddr); if (blk && blk->isValid()) { assert(blk->tag == blkAddr); } else { blk = NULL; } return blk; } FALRUBlk* FALRU::findVictim(Addr addr, PacketList &writebacks) { FALRUBlk * blk = tail; assert(blk->inCache == 0); moveToHead(blk); tagHash.erase(blk->tag); tagHash[blkAlign(addr)] = blk; if (blk->isValid()) { replacements[0]++; } else { tagsInUse++; blk->isTouched = true; if (!warmedUp && tagsInUse.value() >= warmupBound) { warmedUp = true; warmupCycle = curTick(); } } //assert(check()); return blk; } void FALRU::insertBlock(Addr addr, FALRU::BlkType *blk, int context_src) { } void FALRU::moveToHead(FALRUBlk *blk) { int updateMask = blk->inCache ^ cacheMask; for (unsigned i = 0; i < numCaches; i++){ if ((1<inCache &= ~(1<prev; } else if (cacheBoundaries[i] == blk) { cacheBoundaries[i] = blk->prev; } } blk->inCache = cacheMask; if (blk != head) { if (blk == tail){ assert(blk->next == NULL); tail = blk->prev; tail->next = NULL; } else { blk->prev->next = blk->next; blk->next->prev = blk->prev; } blk->next = head; blk->prev = NULL; head->prev = blk; head = blk; } } bool FALRU::check() { FALRUBlk* blk = head; int size = 0; int boundary = 1<<17; int j = 0; int flags = cacheMask; while (blk) { size += blkSize; if (blk->inCache != flags) { return false; } if (size == boundary && blk != tail) { if (cacheBoundaries[j] != blk) { return false; } flags &=~(1 << j); boundary = boundary<<1; ++j; } blk = blk->next; } return true; } void FALRU::clearLocks() { for (int i = 0; i < numBlocks; i++){ blks[i].clearLoadLocks(); } }