mshr.cc revision 11286:2071db8f864b
112854Sgabeblack@google.com/*
212854Sgabeblack@google.com * Copyright (c) 2012-2013, 2015 ARM Limited
312854Sgabeblack@google.com * All rights reserved.
412854Sgabeblack@google.com *
512854Sgabeblack@google.com * The license below extends only to copyright in the software and shall
612854Sgabeblack@google.com * not be construed as granting a license to any other intellectual
712854Sgabeblack@google.com * property including but not limited to intellectual property relating
812854Sgabeblack@google.com * to a hardware implementation of the functionality of the software
912854Sgabeblack@google.com * licensed hereunder.  You may use the software subject to the license
1012854Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated
1112854Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software,
1212854Sgabeblack@google.com * modified or unmodified, in source code or in binary form.
1312854Sgabeblack@google.com *
1412854Sgabeblack@google.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
1512854Sgabeblack@google.com * Copyright (c) 2010 Advanced Micro Devices, Inc.
1612854Sgabeblack@google.com * All rights reserved.
1712854Sgabeblack@google.com *
1812854Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
1912854Sgabeblack@google.com * modification, are permitted provided that the following conditions are
2012854Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
2112854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
2212854Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
2312854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
2412854Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
2512854Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
2612854Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
2712854Sgabeblack@google.com * this software without specific prior written permission.
2812854Sgabeblack@google.com *
2912854Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3012854Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3112854Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3212854Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3312854Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3412854Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3512854Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3612854Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3712854Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3812854Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3912854Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4012854Sgabeblack@google.com *
4112854Sgabeblack@google.com * Authors: Erik Hallnor
4212854Sgabeblack@google.com *          Dave Greene
4312854Sgabeblack@google.com */
4412854Sgabeblack@google.com
4512854Sgabeblack@google.com/**
4612854Sgabeblack@google.com * @file
4712854Sgabeblack@google.com * Miss Status and Handling Register (MSHR) definitions.
4812854Sgabeblack@google.com */
4912854Sgabeblack@google.com
5012854Sgabeblack@google.com#include <algorithm>
5112854Sgabeblack@google.com#include <cassert>
5212854Sgabeblack@google.com#include <string>
5312854Sgabeblack@google.com#include <vector>
5413322Sgabeblack@google.com
5512854Sgabeblack@google.com#include "base/misc.hh"
5612854Sgabeblack@google.com#include "base/types.hh"
5712854Sgabeblack@google.com#include "debug/Cache.hh"
5812854Sgabeblack@google.com#include "mem/cache/cache.hh"
5912854Sgabeblack@google.com#include "mem/cache/mshr.hh"
6012854Sgabeblack@google.com#include "sim/core.hh"
6112854Sgabeblack@google.com
6212854Sgabeblack@google.comusing namespace std;
6312854Sgabeblack@google.com
6412854Sgabeblack@google.comMSHR::MSHR() : readyTime(0), _isUncacheable(false), downstreamPending(false),
6512854Sgabeblack@google.com               pendingModified(false),
6612854Sgabeblack@google.com               postInvalidate(false), postDowngrade(false),
6712854Sgabeblack@google.com               queue(NULL), order(0), blkAddr(0),
6812854Sgabeblack@google.com               blkSize(0), isSecure(false), inService(false),
6912854Sgabeblack@google.com               isForward(false), allocOnFill(false),
7012854Sgabeblack@google.com               data(NULL)
7112854Sgabeblack@google.com{
7212854Sgabeblack@google.com}
7312854Sgabeblack@google.com
7412854Sgabeblack@google.com
7512854Sgabeblack@google.comMSHR::TargetList::TargetList()
7612854Sgabeblack@google.com    : needsWritable(false), hasUpgrade(false)
7712854Sgabeblack@google.com{}
7812854Sgabeblack@google.com
7912854Sgabeblack@google.com
8012854Sgabeblack@google.cominline void
8112854Sgabeblack@google.comMSHR::TargetList::add(PacketPtr pkt, Tick readyTime,
8212854Sgabeblack@google.com                      Counter order, Target::Source source, bool markPending)
8312854Sgabeblack@google.com{
8412854Sgabeblack@google.com    if (source != Target::FromSnoop) {
8512854Sgabeblack@google.com        if (pkt->needsWritable()) {
8612854Sgabeblack@google.com            needsWritable = true;
8712854Sgabeblack@google.com        }
8812854Sgabeblack@google.com
8912854Sgabeblack@google.com        // StoreCondReq is effectively an upgrade if it's in an MSHR
9012854Sgabeblack@google.com        // since it would have been failed already if we didn't have a
9112854Sgabeblack@google.com        // read-only copy
9212854Sgabeblack@google.com        if (pkt->isUpgrade() || pkt->cmd == MemCmd::StoreCondReq) {
9312854Sgabeblack@google.com            hasUpgrade = true;
9412854Sgabeblack@google.com        }
9512854Sgabeblack@google.com    }
9612854Sgabeblack@google.com
9712854Sgabeblack@google.com    if (markPending) {
9812854Sgabeblack@google.com        // Iterate over the SenderState stack and see if we find
9912854Sgabeblack@google.com        // an MSHR entry. If we do, set the downstreamPending
10012854Sgabeblack@google.com        // flag. Otherwise, do nothing.
10112854Sgabeblack@google.com        MSHR *mshr = pkt->findNextSenderState<MSHR>();
10212854Sgabeblack@google.com        if (mshr != NULL) {
10312854Sgabeblack@google.com            assert(!mshr->downstreamPending);
10412854Sgabeblack@google.com            mshr->downstreamPending = true;
10512854Sgabeblack@google.com        } else {
10612854Sgabeblack@google.com            // No need to clear downstreamPending later
10712854Sgabeblack@google.com            markPending = false;
10812854Sgabeblack@google.com        }
10912854Sgabeblack@google.com    }
11012854Sgabeblack@google.com
11112854Sgabeblack@google.com    emplace_back(pkt, readyTime, order, source, markPending);
11212854Sgabeblack@google.com}
11312854Sgabeblack@google.com
11412854Sgabeblack@google.com
11512854Sgabeblack@google.comstatic void
11612854Sgabeblack@google.comreplaceUpgrade(PacketPtr pkt)
11712854Sgabeblack@google.com{
11812854Sgabeblack@google.com    // remember if the current packet has data allocated
11912854Sgabeblack@google.com    bool has_data = pkt->hasData() || pkt->hasRespData();
12012854Sgabeblack@google.com
12112854Sgabeblack@google.com    if (pkt->cmd == MemCmd::UpgradeReq) {
12212854Sgabeblack@google.com        pkt->cmd = MemCmd::ReadExReq;
12312854Sgabeblack@google.com        DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n");
12412854Sgabeblack@google.com    } else if (pkt->cmd == MemCmd::SCUpgradeReq) {
12512854Sgabeblack@google.com        pkt->cmd = MemCmd::SCUpgradeFailReq;
12612854Sgabeblack@google.com        DPRINTF(Cache, "Replacing SCUpgradeReq with SCUpgradeFailReq\n");
12712854Sgabeblack@google.com    } else if (pkt->cmd == MemCmd::StoreCondReq) {
12812854Sgabeblack@google.com        pkt->cmd = MemCmd::StoreCondFailReq;
12912854Sgabeblack@google.com        DPRINTF(Cache, "Replacing StoreCondReq with StoreCondFailReq\n");
13012854Sgabeblack@google.com    }
13112854Sgabeblack@google.com
13212854Sgabeblack@google.com    if (!has_data) {
13312854Sgabeblack@google.com        // there is no sensible way of setting the data field if the
13412854Sgabeblack@google.com        // new command actually would carry data
13512854Sgabeblack@google.com        assert(!pkt->hasData());
13612854Sgabeblack@google.com
13712854Sgabeblack@google.com        if (pkt->hasRespData()) {
13812854Sgabeblack@google.com            // we went from a packet that had no data (neither request,
13912854Sgabeblack@google.com            // nor response), to one that does, and therefore we need to
14012854Sgabeblack@google.com            // actually allocate space for the data payload
14112854Sgabeblack@google.com            pkt->allocate();
14212854Sgabeblack@google.com        }
14312854Sgabeblack@google.com    }
14412854Sgabeblack@google.com}
14512854Sgabeblack@google.com
14612854Sgabeblack@google.com
14712854Sgabeblack@google.comvoid
14812854Sgabeblack@google.comMSHR::TargetList::replaceUpgrades()
14912854Sgabeblack@google.com{
15012854Sgabeblack@google.com    if (!hasUpgrade)
15112854Sgabeblack@google.com        return;
15212854Sgabeblack@google.com
15312854Sgabeblack@google.com    for (auto& t : *this) {
15412854Sgabeblack@google.com        replaceUpgrade(t.pkt);
15512854Sgabeblack@google.com    }
15612854Sgabeblack@google.com
15712854Sgabeblack@google.com    hasUpgrade = false;
15812854Sgabeblack@google.com}
15912854Sgabeblack@google.com
16012854Sgabeblack@google.com
16112854Sgabeblack@google.comvoid
16212854Sgabeblack@google.comMSHR::TargetList::clearDownstreamPending()
16312854Sgabeblack@google.com{
16412854Sgabeblack@google.com    for (auto& t : *this) {
16512854Sgabeblack@google.com        if (t.markedPending) {
16612854Sgabeblack@google.com            // Iterate over the SenderState stack and see if we find
16712854Sgabeblack@google.com            // an MSHR entry. If we find one, clear the
16812854Sgabeblack@google.com            // downstreamPending flag by calling
16912854Sgabeblack@google.com            // clearDownstreamPending(). This recursively clears the
17012854Sgabeblack@google.com            // downstreamPending flag in all caches this packet has
17112854Sgabeblack@google.com            // passed through.
17212854Sgabeblack@google.com            MSHR *mshr = t.pkt->findNextSenderState<MSHR>();
17312854Sgabeblack@google.com            if (mshr != NULL) {
17412854Sgabeblack@google.com                mshr->clearDownstreamPending();
17512854Sgabeblack@google.com            }
17612854Sgabeblack@google.com        }
17712854Sgabeblack@google.com    }
17812854Sgabeblack@google.com}
17912854Sgabeblack@google.com
18012854Sgabeblack@google.com
18112854Sgabeblack@google.combool
18212854Sgabeblack@google.comMSHR::TargetList::checkFunctional(PacketPtr pkt)
18312854Sgabeblack@google.com{
18412854Sgabeblack@google.com    for (auto& t : *this) {
18512854Sgabeblack@google.com        if (pkt->checkFunctional(t.pkt)) {
18612854Sgabeblack@google.com            return true;
18712854Sgabeblack@google.com        }
18812854Sgabeblack@google.com    }
18912854Sgabeblack@google.com
19012854Sgabeblack@google.com    return false;
19112854Sgabeblack@google.com}
19212854Sgabeblack@google.com
19312854Sgabeblack@google.com
19412854Sgabeblack@google.comvoid
19512854Sgabeblack@google.comMSHR::TargetList::print(std::ostream &os, int verbosity,
19612854Sgabeblack@google.com                        const std::string &prefix) const
19712854Sgabeblack@google.com{
19812854Sgabeblack@google.com    for (auto& t : *this) {
19912854Sgabeblack@google.com        const char *s;
20012854Sgabeblack@google.com        switch (t.source) {
20112854Sgabeblack@google.com          case Target::FromCPU:
20212854Sgabeblack@google.com            s = "FromCPU";
20312854Sgabeblack@google.com            break;
20412854Sgabeblack@google.com          case Target::FromSnoop:
20512854Sgabeblack@google.com            s = "FromSnoop";
20612854Sgabeblack@google.com            break;
20712854Sgabeblack@google.com          case Target::FromPrefetcher:
20812854Sgabeblack@google.com            s = "FromPrefetcher";
20912854Sgabeblack@google.com            break;
21012854Sgabeblack@google.com          default:
21112854Sgabeblack@google.com            s = "";
21212854Sgabeblack@google.com            break;
21312854Sgabeblack@google.com        }
21412854Sgabeblack@google.com        ccprintf(os, "%s%s: ", prefix, s);
21512854Sgabeblack@google.com        t.pkt->print(os, verbosity, "");
21612854Sgabeblack@google.com    }
21712854Sgabeblack@google.com}
21812854Sgabeblack@google.com
21912854Sgabeblack@google.com
22012854Sgabeblack@google.comvoid
22112854Sgabeblack@google.comMSHR::allocate(Addr blk_addr, unsigned blk_size, PacketPtr target,
22212854Sgabeblack@google.com               Tick when_ready, Counter _order, bool alloc_on_fill)
22312854Sgabeblack@google.com{
22412854Sgabeblack@google.com    blkAddr = blk_addr;
22512854Sgabeblack@google.com    blkSize = blk_size;
22612854Sgabeblack@google.com    isSecure = target->isSecure();
22712854Sgabeblack@google.com    readyTime = when_ready;
22812854Sgabeblack@google.com    order = _order;
22912854Sgabeblack@google.com    assert(target);
23012854Sgabeblack@google.com    isForward = false;
23112854Sgabeblack@google.com    allocOnFill = alloc_on_fill;
23212854Sgabeblack@google.com    _isUncacheable = target->req->isUncacheable();
23312854Sgabeblack@google.com    inService = false;
23412854Sgabeblack@google.com    downstreamPending = false;
23512854Sgabeblack@google.com    assert(targets.isReset());
23612854Sgabeblack@google.com    // Don't know of a case where we would allocate a new MSHR for a
23712854Sgabeblack@google.com    // snoop (mem-side request), so set source according to request here
23812854Sgabeblack@google.com    Target::Source source = (target->cmd == MemCmd::HardPFReq) ?
23912854Sgabeblack@google.com        Target::FromPrefetcher : Target::FromCPU;
24012854Sgabeblack@google.com    targets.add(target, when_ready, _order, source, true);
24112854Sgabeblack@google.com    assert(deferredTargets.isReset());
24212854Sgabeblack@google.com    data = NULL;
24312854Sgabeblack@google.com}
24412854Sgabeblack@google.com
24512854Sgabeblack@google.com
24612854Sgabeblack@google.comvoid
24712854Sgabeblack@google.comMSHR::clearDownstreamPending()
24812854Sgabeblack@google.com{
24912854Sgabeblack@google.com    assert(downstreamPending);
25012854Sgabeblack@google.com    downstreamPending = false;
25112854Sgabeblack@google.com    // recursively clear flag on any MSHRs we will be forwarding
25212854Sgabeblack@google.com    // responses to
25312854Sgabeblack@google.com    targets.clearDownstreamPending();
25412854Sgabeblack@google.com}
25512854Sgabeblack@google.com
25612854Sgabeblack@google.combool
25712854Sgabeblack@google.comMSHR::markInService(bool pending_modified_resp)
25812854Sgabeblack@google.com{
25912854Sgabeblack@google.com    assert(!inService);
26012854Sgabeblack@google.com    if (isForwardNoResponse()) {
26112854Sgabeblack@google.com        // we just forwarded the request packet & don't expect a
26212854Sgabeblack@google.com        // response, so get rid of it
26312854Sgabeblack@google.com        assert(getNumTargets() == 1);
26412854Sgabeblack@google.com        popTarget();
26512854Sgabeblack@google.com        return true;
26612854Sgabeblack@google.com    }
26712854Sgabeblack@google.com
26812854Sgabeblack@google.com    inService = true;
26912854Sgabeblack@google.com    pendingModified = targets.needsWritable || pending_modified_resp;
27012854Sgabeblack@google.com    postInvalidate = postDowngrade = false;
27112854Sgabeblack@google.com
27212854Sgabeblack@google.com    if (!downstreamPending) {
27312854Sgabeblack@google.com        // let upstream caches know that the request has made it to a
27412854Sgabeblack@google.com        // level where it's going to get a response
27512854Sgabeblack@google.com        targets.clearDownstreamPending();
27612854Sgabeblack@google.com    }
27712854Sgabeblack@google.com    return false;
27812854Sgabeblack@google.com}
27912854Sgabeblack@google.com
28012854Sgabeblack@google.com
28112854Sgabeblack@google.comvoid
28212854Sgabeblack@google.comMSHR::deallocate()
28312854Sgabeblack@google.com{
28412854Sgabeblack@google.com    assert(targets.empty());
28512854Sgabeblack@google.com    targets.resetFlags();
28612854Sgabeblack@google.com    assert(deferredTargets.isReset());
28712854Sgabeblack@google.com    inService = false;
28812854Sgabeblack@google.com}
28912854Sgabeblack@google.com
29012854Sgabeblack@google.com/*
29112854Sgabeblack@google.com * Adds a target to an MSHR
29212854Sgabeblack@google.com */
29312854Sgabeblack@google.comvoid
29412854Sgabeblack@google.comMSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order,
29512854Sgabeblack@google.com                     bool alloc_on_fill)
29612854Sgabeblack@google.com{
29712854Sgabeblack@google.com    // assume we'd never issue a prefetch when we've got an
29812854Sgabeblack@google.com    // outstanding miss
29912854Sgabeblack@google.com    assert(pkt->cmd != MemCmd::HardPFReq);
30012854Sgabeblack@google.com
30112854Sgabeblack@google.com    // uncacheable accesses always allocate a new MSHR, and cacheable
30212854Sgabeblack@google.com    // accesses ignore any uncacheable MSHRs, thus we should never
30312854Sgabeblack@google.com    // have targets addded if originally allocated uncacheable
30412854Sgabeblack@google.com    assert(!_isUncacheable);
30512854Sgabeblack@google.com
30612854Sgabeblack@google.com    // potentially re-evaluate whether we should allocate on a fill or
30712854Sgabeblack@google.com    // not
30812854Sgabeblack@google.com    allocOnFill = allocOnFill || alloc_on_fill;
30912854Sgabeblack@google.com
31012854Sgabeblack@google.com    // if there's a request already in service for this MSHR, we will
31112854Sgabeblack@google.com    // have to defer the new target until after the response if any of
31212854Sgabeblack@google.com    // the following are true:
31312854Sgabeblack@google.com    // - there are other targets already deferred
31412854Sgabeblack@google.com    // - there's a pending invalidate to be applied after the response
31512854Sgabeblack@google.com    //   comes back (but before this target is processed)
31612854Sgabeblack@google.com    // - this target requires a writable block and either we're not
31712854Sgabeblack@google.com    //   getting a writable block back or we have already snooped
31812854Sgabeblack@google.com    //   another read request that will downgrade our writable block
31912854Sgabeblack@google.com    //   to non-writable (Shared or Owned)
32012854Sgabeblack@google.com    if (inService &&
32112854Sgabeblack@google.com        (!deferredTargets.empty() || hasPostInvalidate() ||
32212854Sgabeblack@google.com         (pkt->needsWritable() &&
32312854Sgabeblack@google.com          (!isPendingModified() || hasPostDowngrade() || isForward)))) {
32412854Sgabeblack@google.com        // need to put on deferred list
32512854Sgabeblack@google.com        if (hasPostInvalidate())
32612854Sgabeblack@google.com            replaceUpgrade(pkt);
32712854Sgabeblack@google.com        deferredTargets.add(pkt, whenReady, _order, Target::FromCPU, true);
32812854Sgabeblack@google.com    } else {
32912854Sgabeblack@google.com        // No request outstanding, or still OK to append to
33012854Sgabeblack@google.com        // outstanding request: append to regular target list.  Only
33112854Sgabeblack@google.com        // mark pending if current request hasn't been issued yet
33212854Sgabeblack@google.com        // (isn't in service).
33312854Sgabeblack@google.com        targets.add(pkt, whenReady, _order, Target::FromCPU, !inService);
33412854Sgabeblack@google.com    }
33512854Sgabeblack@google.com}
33612854Sgabeblack@google.com
33712854Sgabeblack@google.combool
33812854Sgabeblack@google.comMSHR::handleSnoop(PacketPtr pkt, Counter _order)
33912854Sgabeblack@google.com{
34012854Sgabeblack@google.com    DPRINTF(Cache, "%s for %s addr %#llx size %d\n", __func__,
34112854Sgabeblack@google.com            pkt->cmdString(), pkt->getAddr(), pkt->getSize());
34212854Sgabeblack@google.com
34312854Sgabeblack@google.com    // when we snoop packets the needsWritable and isInvalidate flags
34412854Sgabeblack@google.com    // should always be the same, however, this assumes that we never
34512854Sgabeblack@google.com    // snoop writes as they are currently not marked as invalidations
34612854Sgabeblack@google.com    panic_if(pkt->needsWritable() != pkt->isInvalidate(),
34712854Sgabeblack@google.com             "%s got snoop %s to addr %#llx where needsWritable, "
34812854Sgabeblack@google.com             "does not match isInvalidate", name(), pkt->cmdString(),
34912854Sgabeblack@google.com             pkt->getAddr());
35012854Sgabeblack@google.com
35112854Sgabeblack@google.com    if (!inService || (pkt->isExpressSnoop() && downstreamPending)) {
35212854Sgabeblack@google.com        // Request has not been issued yet, or it's been issued
35312854Sgabeblack@google.com        // locally but is buffered unissued at some downstream cache
35412854Sgabeblack@google.com        // which is forwarding us this snoop.  Either way, the packet
35512854Sgabeblack@google.com        // we're snooping logically precedes this MSHR's request, so
35612854Sgabeblack@google.com        // the snoop has no impact on the MSHR, but must be processed
35712854Sgabeblack@google.com        // in the standard way by the cache.  The only exception is
35812854Sgabeblack@google.com        // that if we're an L2+ cache buffering an UpgradeReq from a
35912854Sgabeblack@google.com        // higher-level cache, and the snoop is invalidating, then our
36012854Sgabeblack@google.com        // buffered upgrades must be converted to read exclusives,
36112854Sgabeblack@google.com        // since the upper-level cache no longer has a valid copy.
36212854Sgabeblack@google.com        // That is, even though the upper-level cache got out on its
36312854Sgabeblack@google.com        // local bus first, some other invalidating transaction
36412854Sgabeblack@google.com        // reached the global bus before the upgrade did.
36512854Sgabeblack@google.com        if (pkt->needsWritable()) {
36612854Sgabeblack@google.com            targets.replaceUpgrades();
36712854Sgabeblack@google.com            deferredTargets.replaceUpgrades();
36812854Sgabeblack@google.com        }
36912854Sgabeblack@google.com
37012854Sgabeblack@google.com        return false;
37112854Sgabeblack@google.com    }
37212854Sgabeblack@google.com
37312854Sgabeblack@google.com    // From here on down, the request issued by this MSHR logically
37412854Sgabeblack@google.com    // precedes the request we're snooping.
37512854Sgabeblack@google.com    if (pkt->needsWritable()) {
37612854Sgabeblack@google.com        // snooped request still precedes the re-request we'll have to
37712854Sgabeblack@google.com        // issue for deferred targets, if any...
37812854Sgabeblack@google.com        deferredTargets.replaceUpgrades();
37912854Sgabeblack@google.com    }
38012854Sgabeblack@google.com
38112854Sgabeblack@google.com    if (hasPostInvalidate()) {
38212854Sgabeblack@google.com        // a prior snoop has already appended an invalidation, so
38312854Sgabeblack@google.com        // logically we don't have the block anymore; no need for
38412854Sgabeblack@google.com        // further snooping.
38512854Sgabeblack@google.com        return true;
38612854Sgabeblack@google.com    }
38713322Sgabeblack@google.com
38813322Sgabeblack@google.com    if (isPendingModified() || pkt->isInvalidate()) {
38912854Sgabeblack@google.com        // We need to save and replay the packet in two cases:
39012854Sgabeblack@google.com        // 1. We're awaiting a writable copy (Modified or Exclusive),
39112854Sgabeblack@google.com        //    so this MSHR is the orgering point, and we need to respond
39212854Sgabeblack@google.com        //    after we receive data.
39312854Sgabeblack@google.com        // 2. It's an invalidation (e.g., UpgradeReq), and we need
39412854Sgabeblack@google.com        //    to forward the snoop up the hierarchy after the current
39512854Sgabeblack@google.com        //    transaction completes.
39612854Sgabeblack@google.com
39712854Sgabeblack@google.com        // Start by determining if we will eventually respond or not,
39812854Sgabeblack@google.com        // matching the conditions checked in Cache::handleSnoop
39912854Sgabeblack@google.com        bool will_respond = isPendingModified() && pkt->needsResponse() &&
40012854Sgabeblack@google.com            pkt->cmd != MemCmd::InvalidateReq;
40112854Sgabeblack@google.com
40212854Sgabeblack@google.com        // The packet we are snooping may be deleted by the time we
40312854Sgabeblack@google.com        // actually process the target, and we consequently need to
40412854Sgabeblack@google.com        // save a copy here. Clear flags and also allocate new data as
40512854Sgabeblack@google.com        // the original packet data storage may have been deleted by
40612854Sgabeblack@google.com        // the time we get to process this packet. In the cases where
40712854Sgabeblack@google.com        // we are not responding after handling the snoop we also need
40812854Sgabeblack@google.com        // to create a copy of the request to be on the safe side. In
40912854Sgabeblack@google.com        // the latter case the cache is responsible for deleting both
41012854Sgabeblack@google.com        // the packet and the request as part of handling the deferred
41112854Sgabeblack@google.com        // snoop.
41212854Sgabeblack@google.com        PacketPtr cp_pkt = will_respond ? new Packet(pkt, true, true) :
41312854Sgabeblack@google.com            new Packet(new Request(*pkt->req), pkt->cmd);
41412854Sgabeblack@google.com
41512854Sgabeblack@google.com        if (isPendingModified()) {
41612854Sgabeblack@google.com            // we are the ordering point, and will consequently
41712854Sgabeblack@google.com            // respond, and depending on whether the packet
41812854Sgabeblack@google.com            // needsWritable or not we either pass a Shared line or a
41912854Sgabeblack@google.com            // Modified line
42012854Sgabeblack@google.com            pkt->setCacheResponding();
42112854Sgabeblack@google.com
42212854Sgabeblack@google.com            // inform the cache hierarchy that this cache had the line
42312854Sgabeblack@google.com            // in the Modified state, even if the response is passed
42412854Sgabeblack@google.com            // as Shared (and thus non-writable)
42512854Sgabeblack@google.com            pkt->setResponderHadWritable();
42612854Sgabeblack@google.com
42712854Sgabeblack@google.com            // in the case of an uncacheable request there is no need
42812854Sgabeblack@google.com            // to set the responderHadWritable flag, but since the
42912854Sgabeblack@google.com            // recipient does not care there is no harm in doing so
43012854Sgabeblack@google.com        }
43112854Sgabeblack@google.com        targets.add(cp_pkt, curTick(), _order, Target::FromSnoop,
43212854Sgabeblack@google.com                    downstreamPending && targets.needsWritable);
43312854Sgabeblack@google.com
43412854Sgabeblack@google.com        if (pkt->needsWritable()) {
43512854Sgabeblack@google.com            // This transaction will take away our pending copy
43612854Sgabeblack@google.com            postInvalidate = true;
43712854Sgabeblack@google.com        }
43812854Sgabeblack@google.com    }
43912854Sgabeblack@google.com
44012854Sgabeblack@google.com    if (!pkt->needsWritable() && !pkt->req->isUncacheable()) {
44112854Sgabeblack@google.com        // This transaction will get a read-shared copy, downgrading
44212854Sgabeblack@google.com        // our copy if we had a writable one
44312854Sgabeblack@google.com        postDowngrade = true;
44412854Sgabeblack@google.com        // make sure that any downstream cache does not respond with a
44512854Sgabeblack@google.com        // writable (and dirty) copy even if it has one, unless it was
44612854Sgabeblack@google.com        // explicitly asked for one
44712854Sgabeblack@google.com        pkt->setHasSharers();
44812854Sgabeblack@google.com    }
44912854Sgabeblack@google.com
45012854Sgabeblack@google.com    return true;
45112854Sgabeblack@google.com}
45212854Sgabeblack@google.com
45312854Sgabeblack@google.com
45412854Sgabeblack@google.combool
45512854Sgabeblack@google.comMSHR::promoteDeferredTargets()
45612854Sgabeblack@google.com{
45712854Sgabeblack@google.com    assert(targets.empty());
45812854Sgabeblack@google.com    if (deferredTargets.empty()) {
45912854Sgabeblack@google.com        return false;
46012854Sgabeblack@google.com    }
46112854Sgabeblack@google.com
46212854Sgabeblack@google.com    // swap targets & deferredTargets lists
46312854Sgabeblack@google.com    std::swap(targets, deferredTargets);
46412854Sgabeblack@google.com
46512854Sgabeblack@google.com    // clear deferredTargets flags
46612854Sgabeblack@google.com    deferredTargets.resetFlags();
46712854Sgabeblack@google.com
46812854Sgabeblack@google.com    order = targets.front().order;
46912854Sgabeblack@google.com    readyTime = std::max(curTick(), targets.front().readyTime);
47012854Sgabeblack@google.com
47112854Sgabeblack@google.com    return true;
47212854Sgabeblack@google.com}
47312854Sgabeblack@google.com
47412854Sgabeblack@google.com
47512854Sgabeblack@google.comvoid
47612854Sgabeblack@google.comMSHR::promoteWritable()
47712854Sgabeblack@google.com{
47812854Sgabeblack@google.com    if (deferredTargets.needsWritable &&
47912854Sgabeblack@google.com        !(hasPostInvalidate() || hasPostDowngrade())) {
48012854Sgabeblack@google.com        // We got a writable response, but we have deferred targets
48112854Sgabeblack@google.com        // which are waiting to request a writable copy (not because
48212854Sgabeblack@google.com        // of a pending invalidate).  This can happen if the original
48312854Sgabeblack@google.com        // request was for a read-only block, but we got a writable
48412854Sgabeblack@google.com        // response anyway. Since we got the writable copy there's no
48512854Sgabeblack@google.com        // need to defer the targets, so move them up to the regular
48612854Sgabeblack@google.com        // target list.
48712854Sgabeblack@google.com        assert(!targets.needsWritable);
48812854Sgabeblack@google.com        targets.needsWritable = true;
48912854Sgabeblack@google.com        // if any of the deferred targets were upper-level cache
49012854Sgabeblack@google.com        // requests marked downstreamPending, need to clear that
49112854Sgabeblack@google.com        assert(!downstreamPending);  // not pending here anymore
49212854Sgabeblack@google.com        deferredTargets.clearDownstreamPending();
49312854Sgabeblack@google.com        // this clears out deferredTargets too
49412854Sgabeblack@google.com        targets.splice(targets.end(), deferredTargets);
49512854Sgabeblack@google.com        deferredTargets.resetFlags();
49612854Sgabeblack@google.com    }
49712854Sgabeblack@google.com}
49812854Sgabeblack@google.com
49912854Sgabeblack@google.com
50012854Sgabeblack@google.combool
50112854Sgabeblack@google.comMSHR::checkFunctional(PacketPtr pkt)
50212854Sgabeblack@google.com{
50312854Sgabeblack@google.com    // For printing, we treat the MSHR as a whole as single entity.
50412854Sgabeblack@google.com    // For other requests, we iterate over the individual targets
50512854Sgabeblack@google.com    // since that's where the actual data lies.
50612854Sgabeblack@google.com    if (pkt->isPrint()) {
50712854Sgabeblack@google.com        pkt->checkFunctional(this, blkAddr, isSecure, blkSize, NULL);
50812854Sgabeblack@google.com        return false;
50912854Sgabeblack@google.com    } else {
51012854Sgabeblack@google.com        return (targets.checkFunctional(pkt) ||
51112854Sgabeblack@google.com                deferredTargets.checkFunctional(pkt));
51212854Sgabeblack@google.com    }
51312854Sgabeblack@google.com}
51412854Sgabeblack@google.com
51512854Sgabeblack@google.com
51612854Sgabeblack@google.comvoid
51712854Sgabeblack@google.comMSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const
51812854Sgabeblack@google.com{
51912854Sgabeblack@google.com    ccprintf(os, "%s[%#llx:%#llx](%s) %s %s %s state: %s %s %s %s %s\n",
52012854Sgabeblack@google.com             prefix, blkAddr, blkAddr + blkSize - 1,
52112854Sgabeblack@google.com             isSecure ? "s" : "ns",
52212854Sgabeblack@google.com             isForward ? "Forward" : "",
52312854Sgabeblack@google.com             allocOnFill ? "AllocOnFill" : "",
52412854Sgabeblack@google.com             isForwardNoResponse() ? "ForwNoResp" : "",
52512854Sgabeblack@google.com             needsWritable() ? "Wrtbl" : "",
52612854Sgabeblack@google.com             _isUncacheable ? "Unc" : "",
52712854Sgabeblack@google.com             inService ? "InSvc" : "",
52812854Sgabeblack@google.com             downstreamPending ? "DwnPend" : "",
52912854Sgabeblack@google.com             hasPostInvalidate() ? "PostInv" : "",
53012854Sgabeblack@google.com             hasPostDowngrade() ? "PostDowngr" : "");
53112854Sgabeblack@google.com
53212854Sgabeblack@google.com    ccprintf(os, "%s  Targets:\n", prefix);
53312854Sgabeblack@google.com    targets.print(os, verbosity, prefix + "    ");
53412854Sgabeblack@google.com    if (!deferredTargets.empty()) {
53512854Sgabeblack@google.com        ccprintf(os, "%s  Deferred Targets:\n", prefix);
53612854Sgabeblack@google.com        deferredTargets.print(os, verbosity, prefix + "      ");
53712854Sgabeblack@google.com    }
53812854Sgabeblack@google.com}
53912854Sgabeblack@google.com
54012854Sgabeblack@google.comstd::string
54112854Sgabeblack@google.comMSHR::print() const
54212854Sgabeblack@google.com{
54312854Sgabeblack@google.com    ostringstream str;
54412854Sgabeblack@google.com    print(str);
54512854Sgabeblack@google.com    return str.str();
54612854Sgabeblack@google.com}
54712854Sgabeblack@google.com