return true;
}
- PacketList writebacks;
int lat = hitLatency;
bool satisfied = false;
}
#if 0
+ PacketList writebacks;
+
// If this is a block size write/hint (WH64) allocate the block here
// if the coherence protocol allows it.
/** @todo make the fast write alloc (wh64) work with coherence. */
++fastWrites;
}
}
-#endif
// copy writebacks to write buffer
while (!writebacks.empty()) {
allocateBuffer(wbPkt, time, true);
writebacks.pop_front();
}
+#endif
bool needsResponse = pkt->needsResponse();
DPRINTF(Cache, "Block for addr %x being updated in Cache\n",
pkt->getAddr());
BlkType *blk = tags->findBlock(pkt->getAddr());
+
+ if (blk == NULL && pkt->cmd == MemCmd::UpgradeResp) {
+ if (!mshr->handleReplacedPendingUpgrade(pkt)) {
+ mq->markPending(mshr);
+ requestMemSideBus((RequestCause)mq->index, pkt->finishTime);
+ return;
+ }
+ }
+
PacketList writebacks;
blk = handleFill(pkt, blk, writebacks);
deallocate = satisfyMSHR(mshr, pkt, blk);
Addr addr = pkt->getAddr();
if (blk == NULL) {
- // better have read new data
+ // better have read new data...
assert(pkt->isRead());
// 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) {
+ repl_mshr->handleReplacement(blk, blkSize);
+ }
+
DPRINTF(Cache, "replacement: replacing %x with %x: %s\n",
- tags->regenerateBlkAddr(blk->tag, blk->set), addr,
- blk->isDirty() ? "writeback" : "clean");
+ repl_addr, addr, blk->isDirty() ? "writeback" : "clean");
if (blk->isDirty()) {
// Save writeback packet for handling by caller
return conflict_mshr;
}
- // No conclifts; issue read
+ // No conflicts; issue read
return miss_mshr;
}
assert(deferredTargets.empty());
deferredNeedsExclusive = false;
pendingInvalidate = false;
+ replacedPendingUpgrade = false;
+ data = NULL;
}
void
}
+void
+MSHR::handleReplacement(CacheBlk *blk, int blkSize)
+{
+ // must be an outstanding upgrade request on block we're about to
+ // replace...
+ assert(!blk->isWritable());
+ assert(needsExclusive);
+ replacedPendingUpgrade = true;
+
+ // if it's dirty, just remember what happened and allow the
+ // writeback to continue. we'll reissue a ReadEx later whether
+ // the upgrade succeeds or not
+ if (blk->isDirty()) {
+ replacedPendingUpgradeDirty = true;
+ return;
+ }
+
+ // if not dirty, we need to save it off as it will be only valid
+ // copy in system if upgrade is successful (and may need to be
+ // written back then, as the current owner if any will be
+ // invalidating its block)
+ replacedPendingUpgradeDirty = false;
+ data = new uint8_t[blkSize];
+ std::memcpy(data, blk->data, blkSize);
+}
+
+
+bool
+MSHR::handleReplacedPendingUpgrade(Packet *pkt)
+{
+ // @TODO: if upgrade is nacked and replacedPendingUpgradeDirty is true, then we need to writeback the data (or rel
+ assert(pkt->cmd == MemCmd::UpgradeResp);
+ assert(replacedPendingUpgrade);
+ replacedPendingUpgrade = false; // reset
+ if (replacedPendingUpgradeDirty) {
+ // we wrote back the previous copy; just reissue as a ReadEx
+ return false;
+ }
+
+ // previous copy was not dirty, but we are now owner... fake out
+ // cache by taking saved data and converting UpgradeResp to
+ // ReadExResp
+ assert(data);
+ pkt->cmd = MemCmd::ReadExResp;
+ pkt->setData(data);
+ delete [] data;
+ data = NULL;
+ return true;
+}
+
+
void
MSHR::dump()
{
bool deferredNeedsExclusive;
bool pendingInvalidate;
+ /** Is there a pending upgrade that got replaced? */
+ bool replacedPendingUpgrade;
+ bool replacedPendingUpgradeDirty;
/** Thread number of the miss. */
short threadNum;
/** The number of currently allocated targets. */
short ntargets;
+
+ /** Data buffer (if needed). Currently used only for pending
+ * upgrade handling. */
+ uint8_t *data;
+
/**
* Pointer to this MSHR on the ready list.
* @sa MissQueue, MSHRQueue::readyList
bool promoteDeferredTargets();
+ void handleReplacement(CacheBlk *blk, int blkSize);
+ bool handleReplacedPendingUpgrade(Packet *pkt);
+
/**
* Prints the contents of this MSHR to stderr.
*/
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",
+ set, regenerateBlkAddr(tag, set));
if (blk->whenReady > curTick
&& blk->whenReady - curTick > hitLatency) {
lat = blk->whenReady - curTick;
}
}
+ DPRINTF(Cache, "set %x: selecting blk %x for replacement\n",
+ set, regenerateBlkAddr(blk->tag, set));
return blk;
}