summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Reinhardt <stever@gmail.com>2008-01-02 15:22:38 -0800
committerSteve Reinhardt <stever@gmail.com>2008-01-02 15:22:38 -0800
commit6c5a3ab8b28ae14e1f1c37076b7370b37c70de62 (patch)
treed89626ebae1a7b4a14f41fe6b33d01dbcb78bdc2
parentbf9b3821bda5f534a44b176c0ed738a17cb9b80a (diff)
downloadgem5-6c5a3ab8b28ae14e1f1c37076b7370b37c70de62.tar.xz
Add ReadRespWithInvalidate to handle multi-level coherence situation
where we defer a response to a read from a far-away cache A, then later defer a ReadExcl from a cache B on the same bus as us. We'll assert MemInhibit in both cases, but in the latter case MemInhibit will keep the invalidation from reaching cache A. This special response tells cache A that it gets the block to satisfy its read, but must immediately invalidate it. --HG-- extra : convert_revision : f85c8b47bb30232da37ac861b50a6539dc81161b
-rw-r--r--src/cpu/memtest/memtest.cc13
-rw-r--r--src/mem/cache/cache.hh4
-rw-r--r--src/mem/cache/cache_impl.hh51
-rw-r--r--src/mem/packet.cc9
-rw-r--r--src/mem/packet.hh1
5 files changed, 53 insertions, 25 deletions
diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc
index 29da517b3..819b95e70 100644
--- a/src/cpu/memtest/memtest.cc
+++ b/src/cpu/memtest/memtest.cc
@@ -207,9 +207,9 @@ MemTest::completeRequest(PacketPtr pkt)
assert(removeAddr != outstandingAddrs.end());
outstandingAddrs.erase(removeAddr);
- switch (pkt->cmd.toInt()) {
- case MemCmd::ReadResp:
+ assert(pkt->isResponse());
+ if (pkt->isRead()) {
if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
panic("%s: read of %x (blk %x) @ cycle %d "
"returns %x, expected %x\n", name(),
@@ -228,14 +228,9 @@ MemTest::completeRequest(PacketPtr pkt)
if (maxLoads != 0 && numReads >= maxLoads)
exitSimLoop("maximum number of loads reached");
- break;
-
- case MemCmd::WriteResp:
+ } else {
+ assert(pkt->isWrite());
numWritesStat++;
- break;
-
- default:
- panic("invalid command %s (%d)", pkt->cmdString(), pkt->cmd.toInt());
}
noResponseCycles = 0;
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
index 4602fd835..170ba0cd1 100644
--- a/src/mem/cache/cache.hh
+++ b/src/mem/cache/cache.hh
@@ -186,7 +186,7 @@ class Cache : public BaseCache
bool satisfyMSHR(MSHR *mshr, PacketPtr pkt, BlkType *blk);
void doTimingSupplyResponse(PacketPtr req_pkt, uint8_t *blk_data,
- bool already_copied);
+ bool already_copied, bool pending_inval);
/**
* Sets the blk to the new state.
@@ -194,7 +194,7 @@ class Cache : public BaseCache
* @param new_state The new coherence state for the block.
*/
void handleSnoop(PacketPtr ptk, BlkType *blk,
- bool is_timing, bool is_deferred);
+ bool is_timing, bool is_deferred, bool pending_inval);
/**
* Create a writeback request for the given block.
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index 130a909cc..ed65fbabb 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -775,18 +775,31 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
// if this packet is an error copy that to the new packet
if (is_error)
target->pkt->copyError(pkt);
+ if (pkt->isInvalidate()) {
+ // If intermediate cache got ReadRespWithInvalidate,
+ // propagate that. Response should not have
+ // isInvalidate() set otherwise.
+ assert(target->pkt->cmd == MemCmd::ReadResp);
+ assert(pkt->cmd == MemCmd::ReadRespWithInvalidate);
+ target->pkt->cmd = MemCmd::ReadRespWithInvalidate;
+ }
cpuSidePort->respond(target->pkt, completion_time);
} else {
// I don't believe that a snoop can be in an error state
assert(!is_error);
// response to snoop request
DPRINTF(Cache, "processing deferred snoop...\n");
- handleSnoop(target->pkt, blk, true, true);
+ handleSnoop(target->pkt, blk, true, true,
+ mshr->pendingInvalidate || pkt->isInvalidate());
}
mshr->popTarget();
}
+ if (pkt->isInvalidate()) {
+ tags->invalidateBlk(blk);
+ }
+
if (mshr->promoteDeferredTargets()) {
MSHRQueue *mq = mshr->queue;
mq->markPending(mshr);
@@ -854,7 +867,7 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk,
if (blk == NULL) {
// better have read new data...
- assert(pkt->isRead());
+ assert(pkt->hasData());
// need to do a replacement
blk = tags->findReplacement(addr, writebacks);
@@ -890,7 +903,7 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk,
// existing block... probably an upgrade
assert(blk->tag == tags->extractTag(addr));
// either we're getting new data or the block should already be valid
- assert(pkt->isRead() || blk->isValid());
+ assert(pkt->hasData() || blk->isValid());
}
if (!pkt->sharedAsserted()) {
@@ -922,9 +935,9 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk,
template<class TagStore>
void
-Cache<TagStore>::doTimingSupplyResponse(PacketPtr req_pkt,
- uint8_t *blk_data,
- bool already_copied)
+Cache<TagStore>::
+doTimingSupplyResponse(PacketPtr req_pkt, uint8_t *blk_data,
+ bool already_copied, bool pending_inval)
{
// timing-mode snoop responses require a new packet, unless we
// already made a copy...
@@ -941,14 +954,29 @@ Cache<TagStore>::doTimingSupplyResponse(PacketPtr req_pkt,
if (pkt->isRead()) {
pkt->setDataFromBlock(blk_data, blkSize);
}
+ if (pkt->cmd == MemCmd::ReadResp && pending_inval) {
+ // Assume we defer a response to a read from a far-away cache
+ // A, then later defer a ReadExcl from a cache B on the same
+ // bus as us. We'll assert MemInhibit in both cases, but in
+ // the latter case MemInhibit will keep the invalidation from
+ // reaching cache A. This special response tells cache A that
+ // it gets the block to satisfy its read, but must immediately
+ // invalidate it.
+ pkt->cmd = MemCmd::ReadRespWithInvalidate;
+ }
memSidePort->respond(pkt, curTick + hitLatency);
}
template<class TagStore>
void
Cache<TagStore>::handleSnoop(PacketPtr pkt, BlkType *blk,
- bool is_timing, bool is_deferred)
+ bool is_timing, bool is_deferred,
+ bool pending_inval)
{
+ // deferred snoops can only happen in timing mode
+ assert(!(is_deferred && !is_timing));
+ // pending_inval only makes sense on deferred snoops
+ assert(!(pending_inval && !is_deferred));
assert(pkt->isRequest());
// first propagate snoop upward to see if anyone above us wants to
@@ -1018,7 +1046,7 @@ Cache<TagStore>::handleSnoop(PacketPtr pkt, BlkType *blk,
pkt->setSupplyExclusive();
}
if (is_timing) {
- doTimingSupplyResponse(pkt, blk->data, is_deferred);
+ doTimingSupplyResponse(pkt, blk->data, is_deferred, pending_inval);
} else {
pkt->makeAtomicResponse();
pkt->setDataFromBlock(blk->data, blkSize);
@@ -1085,7 +1113,8 @@ Cache<TagStore>::snoopTiming(PacketPtr pkt)
// the packet's invalidate flag is set...
assert(pkt->isInvalidate());
}
- doTimingSupplyResponse(pkt, wb_pkt->getPtr<uint8_t>(), false);
+ doTimingSupplyResponse(pkt, wb_pkt->getPtr<uint8_t>(),
+ false, false);
if (pkt->isInvalidate()) {
// Invalidation trumps our writeback... discard here
@@ -1101,7 +1130,7 @@ Cache<TagStore>::snoopTiming(PacketPtr pkt)
}
}
- handleSnoop(pkt, blk, true, false);
+ handleSnoop(pkt, blk, true, false, false);
}
@@ -1116,7 +1145,7 @@ Cache<TagStore>::snoopAtomic(PacketPtr pkt)
}
BlkType *blk = tags->findBlock(pkt->getAddr());
- handleSnoop(pkt, blk, false, false);
+ handleSnoop(pkt, blk, false, false, false);
return hitLatency;
}
diff --git a/src/mem/packet.cc b/src/mem/packet.cc
index 164363860..f3bd06f36 100644
--- a/src/mem/packet.cc
+++ b/src/mem/packet.cc
@@ -59,6 +59,9 @@ MemCmd::commandInfo[] =
{ SET3(IsRead, IsRequest, NeedsResponse), ReadResp, "ReadReq" },
/* ReadResp */
{ SET3(IsRead, IsResponse, HasData), InvalidCmd, "ReadResp" },
+ /* ReadRespWithInvalidate */
+ { SET4(IsRead, IsResponse, HasData, IsInvalidate),
+ InvalidCmd, "ReadRespWithInvalidate" },
/* WriteReq */
{ SET5(IsWrite, NeedsExclusive, IsRequest, NeedsResponse, HasData),
WriteResp, "WriteReq" },
@@ -84,19 +87,19 @@ MemCmd::commandInfo[] =
IsRequest, HasData, NeedsResponse),
WriteInvalidateResp, "WriteInvalidateReq" },
/* WriteInvalidateResp */
- { SET4(IsWrite, NeedsExclusive, IsInvalidate, IsResponse),
+ { SET3(IsWrite, NeedsExclusive, IsResponse),
InvalidCmd, "WriteInvalidateResp" },
/* UpgradeReq */
{ SET4(IsInvalidate, NeedsExclusive, IsRequest, NeedsResponse),
UpgradeResp, "UpgradeReq" },
/* UpgradeResp */
- { SET3(IsInvalidate, NeedsExclusive, IsResponse),
+ { SET2(NeedsExclusive, IsResponse),
InvalidCmd, "UpgradeResp" },
/* ReadExReq */
{ SET5(IsRead, NeedsExclusive, IsInvalidate, IsRequest, NeedsResponse),
ReadExResp, "ReadExReq" },
/* ReadExResp */
- { SET5(IsRead, NeedsExclusive, IsInvalidate, IsResponse, HasData),
+ { SET4(IsRead, NeedsExclusive, IsResponse, HasData),
InvalidCmd, "ReadExResp" },
/* LoadLockedReq */
{ SET4(IsRead, IsLocked, IsRequest, NeedsResponse),
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
index 30ef71507..05442b369 100644
--- a/src/mem/packet.hh
+++ b/src/mem/packet.hh
@@ -66,6 +66,7 @@ class MemCmd
InvalidCmd,
ReadReq,
ReadResp,
+ ReadRespWithInvalidate,
WriteReq,
WriteResp,
Writeback,