*
* Authors: Erik Hallnor
* Dave Greene
+ * Nikos Nikoleris
*/
/**
MSHR::MSHR() : downstreamPending(false),
pendingModified(false),
postInvalidate(false), postDowngrade(false),
- isForward(false)
+ wasWholeLineWrite(false), isForward(false)
{
}
if (source != Target::FromPrefetcher) {
hasFromCache = hasFromCache || pkt->fromCache();
+
+ updateWriteFlags(pkt);
}
}
}
void
-MSHR::TargetList::clearDownstreamPending()
+MSHR::TargetList::clearDownstreamPending(MSHR::TargetList::iterator begin,
+ MSHR::TargetList::iterator end)
{
- for (auto& t : *this) {
- if (t.markedPending) {
+ for (auto t = begin; t != end; t++) {
+ if (t->markedPending) {
// Iterate over the SenderState stack and see if we find
// an MSHR entry. If we find one, clear the
// downstreamPending flag by calling
// clearDownstreamPending(). This recursively clears the
// downstreamPending flag in all caches this packet has
// passed through.
- MSHR *mshr = t.pkt->findNextSenderState<MSHR>();
+ MSHR *mshr = t->pkt->findNextSenderState<MSHR>();
if (mshr != nullptr) {
mshr->clearDownstreamPending();
}
- t.markedPending = false;
+ t->markedPending = false;
}
}
}
+void
+MSHR::TargetList::clearDownstreamPending()
+{
+ clearDownstreamPending(begin(), end());
+}
+
bool
-MSHR::TargetList::checkFunctional(PacketPtr pkt)
+MSHR::TargetList::trySatisfyFunctional(PacketPtr pkt)
{
for (auto& t : *this) {
- if (pkt->checkFunctional(t.pkt)) {
+ if (pkt->trySatisfyFunctional(t.pkt)) {
return true;
}
}
order = _order;
assert(target);
isForward = false;
+ wasWholeLineWrite = false;
_isUncacheable = target->req->isUncacheable();
inService = false;
downstreamPending = false;
- assert(targets.isReset());
+
+ targets.init(blkAddr, blkSize);
+ deferredTargets.init(blkAddr, blkSize);
+
// Don't know of a case where we would allocate a new MSHR for a
// snoop (mem-side request), so set source according to request here
Target::Source source = (target->cmd == MemCmd::HardPFReq) ?
Target::FromPrefetcher : Target::FromCPU;
targets.add(target, when_ready, _order, source, true, alloc_on_fill);
- assert(deferredTargets.isReset());
}
// level where it's going to get a response
targets.clearDownstreamPending();
}
+ // if the line is not considered a whole-line write when sent
+ // downstream, make sure it is also not considered a whole-line
+ // write when receiving the response, and vice versa
+ wasWholeLineWrite = isWholeLineWrite();
}
// the packet and the request as part of handling the deferred
// snoop.
PacketPtr cp_pkt = will_respond ? new Packet(pkt, true, true) :
- new Packet(new Request(*pkt->req), pkt->cmd, blkSize, pkt->id);
+ new Packet(std::make_shared<Request>(*pkt->req), pkt->cmd,
+ blkSize, pkt->id);
if (will_respond) {
// we are the ordering point, and will consequently
MSHR::extractServiceableTargets(PacketPtr pkt)
{
TargetList ready_targets;
+ ready_targets.init(blkAddr, blkSize);
// If the downstream MSHR got an invalidation request then we only
// service the first of the FromCPU targets and any other
// non-FromCPU target. This way the remaining FromCPU targets
return true;
}
+void
+MSHR::promoteIf(const std::function<bool (Target &)>& pred)
+{
+ // if any of the deferred targets were upper-level cache
+ // requests marked downstreamPending, need to clear that
+ assert(!downstreamPending); // not pending here anymore
+
+ // find the first target does not satisfy the condition
+ auto last_it = std::find_if_not(deferredTargets.begin(),
+ deferredTargets.end(),
+ pred);
+
+ // for the prefix of the deferredTargets [begin(), last_it) clear
+ // the downstreamPending flag and move them to the target list
+ deferredTargets.clearDownstreamPending(deferredTargets.begin(),
+ last_it);
+ targets.splice(targets.end(), deferredTargets,
+ deferredTargets.begin(), last_it);
+ // We need to update the flags for the target lists after the
+ // modifications
+ deferredTargets.populateFlags();
+}
+
+void
+MSHR::promoteReadable()
+{
+ if (!deferredTargets.empty() && !hasPostInvalidate()) {
+ // We got a non invalidating response, and we have the block
+ // but we have deferred targets which are waiting and they do
+ // not need writable. This can happen if the original request
+ // was for a cache clean operation and we had a copy of the
+ // block. Since we serviced the cache clean operation and we
+ // have the block, there's no need to defer the targets, so
+ // move them up to the regular target list.
+
+ auto pred = [](Target &t) {
+ assert(t.source == Target::FromCPU);
+ return !t.pkt->req->isCacheInvalidate() &&
+ !t.pkt->needsWritable();
+ };
+ promoteIf(pred);
+ }
+}
void
MSHR::promoteWritable()
// target list.
assert(!targets.needsWritable);
targets.needsWritable = true;
- // if any of the deferred targets were upper-level cache
- // requests marked downstreamPending, need to clear that
- assert(!downstreamPending); // not pending here anymore
- deferredTargets.clearDownstreamPending();
- // this clears out deferredTargets too
- targets.splice(targets.end(), deferredTargets);
- deferredTargets.resetFlags();
+
+ auto pred = [](Target &t) {
+ assert(t.source == Target::FromCPU);
+ return !t.pkt->req->isCacheInvalidate();
+ };
+
+ promoteIf(pred);
}
}
bool
-MSHR::checkFunctional(PacketPtr pkt)
+MSHR::trySatisfyFunctional(PacketPtr pkt)
{
// For printing, we treat the MSHR as a whole as single entity.
// For other requests, we iterate over the individual targets
// since that's where the actual data lies.
if (pkt->isPrint()) {
- pkt->checkFunctional(this, blkAddr, isSecure, blkSize, nullptr);
+ pkt->trySatisfyFunctional(this, blkAddr, isSecure, blkSize, nullptr);
return false;
} else {
- return (targets.checkFunctional(pkt) ||
- deferredTargets.checkFunctional(pkt));
+ return (targets.trySatisfyFunctional(pkt) ||
+ deferredTargets.trySatisfyFunctional(pkt));
}
}