summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/cache/cache_impl.hh45
-rw-r--r--src/mem/cache/mshr.cc28
-rw-r--r--src/mem/cache/mshr.hh18
-rw-r--r--src/mem/cache/mshr_queue.cc3
-rw-r--r--src/mem/dram_ctrl.cc2
-rw-r--r--src/mem/simple_mem.cc5
6 files changed, 87 insertions, 14 deletions
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index 24e3eec15..66abf6eff 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -345,7 +345,6 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk,
blk->status |= BlkSecure;
}
}
- std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
if (pkt->cmd == MemCmd::Writeback) {
blk->status |= BlkDirty;
if (pkt->isSupplyExclusive()) {
@@ -354,11 +353,11 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk,
// nothing else to do; writeback doesn't expect response
assert(!pkt->needsResponse());
} else if (pkt->cmd == MemCmd::WriteInvalidateReq) {
- assert(blk->isReadable()); // implicitly checks for Valid bit also
- blk->status |= (BlkDirty | BlkCanGoExclusive);
+ blk->status |= (BlkReadable | BlkDirty | BlkCanGoExclusive);
blk->status &= ~BlkWritable;
++fastWrites;
}
+ std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print());
incHitCount(pkt);
return true;
@@ -636,7 +635,20 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt)
pkt = pf;
}
- if (mshr) {
+ if (pkt && (pkt->cmd == MemCmd::WriteInvalidateReq)) {
+ // WriteInvalidates cannot coalesce with other requests, so
+ // we cannot use an existing MSHR. If one exists, we mark it
+ // as 'obsolete' so they don't modify the cache.
+ if (mshr) {
+ // Everything up to this point is obsolete, meaning
+ // they should not modify the cache.
+ DPRINTF(Cache, "%s: marking MSHR obsolete in %s of %x\n",
+ __func__, pkt->cmdString(), pkt->getAddr());
+
+ mshr->markObsolete();
+ }
+ allocateMissBuffer(pkt, time, true);
+ } else if (mshr) {
/// MSHR hit
/// @note writebacks will be checked in getNextMSHR()
/// for any conflicting requests to the same block
@@ -1077,7 +1089,10 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt)
bool is_fill = !mshr->isForward &&
(pkt->isRead() || pkt->cmd == MemCmd::UpgradeResp);
- if (is_fill && !is_error) {
+ if (mshr->isObsolete()) {
+ DPRINTF(Cache, "%s: skipping cache fills; data for %s of %x "
+ "is obsolete\n", __func__, pkt->cmdString(), pkt->getAddr());
+ } else if (is_fill && !is_error) {
DPRINTF(Cache, "Block for addr %x being updated in Cache\n",
pkt->getAddr());
@@ -1113,8 +1128,19 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt)
}
if (is_fill) {
- satisfyCpuSideRequest(target->pkt, blk,
- true, mshr->hasPostDowngrade());
+ // Presently the only situation leading to 'obsolete'
+ // data is when a WriteInvalidate blows away an already
+ // pending/in-progress read. We don't want to overwrite
+ // cache data in that case.
+ if (mshr->isObsolete()) {
+ DPRINTF(Cache, "%s: skipping satisfyCpuSideRequest; "
+ "data for %s of %x is obsolete\n",
+ __func__, target->pkt->cmdString(),
+ target->pkt->getAddr());
+ } else {
+ satisfyCpuSideRequest(target->pkt, blk,
+ true, mshr->hasPostDowngrade());
+ }
// How many bytes past the first request is this one
int transfer_offset =
target->pkt->getOffset(blkSize) - initial_offset;
@@ -1490,6 +1516,11 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk,
// there are cases (such as failed store conditionals or
// compare-and-swaps) where we'll demand an exclusive copy but
// end up not writing it.
+ // Caveat: if a Read takes a value from a WriteInvalidate MSHR,
+ // it will get marked Dirty even though it is Clean (once the
+ // WriteInvalidate completes). This is due to insufficient meta-
+ // data and overly presumptive interpretation of the inhibit flag.
+ // The result is an unnecessary extra writeback.
if (pkt->memInhibitAsserted())
blk->status |= BlkDirty;
}
diff --git a/src/mem/cache/mshr.cc b/src/mem/cache/mshr.cc
index 79a91da2b..bc46ed267 100644
--- a/src/mem/cache/mshr.cc
+++ b/src/mem/cache/mshr.cc
@@ -62,10 +62,11 @@
using namespace std;
MSHR::MSHR() : readyTime(0), _isUncacheable(false), downstreamPending(false),
- pendingDirty(false), postInvalidate(false),
- postDowngrade(false), queue(NULL), order(0), addr(0), size(0),
- isSecure(false), inService(false), isForward(false),
- threadNum(InvalidThreadID), data(NULL)
+ pendingDirty(false), pendingClean(false),
+ postInvalidate(false), postDowngrade(false),
+ _isObsolete(false), queue(NULL), order(0), addr(0),
+ size(0), isSecure(false), inService(false),
+ isForward(false), threadNum(InvalidThreadID), data(NULL)
{
}
@@ -213,7 +214,9 @@ MSHR::allocate(Addr _addr, int _size, PacketPtr target, Tick whenReady,
isForward = false;
_isUncacheable = target->req->isUncacheable();
inService = false;
+ pendingClean = (target->cmd == MemCmd::WriteInvalidateReq);
downstreamPending = false;
+ _isObsolete = false;
threadNum = 0;
assert(targets.isReset());
// Don't know of a case where we would allocate a new MSHR for a
@@ -250,7 +253,8 @@ MSHR::markInService(PacketPtr pkt)
assert(pkt != NULL);
inService = true;
- pendingDirty = (targets.needsExclusive ||
+ pendingDirty = ((targets.needsExclusive &&
+ (pkt->cmd != MemCmd::WriteInvalidateReq)) ||
(!pkt->sharedAsserted() && pkt->memInhibitAsserted()));
postInvalidate = postDowngrade = false;
@@ -366,7 +370,12 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
targets.add(cp_pkt, curTick(), _order, Target::FromSnoop,
downstreamPending && targets.needsExclusive);
- if (isPendingDirty()) {
+ // WriteInvalidates must writeback and should not be inhibited on
+ // account of its snoops discovering MSHRs wanting exclusive access
+ // to what it wrote. We don't want to push this check higher,
+ // however, because we want to be sure to add an invalidating
+ // Target::FromSnoop, above.
+ if (isPendingDirty() && (pkt->cmd != MemCmd::WriteInvalidateReq)) {
pkt->assertMemInhibit();
pkt->setSupplyExclusive();
}
@@ -374,6 +383,13 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
if (pkt->needsExclusive()) {
// This transaction will take away our pending copy
postInvalidate = true;
+
+ // Do not defer (i.e. return true) the snoop if the block is
+ // going to be clean once the MSHR completes, as the data is
+ // ready now.
+ if (isPendingClean()) {
+ return false;
+ }
}
}
diff --git a/src/mem/cache/mshr.hh b/src/mem/cache/mshr.hh
index 65357b9e6..e5a15b61d 100644
--- a/src/mem/cache/mshr.hh
+++ b/src/mem/cache/mshr.hh
@@ -83,12 +83,18 @@ class MSHR : public Packet::SenderState, public Printable
/** Will we have a dirty copy after this request? */
bool pendingDirty;
+ /** Will we have a clean copy after this request? (i.e. is writeback) */
+ bool pendingClean;
+
/** Did we snoop an invalidate while waiting for data? */
bool postInvalidate;
/** Did we snoop a read while waiting for data? */
bool postDowngrade;
+ /** Did we get WriteInvalidate'd (and therefore obsoleted)? */
+ bool _isObsolete;
+
public:
class Target {
@@ -176,6 +182,10 @@ class MSHR : public Packet::SenderState, public Printable
assert(inService); return pendingDirty;
}
+ bool isPendingClean() const {
+ return pendingClean;
+ }
+
bool hasPostInvalidate() const {
assert(inService); return postInvalidate;
}
@@ -214,6 +224,8 @@ class MSHR : public Packet::SenderState, public Printable
bool isUncacheable() const { return _isUncacheable; }
+ bool isObsolete() const { return _isObsolete; }
+
/**
* Allocate a miss to this MSHR.
* @param cmd The requesting command.
@@ -289,6 +301,12 @@ class MSHR : public Packet::SenderState, public Printable
bool checkFunctional(PacketPtr pkt);
+ /** Mark this MSHR as tracking a transaction with obsoleted data. It still
+ * needs to complete its lifecycle, but should not modify the cache. */
+ void markObsolete() {
+ _isObsolete = true;
+ }
+
/**
* Prints the contents of this MSHR for debugging.
*/
diff --git a/src/mem/cache/mshr_queue.cc b/src/mem/cache/mshr_queue.cc
index 7bfbb90f5..9146cddf7 100644
--- a/src/mem/cache/mshr_queue.cc
+++ b/src/mem/cache/mshr_queue.cc
@@ -45,7 +45,9 @@
* Definition of MSHRQueue class functions.
*/
+#include "base/trace.hh"
#include "mem/cache/mshr_queue.hh"
+#include "debug/Drain.hh"
using namespace std;
@@ -191,6 +193,7 @@ MSHRQueue::deallocateOne(MSHR *mshr)
if (drainManager && allocated == 0) {
// Notify the drain manager that we have completed draining if
// there are no other outstanding requests in this MSHR queue.
+ DPRINTF(Drain, "MSHRQueue now empty, signalling drained\n");
drainManager->signalDrainDone();
drainManager = NULL;
setDrainState(Drainable::Drained);
diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc
index f65f7e1dd..1beebdd01 100644
--- a/src/mem/dram_ctrl.cc
+++ b/src/mem/dram_ctrl.cc
@@ -737,6 +737,7 @@ DRAMCtrl::processRespondEvent()
// if there is nothing left in any queue, signal a drain
if (writeQueue.empty() && readQueue.empty() &&
drainManager) {
+ DPRINTF(Drain, "DRAM controller done draining\n");
drainManager->signalDrainDone();
drainManager = NULL;
}
@@ -1290,6 +1291,7 @@ DRAMCtrl::processNextReqEvent()
} else {
// check if we are drained
if (respQueue.empty () && drainManager) {
+ DPRINTF(Drain, "DRAM controller done draining\n");
drainManager->signalDrainDone();
drainManager = NULL;
}
diff --git a/src/mem/simple_mem.cc b/src/mem/simple_mem.cc
index 27d3f1186..4e1020de5 100644
--- a/src/mem/simple_mem.cc
+++ b/src/mem/simple_mem.cc
@@ -44,6 +44,7 @@
#include "base/random.hh"
#include "mem/simple_mem.hh"
+#include "debug/Drain.hh"
using namespace std;
@@ -200,6 +201,7 @@ SimpleMemory::dequeue()
reschedule(dequeueEvent,
std::max(packetQueue.front().tick, curTick()), true);
} else if (drainManager) {
+ DPRINTF(Drain, "Drainng of SimpleMemory complete\n");
drainManager->signalDrainDone();
drainManager = NULL;
}
@@ -240,7 +242,8 @@ SimpleMemory::drain(DrainManager *dm)
if (!packetQueue.empty()) {
count += 1;
drainManager = dm;
- }
+ DPRINTF(Drain, "SimpleMemory Queue has requests, waiting to drain\n");
+ }
if (count)
setDrainState(Drainable::Draining);