mem: Adding verbose debug output in the memory system
[gem5.git] / src / mem / cache / tags / lru.cc
index fa46aff7b55794609ef808a550fd45796f7e4ca4..f515ed053a2e1932915cb1787c5a6d3abba09315 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2003-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
 
 #include <string>
 
-#include "mem/cache/base_cache.hh"
 #include "base/intmath.hh"
+#include "debug/Cache.hh"
+#include "debug/CacheRepl.hh"
+#include "mem/cache/tags/cacheset.hh"
 #include "mem/cache/tags/lru.hh"
+#include "mem/cache/base.hh"
 #include "sim/core.hh"
 
 using namespace std;
 
-LRUBlk*
-CacheSet::findBlk(Addr tag) const
-{
-    for (int i = 0; i < assoc; ++i) {
-        if (blks[i]->tag == tag && blks[i]->isValid()) {
-            return blks[i];
-        }
-    }
-    return 0;
-}
-
-
-void
-CacheSet::moveToHead(LRUBlk *blk)
-{
-    // nothing to do if blk is already head
-    if (blks[0] == blk)
-        return;
-
-    // write 'next' block into blks[i], moving up from MRU toward LRU
-    // until we overwrite the block we moved to head.
-
-    // start by setting up to write 'blk' into blks[0]
-    int i = 0;
-    LRUBlk *next = blk;
-
-    do {
-        assert(i < assoc);
-        // swap blks[i] and next
-        LRUBlk *tmp = blks[i];
-        blks[i] = next;
-        next = tmp;
-        ++i;
-    } while (next != blk);
-}
-
-
 // create and initialize a LRU/MRU cache structure
-LRU::LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency) :
-    numSets(_numSets), blkSize(_blkSize), assoc(_assoc), hitLatency(_hit_latency)
+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)) {
@@ -97,9 +77,6 @@ LRU::LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency) :
         fatal("access latency must be greater than zero");
     }
 
-    LRUBlk  *blk;
-    int i, j, blkIndex;
-
     blkMask = blkSize - 1;
     setShift = floorLog2(blkSize);
     setMask = numSets - 1;
@@ -109,25 +86,26 @@ LRU::LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency) :
     warmupBound = numSets * assoc;
 
     sets = new CacheSet[numSets];
-    blks = new LRUBlk[numSets * assoc];
+    blks = new BlkType[numSets * assoc];
     // allocate data storage in one big chunk
-    dataBlks = new uint8_t[numSets*assoc*blkSize];
+    numBlocks = numSets * assoc;
+    dataBlks = new uint8_t[numBlocks * blkSize];
 
