summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
authorSteve Reinhardt <stever@gmail.com>2008-02-16 14:58:03 -0500
committerSteve Reinhardt <stever@gmail.com>2008-02-16 14:58:03 -0500
commit4597a71cef808969c442fca73ae662efe75550d7 (patch)
treef674856f086d7fea06df0fb7767a5cc615c3bed5 /src/mem
parent69ce7f953b96834ec52d3340f375317ac5858b43 (diff)
downloadgem5-4597a71cef808969c442fca73ae662efe75550d7.tar.xz
Make L2+ caches allocate new block for writeback misses
instead of forwarding down the line. --HG-- extra : convert_revision : b0d6e7862c92ea7a2d21f817d30398735e7bb8ba
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/cache/cache.hh8
-rw-r--r--src/mem/cache/cache_impl.hh141
2 files changed, 93 insertions, 56 deletions
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
index 073ce5ecb..6f5428c13 100644
--- a/src/mem/cache/cache.hh
+++ b/src/mem/cache/cache.hh
@@ -170,6 +170,14 @@ class Cache : public BaseCache
void cmpAndSwap(BlkType *blk, PacketPtr pkt);
/**
+ * Find a block frame for new block at address addr, assuming that
+ * the block is not currently in the cache. Append writebacks if
+ * any to provided packet list. Return free block frame. May
+ * return NULL if there are no replaceable blocks at the moment.
+ */
+ BlkType *allocateBlock(Addr addr, PacketList &writebacks);
+
+ /**
* Populates a cache block and handles all outstanding requests for the
* satisfied fill request. This version takes two memory requests. One
* contains the fill data, the other is an optional target to satisfy.
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index 6e4b50ed9..d4fbc90a5 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -267,7 +267,6 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
return false;
}
- bool satisfied = false; // assume the worst
blk = tags->findBlock(pkt->getAddr(), lat);
if (prefetchAccess) {
@@ -279,7 +278,7 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
(blk) ? "hit" : "miss");
if (blk != NULL) {
- // HIT
+
if (blk->isPrefetch()) {
//Signal that this was a hit under prefetch (no need for
//use prefetch (only can get here if true)
@@ -296,37 +295,54 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
if (pkt->needsExclusive() ? blk->isWritable() : blk->isValid()) {
// OK to satisfy access
hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
- satisfied = true;
satisfyCpuSideRequest(pkt, blk);
- } else if (pkt->cmd == MemCmd::Writeback) {
- // special case: writeback to read-only block (e.g., from
- // L1 into L2). since we're really just passing ownership
- // from one cache to another, we can update this cache to
- // be the owner without making the block writeable
- assert(!blk->isWritable() /* && !blk->isDirty() */);
- assert(blkSize == pkt->getSize());
- std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
- blk->status |= BlkDirty;
- satisfied = true;
- // nothing else to do; writeback doesn't expect response
- assert(!pkt->needsResponse());
- } else {
- // permission violation... nothing to do here, leave unsatisfied
- // for statistics purposes this counts like a complete miss
- incMissCount(pkt);
+ return true;
}
- } else {
- // complete miss (no matching block)
- incMissCount(pkt);
+ }
- if (pkt->isLocked() && pkt->isWrite()) {
- // miss on store conditional... just give up now
- pkt->req->setExtraData(0);
- satisfied = true;
+ // Can't satisfy access normally... either no block (blk == NULL)
+ // or have block but need exclusive & only have shared.
+
+ // Writeback handling is special case. We can write the block
+ // into the cache without having a writeable copy (or any copy at
+ // all).
+ if (pkt->cmd == MemCmd::Writeback) {
+ PacketList writebacks;
+ assert(blkSize == pkt->getSize());
+ if (blk == NULL) {
+ // need to do a replacement
+ blk = allocateBlock(pkt->getAddr(), writebacks);
+ if (blk == NULL) {
+ // no replaceable block available, give up.
+ // writeback will be forwarded to next level.
+ incMissCount(pkt);
+ return false;
+ }
+ blk->status = BlkValid;
+ }
+ std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
+ blk->status |= BlkDirty;
+ // copy writebacks from replacement to write buffer
+ while (!writebacks.empty()) {
+ PacketPtr wbPkt = writebacks.front();
+ allocateWriteBuffer(wbPkt, curTick + hitLatency, true);
+ writebacks.pop_front();
}
+ // nothing else to do; writeback doesn't expect response
+ assert(!pkt->needsResponse());
+ hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
+ return true;
+ }
+
+ incMissCount(pkt);
+
+ if (blk == NULL && pkt->isLocked() && pkt->isWrite()) {
+ // complete miss on store conditional... just give up now
+ pkt->req->setExtraData(0);
+ return true;
}
- return satisfied;
+ return false;
}
@@ -850,6 +866,40 @@ Cache<TagStore>::writebackBlk(BlkType *blk)
}
+template<class TagStore>
+typename Cache<TagStore>::BlkType*
+Cache<TagStore>::allocateBlock(Addr addr, PacketList &writebacks)
+{
+ BlkType *blk = tags->findReplacement(addr, writebacks);
+
+ if (blk->isValid()) {
+ Addr repl_addr = tags->regenerateBlkAddr(blk->tag, blk->set);
+ MSHR *repl_mshr = mshrQueue.findMatch(repl_addr);
+ if (repl_mshr) {
+ // must be an outstanding upgrade request on block
+ // we're about to replace...
+ assert(!blk->isWritable());
+ assert(repl_mshr->needsExclusive());
+ // too hard to replace block with transient state
+ return NULL;
+ } else {
+ DPRINTF(Cache, "replacement: replacing %x with %x: %s\n",
+ repl_addr, addr,
+ blk->isDirty() ? "writeback" : "clean");
+
+ if (blk->isDirty()) {
+ // Save writeback packet for handling by caller
+ writebacks.push_back(writebackBlk(blk));
+ }
+ }
+ }
+
+ // Set tag for new block. Caller is responsible for setting status.
+ blk->tag = tags->extractTag(addr);
+ return blk;
+}
+
+
// Note that the reason we return a list of writebacks rather than
// inserting them directly in the write buffer is that this function
// is called by both atomic and timing-mode accesses, and in atomic
@@ -868,37 +918,16 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk,
if (blk == NULL) {
// better have read new data...
assert(pkt->hasData());
-
// need to do a replacement
- blk = tags->findReplacement(addr, writebacks);
- if (blk->isValid()) {
- Addr repl_addr = tags->regenerateBlkAddr(blk->tag, blk->set);
- MSHR *repl_mshr = mshrQueue.findMatch(repl_addr);
- if (repl_mshr) {
- // must be an outstanding upgrade request on block
- // we're about to replace...
- assert(!blk->isWritable());
- assert(repl_mshr->needsExclusive());
- // too hard to replace block with transient state;
- // just use temporary storage to complete the current
- // request and then get rid of it
- assert(!tempBlock->isValid());
- blk = tempBlock;
- tempBlock->set = tags->extractSet(addr);
- DPRINTF(Cache, "using temp block for %x\n", addr);
- } else {
- DPRINTF(Cache, "replacement: replacing %x with %x: %s\n",
- repl_addr, addr,
- blk->isDirty() ? "writeback" : "clean");
-
- if (blk->isDirty()) {
- // Save writeback packet for handling by caller
- writebacks.push_back(writebackBlk(blk));
- }
- }
+ blk = allocateBlock(addr, writebacks);
+ if (blk == NULL) {
+ // No replaceable block... just use temporary storage to
+ // complete the current request and then get rid of it
+ assert(!tempBlock->isValid());
+ blk = tempBlock;
+ tempBlock->set = tags->extractSet(addr);
+ DPRINTF(Cache, "using temp block for %x\n", addr);
}
-
- blk->tag = tags->extractTag(addr);
} else {
// existing block... probably an upgrade
assert(blk->tag == tags->extractTag(addr));