mshr.cc revision 7465
12810SN/A/* 22810SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 37465Ssteve.reinhardt@amd.com * Copyright (c) 2010 Advancec Micro Devices, Inc. 42810SN/A * All rights reserved. 52810SN/A * 62810SN/A * Redistribution and use in source and binary forms, with or without 72810SN/A * modification, are permitted provided that the following conditions are 82810SN/A * met: redistributions of source code must retain the above copyright 92810SN/A * notice, this list of conditions and the following disclaimer; 102810SN/A * redistributions in binary form must reproduce the above copyright 112810SN/A * notice, this list of conditions and the following disclaimer in the 122810SN/A * documentation and/or other materials provided with the distribution; 132810SN/A * neither the name of the copyright holders nor the names of its 142810SN/A * contributors may be used to endorse or promote products derived from 152810SN/A * this software without specific prior written permission. 162810SN/A * 172810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 182810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 192810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 202810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 212810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 222810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 232810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 242810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 252810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 262810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 272810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 282810SN/A * 292810SN/A * Authors: Erik Hallnor 302810SN/A * Dave Greene 312810SN/A */ 322810SN/A 332810SN/A/** 342810SN/A * @file 352810SN/A * Miss Status and Handling Register (MSHR) definitions. 362810SN/A */ 372810SN/A 386216Snate@binkert.org#include <algorithm> 396216Snate@binkert.org#include <cassert> 402810SN/A#include <string> 412810SN/A#include <vector> 422810SN/A 436216Snate@binkert.org#include "base/misc.hh" 446216Snate@binkert.org#include "base/types.hh" 456216Snate@binkert.org#include "mem/cache/cache.hh" 465338Sstever@gmail.com#include "mem/cache/mshr.hh" 476216Snate@binkert.org#include "sim/core.hh" 482810SN/A 492810SN/Ausing namespace std; 502810SN/A 512810SN/AMSHR::MSHR() 522810SN/A{ 532810SN/A inService = false; 542810SN/A ntargets = 0; 556221Snate@binkert.org threadNum = InvalidThreadID; 564903SN/A targets = new TargetList(); 574903SN/A deferredTargets = new TargetList(); 582810SN/A} 592810SN/A 604903SN/A 614903SN/AMSHR::TargetList::TargetList() 624903SN/A : needsExclusive(false), hasUpgrade(false) 634903SN/A{} 644903SN/A 654903SN/A 664903SN/Ainline void 674908SN/AMSHR::TargetList::add(PacketPtr pkt, Tick readyTime, 685875Ssteve.reinhardt@amd.com Counter order, Target::Source source, bool markPending) 694903SN/A{ 705875Ssteve.reinhardt@amd.com if (source != Target::FromSnoop) { 714903SN/A if (pkt->needsExclusive()) { 724903SN/A needsExclusive = true; 734903SN/A } 744903SN/A 757465Ssteve.reinhardt@amd.com if (pkt->isUpgrade()) { 764903SN/A hasUpgrade = true; 774903SN/A } 785318SN/A } 794908SN/A 805318SN/A if (markPending) { 814908SN/A MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState); 824908SN/A if (mshr != NULL) { 834908SN/A assert(!mshr->downstreamPending); 844908SN/A mshr->downstreamPending = true; 854908SN/A } 864903SN/A } 874903SN/A 885875Ssteve.reinhardt@amd.com push_back(Target(pkt, readyTime, order, source, markPending)); 894903SN/A} 904903SN/A 914903SN/A 924903SN/Avoid 934903SN/AMSHR::TargetList::replaceUpgrades() 944903SN/A{ 954903SN/A if (!hasUpgrade) 964903SN/A return; 974903SN/A 984903SN/A Iterator end_i = end(); 994903SN/A for (Iterator i = begin(); i != end_i; ++i) { 1004903SN/A if (i->pkt->cmd == MemCmd::UpgradeReq) { 1014903SN/A i->pkt->cmd = MemCmd::ReadExReq; 1024903SN/A DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n"); 1037465Ssteve.reinhardt@amd.com } else if (i->pkt->cmd == MemCmd::SCUpgradeReq) { 1047465Ssteve.reinhardt@amd.com i->pkt->cmd = MemCmd::SCUpgradeFailReq; 1057465Ssteve.reinhardt@amd.com DPRINTF(Cache, "Replacing SCUpgradeReq with SCUpgradeFailReq\n"); 1064903SN/A } 1074903SN/A } 1084903SN/A 1094903SN/A hasUpgrade = false; 1104903SN/A} 1114903SN/A 1124903SN/A 1132810SN/Avoid 1144908SN/AMSHR::TargetList::clearDownstreamPending() 1154908SN/A{ 1164908SN/A Iterator end_i = end(); 1174908SN/A for (Iterator i = begin(); i != end_i; ++i) { 1185318SN/A if (i->markedPending) { 1195318SN/A MSHR *mshr = dynamic_cast<MSHR*>(i->pkt->senderState); 1205318SN/A if (mshr != NULL) { 1215318SN/A mshr->clearDownstreamPending(); 1225318SN/A } 1234908SN/A } 1244908SN/A } 1254908SN/A} 1264908SN/A 1274908SN/A 1284920SN/Abool 1294920SN/AMSHR::TargetList::checkFunctional(PacketPtr pkt) 1304920SN/A{ 1314920SN/A Iterator end_i = end(); 1324920SN/A for (Iterator i = begin(); i != end_i; ++i) { 1334920SN/A if (pkt->checkFunctional(i->pkt)) { 1344920SN/A return true; 1354920SN/A } 1364920SN/A } 1374920SN/A 1384920SN/A return false; 1394920SN/A} 1404920SN/A 1414920SN/A 1424908SN/Avoid 1435314SN/AMSHR::TargetList:: 1445314SN/Aprint(std::ostream &os, int verbosity, const std::string &prefix) const 1455314SN/A{ 1465314SN/A ConstIterator end_i = end(); 1475314SN/A for (ConstIterator i = begin(); i != end_i; ++i) { 1485875Ssteve.reinhardt@amd.com const char *s; 1495875Ssteve.reinhardt@amd.com switch (i->source) { 1505875Ssteve.reinhardt@amd.com case Target::FromCPU: s = "FromCPU"; 1515875Ssteve.reinhardt@amd.com case Target::FromSnoop: s = "FromSnoop"; 1525875Ssteve.reinhardt@amd.com case Target::FromPrefetcher: s = "FromPrefetcher"; 1535875Ssteve.reinhardt@amd.com default: s = ""; 1545875Ssteve.reinhardt@amd.com } 1555875Ssteve.reinhardt@amd.com ccprintf(os, "%s%s: ", prefix, s); 1565314SN/A i->pkt->print(os, verbosity, ""); 1575314SN/A } 1585314SN/A} 1595314SN/A 1605314SN/A 1615314SN/Avoid 1624666SN/AMSHR::allocate(Addr _addr, int _size, PacketPtr target, 1634871SN/A Tick whenReady, Counter _order) 1642810SN/A{ 1652885SN/A addr = _addr; 1664626SN/A size = _size; 1674871SN/A readyTime = whenReady; 1684666SN/A order = _order; 1694626SN/A assert(target); 1705730SSteve.Reinhardt@amd.com isForward = false; 1714626SN/A _isUncacheable = target->req->isUncacheable(); 1724626SN/A inService = false; 1734908SN/A downstreamPending = false; 1744626SN/A threadNum = 0; 1754626SN/A ntargets = 1; 1765875Ssteve.reinhardt@amd.com assert(targets->isReset()); 1774626SN/A // Don't know of a case where we would allocate a new MSHR for a 1785875Ssteve.reinhardt@amd.com // snoop (mem-side request), so set source according to request here 1795875Ssteve.reinhardt@amd.com Target::Source source = (target->cmd == MemCmd::HardPFReq) ? 1805875Ssteve.reinhardt@amd.com Target::FromPrefetcher : Target::FromCPU; 1815875Ssteve.reinhardt@amd.com targets->add(target, whenReady, _order, source, true); 1824903SN/A assert(deferredTargets->isReset()); 1834665SN/A pendingInvalidate = false; 1844670SN/A pendingShared = false; 1854668SN/A data = NULL; 1862810SN/A} 1872810SN/A 1884908SN/A 1895318SN/Avoid 1905318SN/AMSHR::clearDownstreamPending() 1915318SN/A{ 1925318SN/A assert(downstreamPending); 1935318SN/A downstreamPending = false; 1945318SN/A // recursively clear flag on any MSHRs we will be forwarding 1955318SN/A // responses to 1965318SN/A targets->clearDownstreamPending(); 1975318SN/A} 1985318SN/A 1994908SN/Abool 2004908SN/AMSHR::markInService() 2014908SN/A{ 2024908SN/A assert(!inService); 2035730SSteve.Reinhardt@amd.com if (isForwardNoResponse()) { 2044908SN/A // we just forwarded the request packet & don't expect a 2054908SN/A // response, so get rid of it 2064908SN/A assert(getNumTargets() == 1); 2074908SN/A popTarget(); 2084908SN/A return true; 2094908SN/A } 2104908SN/A inService = true; 2114908SN/A if (!downstreamPending) { 2124908SN/A // let upstream caches know that the request has made it to a 2134908SN/A // level where it's going to get a response 2144908SN/A targets->clearDownstreamPending(); 2154908SN/A } 2164908SN/A return false; 2174908SN/A} 2184908SN/A 2194908SN/A 2202810SN/Avoid 2212810SN/AMSHR::deallocate() 2222810SN/A{ 2234903SN/A assert(targets->empty()); 2244903SN/A targets->resetFlags(); 2254903SN/A assert(deferredTargets->isReset()); 2262810SN/A assert(ntargets == 0); 2272810SN/A inService = false; 2282989SN/A //allocIter = NULL; 2292989SN/A //readyIter = NULL; 2302810SN/A} 2312810SN/A 2322810SN/A/* 2332810SN/A * Adds a target to an MSHR 2342810SN/A */ 2352810SN/Avoid 2364903SN/AMSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order) 2372810SN/A{ 2384903SN/A // if there's a request already in service for this MSHR, we will 2394903SN/A // have to defer the new target until after the response if any of 2404903SN/A // the following are true: 2414903SN/A // - there are other targets already deferred 2424903SN/A // - there's a pending invalidate to be applied after the response 2434903SN/A // comes back (but before this target is processed) 2444903SN/A // - the outstanding request is for a non-exclusive block and this 2454903SN/A // target requires an exclusive block 2465875Ssteve.reinhardt@amd.com 2475875Ssteve.reinhardt@amd.com // assume we'd never issue a prefetch when we've got an 2485875Ssteve.reinhardt@amd.com // outstanding miss 2495875Ssteve.reinhardt@amd.com assert(pkt->cmd != MemCmd::HardPFReq); 2505875Ssteve.reinhardt@amd.com 2514903SN/A if (inService && 2524903SN/A (!deferredTargets->empty() || pendingInvalidate || 2534903SN/A (!targets->needsExclusive && pkt->needsExclusive()))) { 2544903SN/A // need to put on deferred list 2555875Ssteve.reinhardt@amd.com deferredTargets->add(pkt, whenReady, _order, Target::FromCPU, true); 2564665SN/A } else { 2575318SN/A // No request outstanding, or still OK to append to 2585318SN/A // outstanding request: append to regular target list. Only 2595318SN/A // mark pending if current request hasn't been issued yet 2605318SN/A // (isn't in service). 2615875Ssteve.reinhardt@amd.com targets->add(pkt, whenReady, _order, Target::FromCPU, !inService); 2622810SN/A } 2632810SN/A 2642810SN/A ++ntargets; 2654665SN/A} 2664665SN/A 2674902SN/Abool 2684902SN/AMSHR::handleSnoop(PacketPtr pkt, Counter _order) 2694665SN/A{ 2704910SN/A if (!inService || (pkt->isExpressSnoop() && downstreamPending)) { 2714903SN/A // Request has not been issued yet, or it's been issued 2724903SN/A // locally but is buffered unissued at some downstream cache 2734903SN/A // which is forwarding us this snoop. Either way, the packet 2744903SN/A // we're snooping logically precedes this MSHR's request, so 2754903SN/A // the snoop has no impact on the MSHR, but must be processed 2764903SN/A // in the standard way by the cache. The only exception is 2774903SN/A // that if we're an L2+ cache buffering an UpgradeReq from a 2784903SN/A // higher-level cache, and the snoop is invalidating, then our 2794903SN/A // buffered upgrades must be converted to read exclusives, 2804903SN/A // since the upper-level cache no longer has a valid copy. 2814903SN/A // That is, even though the upper-level cache got out on its 2824903SN/A // local bus first, some other invalidating transaction 2834903SN/A // reached the global bus before the upgrade did. 2844903SN/A if (pkt->needsExclusive()) { 2854903SN/A targets->replaceUpgrades(); 2864903SN/A deferredTargets->replaceUpgrades(); 2874903SN/A } 2884903SN/A 2894902SN/A return false; 2904902SN/A } 2914665SN/A 2924903SN/A // From here on down, the request issued by this MSHR logically 2934903SN/A // precedes the request we're snooping. 2944903SN/A 2954903SN/A if (pkt->needsExclusive()) { 2964903SN/A // snooped request still precedes the re-request we'll have to 2974903SN/A // issue for deferred targets, if any... 2984903SN/A deferredTargets->replaceUpgrades(); 2994903SN/A } 3004903SN/A 3014665SN/A if (pendingInvalidate) { 3024665SN/A // a prior snoop has already appended an invalidation, so 3034903SN/A // logically we don't have the block anymore; no need for 3044903SN/A // further snooping. 3054902SN/A return true; 3064665SN/A } 3074665SN/A 3084903SN/A if (targets->needsExclusive || pkt->needsExclusive()) { 3094670SN/A // actual target device (typ. PhysicalMemory) will delete the 3104670SN/A // packet on reception, so we need to save a copy here 3114970SN/A PacketPtr cp_pkt = new Packet(pkt, true); 3125875Ssteve.reinhardt@amd.com targets->add(cp_pkt, curTick, _order, Target::FromSnoop, 3135318SN/A downstreamPending && targets->needsExclusive); 3144670SN/A ++ntargets; 3154670SN/A 3164903SN/A if (targets->needsExclusive) { 3174670SN/A // We're awaiting an exclusive copy, so ownership is pending. 3184670SN/A // It's up to us to respond once the data arrives. 3194670SN/A pkt->assertMemInhibit(); 3204916SN/A pkt->setSupplyExclusive(); 3214910SN/A } else { 3224910SN/A // Someone else may respond before we get around to 3234910SN/A // processing this snoop, which means the copied request 3244910SN/A // pointer will no longer be valid 3254910SN/A cp_pkt->req = NULL; 3264670SN/A } 3274670SN/A 3284670SN/A if (pkt->needsExclusive()) { 3294670SN/A // This transaction will take away our pending copy 3304670SN/A pendingInvalidate = true; 3314670SN/A } 3324670SN/A } else { 3334670SN/A // Read to a read: no conflict, so no need to record as 3344670SN/A // target, but make sure neither reader thinks he's getting an 3354670SN/A // exclusive copy 3364670SN/A pendingShared = true; 3374670SN/A pkt->assertShared(); 3384667SN/A } 3394902SN/A 3404902SN/A return true; 3414665SN/A} 3424665SN/A 3434665SN/A 3444665SN/Abool 3454665SN/AMSHR::promoteDeferredTargets() 3464665SN/A{ 3474903SN/A assert(targets->empty()); 3484903SN/A if (deferredTargets->empty()) { 3494665SN/A return false; 3504665SN/A } 3514665SN/A 3524903SN/A // swap targets & deferredTargets lists 3534903SN/A TargetList *tmp = targets; 3544665SN/A targets = deferredTargets; 3554903SN/A deferredTargets = tmp; 3562810SN/A 3574903SN/A assert(targets->size() == ntargets); 3584903SN/A 3594903SN/A // clear deferredTargets flags 3604903SN/A deferredTargets->resetFlags(); 3614903SN/A 3624665SN/A pendingInvalidate = false; 3634670SN/A pendingShared = false; 3644903SN/A order = targets->front().order; 3654903SN/A readyTime = std::max(curTick, targets->front().readyTime); 3664665SN/A 3674665SN/A return true; 3682810SN/A} 3692810SN/A 3702810SN/A 3712810SN/Avoid 3724670SN/AMSHR::handleFill(Packet *pkt, CacheBlk *blk) 3734668SN/A{ 3744671SN/A if (pendingShared) { 3754670SN/A // we snooped another read while this read was in 3764670SN/A // service... assert shared line on its behalf 3774670SN/A pkt->assertShared(); 3784668SN/A } 3795270SN/A 3805270SN/A if (!pkt->sharedAsserted() && !pendingInvalidate 3815270SN/A && deferredTargets->needsExclusive) { 3825270SN/A // We got an exclusive response, but we have deferred targets 3835270SN/A // which are waiting to request an exclusive copy (not because 3845270SN/A // of a pending invalidate). This can happen if the original 3855270SN/A // request was for a read-only (non-exclusive) block, but we 3865270SN/A // got an exclusive copy anyway because of the E part of the 3875270SN/A // MOESI/MESI protocol. Since we got the exclusive copy 3885270SN/A // there's no need to defer the targets, so move them up to 3895270SN/A // the regular target list. 3905270SN/A assert(!targets->needsExclusive); 3915270SN/A targets->needsExclusive = true; 3925318SN/A // if any of the deferred targets were upper-level cache 3935318SN/A // requests marked downstreamPending, need to clear that 3945318SN/A assert(!downstreamPending); // not pending here anymore 3955318SN/A deferredTargets->clearDownstreamPending(); 3965270SN/A // this clears out deferredTargets too 3975270SN/A targets->splice(targets->end(), *deferredTargets); 3985270SN/A deferredTargets->resetFlags(); 3995270SN/A } 4004668SN/A} 4014668SN/A 4024668SN/A 4035314SN/Abool 4045314SN/AMSHR::checkFunctional(PacketPtr pkt) 4055314SN/A{ 4065314SN/A // For printing, we treat the MSHR as a whole as single entity. 4075314SN/A // For other requests, we iterate over the individual targets 4085314SN/A // since that's where the actual data lies. 4095314SN/A if (pkt->isPrint()) { 4105314SN/A pkt->checkFunctional(this, addr, size, NULL); 4115314SN/A return false; 4125314SN/A } else { 4135314SN/A return (targets->checkFunctional(pkt) || 4145314SN/A deferredTargets->checkFunctional(pkt)); 4155314SN/A } 4165314SN/A} 4175314SN/A 4185314SN/A 4194668SN/Avoid 4205314SN/AMSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const 4212810SN/A{ 4225314SN/A ccprintf(os, "%s[%x:%x] %s %s %s state: %s %s %s %s\n", 4235314SN/A prefix, addr, addr+size-1, 4245730SSteve.Reinhardt@amd.com isForward ? "Forward" : "", 4255730SSteve.Reinhardt@amd.com isForwardNoResponse() ? "ForwNoResp" : "", 4265314SN/A needsExclusive() ? "Excl" : "", 4275314SN/A _isUncacheable ? "Unc" : "", 4285314SN/A inService ? "InSvc" : "", 4295314SN/A downstreamPending ? "DwnPend" : "", 4305314SN/A pendingInvalidate ? "PendInv" : "", 4315314SN/A pendingShared ? "PendShared" : ""); 4322810SN/A 4335314SN/A ccprintf(os, "%s Targets:\n", prefix); 4345314SN/A targets->print(os, verbosity, prefix + " "); 4355314SN/A if (!deferredTargets->empty()) { 4365314SN/A ccprintf(os, "%s Deferred Targets:\n", prefix); 4375314SN/A deferredTargets->print(os, verbosity, prefix + " "); 4382810SN/A } 4392810SN/A} 4402810SN/A 4412810SN/AMSHR::~MSHR() 4422810SN/A{ 4432810SN/A} 444