-    blkIndex = 0;      // index into blks array
-    for (i = 0; i < numSets; ++i) {
+    unsigned blkIndex = 0;       // index into blks array
+    for (unsigned i = 0; i < numSets; ++i) {
         sets[i].assoc = assoc;
 
-        sets[i].blks = new LRUBlk*[assoc];
+        sets[i].blks = new BlkType*[assoc];
 
         // link in the data blocks
-        for (j = 0; j < assoc; ++j) {
+        for (unsigned j = 0; j < assoc; ++j) {
             // locate next cache block
-            blk = &blks[blkIndex];
+            BlkType *blk = &blks[blkIndex];
             blk->data = &dataBlks[blkSize*blkIndex];
             ++blkIndex;
 
             // invalidate new cache block
-            blk->status = 0;
+            blk->invalidate();
 
             //EGH Fix Me : do we need to initialize blk?
 
@@ -150,34 +128,21 @@ LRU::~LRU()
     delete [] sets;
 }
 
-// probe cache for presence of given block.
-bool
-LRU::probe(Addr addr) const
-{
-    //  return(findBlock(Read, addr, asid) != 0);
-    Addr tag = extractTag(addr);
-    unsigned myset = extractSet(addr);
-
-    LRUBlk *blk = sets[myset].findBlk(tag);
-
-    return (blk != NULL);      // true if in cache
-}
-
-LRUBlk*
-LRU::findBlock(Addr addr, int &lat)
+LRU::BlkType*
+LRU::accessBlock(Addr addr, Cycles &lat, int master_id)
 {
     Addr tag = extractTag(addr);
     unsigned set = extractSet(addr);
-    LRUBlk *blk = sets[set].findBlk(tag);
+    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(Cache, "set %x: moving blk %x to MRU\n",
+        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;
+        if (blk->whenReady > curTick()
+            && cache->ticksToCycles(blk->whenReady - curTick()) > hitLatency) {
+            lat = cache->ticksToCycles(blk->whenReady - curTick());
         }
         blk->refCount += 1;
     }
@@ -186,56 +151,115 @@ LRU::findBlock(Addr addr, int &lat)
 }
 
 
-LRUBlk*
+LRU::BlkType*
 LRU::findBlock(Addr addr) const
 {
     Addr tag = extractTag(addr);
     unsigned set = extractSet(addr);
-    LRUBlk *blk = sets[set].findBlk(tag);
+    BlkType *blk = sets[set].findBlk(tag);
     return blk;
 }
 
-LRUBlk*
-LRU::findReplacement(Addr addr, PacketList &writebacks)
+LRU::BlkType*
+LRU::findVictim(Addr addr, PacketList &writebacks)
 {
     unsigned set = extractSet(addr);
     // grab a replacement candidate
-    LRUBlk *blk = sets[set].blks[assoc-1];
-    sets[set].moveToHead(blk);
+    BlkType *blk = sets[set].blks[assoc-1];
+
     if (blk->isValid()) {
-        replacements[0]++;
-        totalRefs += blk->refCount;
-        ++sampledRefs;
-        blk->refCount = 0;
-    } else if (!blk->isTouched) {
+        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 master_id)
+{
+    if (!blk->isTouched) {
         tagsInUse++;
         blk->isTouched = true;
         if (!warmedUp && tagsInUse.value() >= warmupBound) {
             warmedUp = true;
-            warmupCycle = curTick;
+            warmupCycle = curTick();
         }
     }
 
-    DPRINTF(Cache, "set %x: selecting blk %x for replacement\n",
-            set, regenerateBlkAddr(blk->tag, set));
-    return blk;
+    // If we're replacing a block that was previously valid update
+    // stats for it. This can't be done in findBlock() because a
+    // found block might not actually be replaced there if the
+    // coherence protocol says it can't be.
+    if (blk->isValid()) {
+        replacements[0]++;
+        totalRefs += blk->refCount;
+        ++sampledRefs;
+        blk->refCount = 0;
+
+        // deal with evicted block
+        assert(blk->srcMasterId < cache->system->maxMasters());
+        occupancies[blk->srcMasterId]--;
+
+        blk->invalidate();
+    }
+
+    blk->isTouched = true;
+    // Set tag for new block.  Caller is responsible for setting status.
+    blk->tag = extractTag(addr);
+
+    // deal with what we are bringing in
+    assert(master_id < cache->system->maxMasters());
+    occupancies[master_id]++;
+    blk->srcMasterId = master_id;
+
+    unsigned set = extractSet(addr);
+    sets[set].moveToHead(blk);
+}
+
+void
+LRU::invalidate(BlkType *blk)
+{
+    assert(blk);
+    assert(blk->isValid());
+    tagsInUse--;
+    assert(blk->srcMasterId < cache->system->maxMasters());
+    occupancies[blk->srcMasterId]--;
+    blk->srcMasterId = Request::invldMasterId;
+
+    // should be evicted before valid blocks
+    unsigned set = blk->set;
+    sets[set].moveToTail(blk);
 }
 
 void
-LRU::invalidateBlk(LRU::BlkType *blk)
+LRU::clearLocks()
 {
-    if (blk) {
-        blk->status = 0;
-        blk->isTouched = false;
-        blk->clearLoadLocks();
-        tagsInUse--;
+    for (int i = 0; i < numBlocks; i++){
+        blks[i].clearLoadLocks();
+    }
+}
+
+std::string
+LRU::print() const {
+    std::string cache_state;
+    for (unsigned i = 0; i < numSets; ++i) {
+        // link in the data blocks
+        for (unsigned j = 0; j < assoc; ++j) {
+            BlkType *blk = sets[i].blks[j];
+            if (blk->isValid())
+                cache_state += csprintf("\tset: %d block: %d %s\n", i, j,
+                        blk->print());
+        }
     }
+    if (cache_state.empty())
+        cache_state = "no valid tags\n";
+    return cache_state;
 }
 
 void
 LRU::cleanupRefs()
 {
-    for (int i = 0; i < numSets*assoc; ++i) {
+    for (unsigned i = 0; i < numSets*assoc; ++i) {
         if (blks[i].isValid()) {
             totalRefs += blks[i].refCount;
             ++sampledRefs;