mshr.cc revision 5338
12810SN/A/* 22810SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 32810SN/A * All rights reserved. 42810SN/A * 52810SN/A * Redistribution and use in source and binary forms, with or without 62810SN/A * modification, are permitted provided that the following conditions are 72810SN/A * met: redistributions of source code must retain the above copyright 82810SN/A * notice, this list of conditions and the following disclaimer; 92810SN/A * redistributions in binary form must reproduce the above copyright 102810SN/A * notice, this list of conditions and the following disclaimer in the 112810SN/A * documentation and/or other materials provided with the distribution; 122810SN/A * neither the name of the copyright holders nor the names of its 132810SN/A * contributors may be used to endorse or promote products derived from 142810SN/A * this software without specific prior written permission. 152810SN/A * 162810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272810SN/A * 282810SN/A * Authors: Erik Hallnor 292810SN/A * Dave Greene 302810SN/A */ 312810SN/A 322810SN/A/** 332810SN/A * @file 342810SN/A * Miss Status and Handling Register (MSHR) definitions. 352810SN/A */ 362810SN/A 372810SN/A#include <assert.h> 382810SN/A#include <string> 392810SN/A#include <vector> 404666SN/A#include <algorithm> 412810SN/A 425338Sstever@gmail.com#include "mem/cache/mshr.hh" 434167SN/A#include "sim/core.hh" // for curTick 442810SN/A#include "sim/host.hh" 452810SN/A#include "base/misc.hh" 462810SN/A#include "mem/cache/cache.hh" 472810SN/A 482810SN/Ausing namespace std; 492810SN/A 502810SN/AMSHR::MSHR() 512810SN/A{ 522810SN/A inService = false; 532810SN/A ntargets = 0; 542813SN/A threadNum = -1; 554903SN/A targets = new TargetList(); 564903SN/A deferredTargets = new TargetList(); 572810SN/A} 582810SN/A 594903SN/A 604903SN/AMSHR::TargetList::TargetList() 614903SN/A : needsExclusive(false), hasUpgrade(false) 624903SN/A{} 634903SN/A 644903SN/A 654903SN/Ainline void 664908SN/AMSHR::TargetList::add(PacketPtr pkt, Tick readyTime, 675318SN/A Counter order, bool cpuSide, bool markPending) 684903SN/A{ 694903SN/A if (cpuSide) { 704903SN/A if (pkt->needsExclusive()) { 714903SN/A needsExclusive = true; 724903SN/A } 734903SN/A 744903SN/A if (pkt->cmd == MemCmd::UpgradeReq) { 754903SN/A hasUpgrade = true; 764903SN/A } 775318SN/A } 784908SN/A 795318SN/A if (markPending) { 804908SN/A MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState); 814908SN/A if (mshr != NULL) { 824908SN/A assert(!mshr->downstreamPending); 834908SN/A mshr->downstreamPending = true; 844908SN/A } 854903SN/A } 864903SN/A 875318SN/A push_back(Target(pkt, readyTime, order, cpuSide, markPending)); 884903SN/A} 894903SN/A 904903SN/A 914903SN/Avoid 924903SN/AMSHR::TargetList::replaceUpgrades() 934903SN/A{ 944903SN/A if (!hasUpgrade) 954903SN/A return; 964903SN/A 974903SN/A Iterator end_i = end(); 984903SN/A for (Iterator i = begin(); i != end_i; ++i) { 994903SN/A if (i->pkt->cmd == MemCmd::UpgradeReq) { 1004903SN/A i->pkt->cmd = MemCmd::ReadExReq; 1014903SN/A DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n"); 1024903SN/A } 1034903SN/A } 1044903SN/A 1054903SN/A hasUpgrade = false; 1064903SN/A} 1074903SN/A 1084903SN/A 1092810SN/Avoid 1104908SN/AMSHR::TargetList::clearDownstreamPending() 1114908SN/A{ 1124908SN/A Iterator end_i = end(); 1134908SN/A for (Iterator i = begin(); i != end_i; ++i) { 1145318SN/A if (i->markedPending) { 1155318SN/A MSHR *mshr = dynamic_cast<MSHR*>(i->pkt->senderState); 1165318SN/A if (mshr != NULL) { 1175318SN/A mshr->clearDownstreamPending(); 1185318SN/A } 1194908SN/A } 1204908SN/A } 1214908SN/A} 1224908SN/A 1234908SN/A 1244920SN/Abool 1254920SN/AMSHR::TargetList::checkFunctional(PacketPtr pkt) 1264920SN/A{ 1274920SN/A Iterator end_i = end(); 1284920SN/A for (Iterator i = begin(); i != end_i; ++i) { 1294920SN/A if (pkt->checkFunctional(i->pkt)) { 1304920SN/A return true; 1314920SN/A } 1324920SN/A } 1334920SN/A 1344920SN/A return false; 1354920SN/A} 1364920SN/A 1374920SN/A 1384908SN/Avoid 1395314SN/AMSHR::TargetList:: 1405314SN/Aprint(std::ostream &os, int verbosity, const std::string &prefix) const 1415314SN/A{ 1425314SN/A ConstIterator end_i = end(); 1435314SN/A for (ConstIterator i = begin(); i != end_i; ++i) { 1445314SN/A ccprintf(os, "%s%s: ", prefix, i->isCpuSide() ? "cpu" : "mem"); 1455314SN/A i->pkt->print(os, verbosity, ""); 1465314SN/A } 1475314SN/A} 1485314SN/A 1495314SN/A 1505314SN/Avoid 1514666SN/AMSHR::allocate(Addr _addr, int _size, PacketPtr target, 1524871SN/A Tick whenReady, Counter _order) 1532810SN/A{ 1542885SN/A addr = _addr; 1554626SN/A size = _size; 1564871SN/A readyTime = whenReady; 1574666SN/A order = _order; 1584626SN/A assert(target); 1594628SN/A isCacheFill = false; 1604626SN/A _isUncacheable = target->req->isUncacheable(); 1614626SN/A inService = false; 1624908SN/A downstreamPending = false; 1634626SN/A threadNum = 0; 1644626SN/A ntargets = 1; 1654626SN/A // Don't know of a case where we would allocate a new MSHR for a 1664666SN/A // snoop (mem-side request), so set cpuSide to true here. 1674903SN/A assert(targets->isReset()); 1685318SN/A targets->add(target, whenReady, _order, true, true); 1694903SN/A assert(deferredTargets->isReset()); 1704665SN/A pendingInvalidate = false; 1714670SN/A pendingShared = false; 1724668SN/A data = NULL; 1732810SN/A} 1742810SN/A 1754908SN/A 1765318SN/Avoid 1775318SN/AMSHR::clearDownstreamPending() 1785318SN/A{ 1795318SN/A assert(downstreamPending); 1805318SN/A downstreamPending = false; 1815318SN/A // recursively clear flag on any MSHRs we will be forwarding 1825318SN/A // responses to 1835318SN/A targets->clearDownstreamPending(); 1845318SN/A} 1855318SN/A 1864908SN/Abool 1874908SN/AMSHR::markInService() 1884908SN/A{ 1894908SN/A assert(!inService); 1904908SN/A if (isSimpleForward()) { 1914908SN/A // we just forwarded the request packet & don't expect a 1924908SN/A // response, so get rid of it 1934908SN/A assert(getNumTargets() == 1); 1944908SN/A popTarget(); 1954908SN/A return true; 1964908SN/A } 1974908SN/A inService = true; 1984908SN/A if (!downstreamPending) { 1994908SN/A // let upstream caches know that the request has made it to a 2004908SN/A // level where it's going to get a response 2014908SN/A targets->clearDownstreamPending(); 2024908SN/A } 2034908SN/A return false; 2044908SN/A} 2054908SN/A 2064908SN/A 2072810SN/Avoid 2082810SN/AMSHR::deallocate() 2092810SN/A{ 2104903SN/A assert(targets->empty()); 2114903SN/A targets->resetFlags(); 2124903SN/A assert(deferredTargets->isReset()); 2132810SN/A assert(ntargets == 0); 2142810SN/A inService = false; 2152989SN/A //allocIter = NULL; 2162989SN/A //readyIter = NULL; 2172810SN/A} 2182810SN/A 2192810SN/A/* 2202810SN/A * Adds a target to an MSHR 2212810SN/A */ 2222810SN/Avoid 2234903SN/AMSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order) 2242810SN/A{ 2254903SN/A // if there's a request already in service for this MSHR, we will 2264903SN/A // have to defer the new target until after the response if any of 2274903SN/A // the following are true: 2284903SN/A // - there are other targets already deferred 2294903SN/A // - there's a pending invalidate to be applied after the response 2304903SN/A // comes back (but before this target is processed) 2314903SN/A // - the outstanding request is for a non-exclusive block and this 2324903SN/A // target requires an exclusive block 2334903SN/A if (inService && 2344903SN/A (!deferredTargets->empty() || pendingInvalidate || 2354903SN/A (!targets->needsExclusive && pkt->needsExclusive()))) { 2364903SN/A // need to put on deferred list 2375318SN/A deferredTargets->add(pkt, whenReady, _order, true, true); 2384665SN/A } else { 2395318SN/A // No request outstanding, or still OK to append to 2405318SN/A // outstanding request: append to regular target list. Only 2415318SN/A // mark pending if current request hasn't been issued yet 2425318SN/A // (isn't in service). 2435318SN/A targets->add(pkt, whenReady, _order, true, !inService); 2442810SN/A } 2452810SN/A 2462810SN/A ++ntargets; 2474665SN/A} 2484665SN/A 2494902SN/Abool 2504902SN/AMSHR::handleSnoop(PacketPtr pkt, Counter _order) 2514665SN/A{ 2524910SN/A if (!inService || (pkt->isExpressSnoop() && downstreamPending)) { 2534903SN/A // Request has not been issued yet, or it's been issued 2544903SN/A // locally but is buffered unissued at some downstream cache 2554903SN/A // which is forwarding us this snoop. Either way, the packet 2564903SN/A // we're snooping logically precedes this MSHR's request, so 2574903SN/A // the snoop has no impact on the MSHR, but must be processed 2584903SN/A // in the standard way by the cache. The only exception is 2594903SN/A // that if we're an L2+ cache buffering an UpgradeReq from a 2604903SN/A // higher-level cache, and the snoop is invalidating, then our 2614903SN/A // buffered upgrades must be converted to read exclusives, 2624903SN/A // since the upper-level cache no longer has a valid copy. 2634903SN/A // That is, even though the upper-level cache got out on its 2644903SN/A // local bus first, some other invalidating transaction 2654903SN/A // reached the global bus before the upgrade did. 2664903SN/A if (pkt->needsExclusive()) { 2674903SN/A targets->replaceUpgrades(); 2684903SN/A deferredTargets->replaceUpgrades(); 2694903SN/A } 2704903SN/A 2714902SN/A return false; 2724902SN/A } 2734665SN/A 2744903SN/A // From here on down, the request issued by this MSHR logically 2754903SN/A // precedes the request we're snooping. 2764903SN/A 2774903SN/A if (pkt->needsExclusive()) { 2784903SN/A // snooped request still precedes the re-request we'll have to 2794903SN/A // issue for deferred targets, if any... 2804903SN/A deferredTargets->replaceUpgrades(); 2814903SN/A } 2824903SN/A 2834665SN/A if (pendingInvalidate) { 2844665SN/A // a prior snoop has already appended an invalidation, so 2854903SN/A // logically we don't have the block anymore; no need for 2864903SN/A // further snooping. 2874902SN/A return true; 2884665SN/A } 2894665SN/A 2904903SN/A if (targets->needsExclusive || pkt->needsExclusive()) { 2914670SN/A // actual target device (typ. PhysicalMemory) will delete the 2924670SN/A // packet on reception, so we need to save a copy here 2934970SN/A PacketPtr cp_pkt = new Packet(pkt, true); 2945318SN/A targets->add(cp_pkt, curTick, _order, false, 2955318SN/A downstreamPending && targets->needsExclusive); 2964670SN/A ++ntargets; 2974670SN/A 2984903SN/A if (targets->needsExclusive) { 2994670SN/A // We're awaiting an exclusive copy, so ownership is pending. 3004670SN/A // It's up to us to respond once the data arrives. 3014670SN/A pkt->assertMemInhibit(); 3024916SN/A pkt->setSupplyExclusive(); 3034910SN/A } else { 3044910SN/A // Someone else may respond before we get around to 3054910SN/A // processing this snoop, which means the copied request 3064910SN/A // pointer will no longer be valid 3074910SN/A cp_pkt->req = NULL; 3084670SN/A } 3094670SN/A 3104670SN/A if (pkt->needsExclusive()) { 3114670SN/A // This transaction will take away our pending copy 3124670SN/A pendingInvalidate = true; 3134670SN/A } 3144670SN/A } else { 3154670SN/A // Read to a read: no conflict, so no need to record as 3164670SN/A // target, but make sure neither reader thinks he's getting an 3174670SN/A // exclusive copy 3184670SN/A pendingShared = true; 3194670SN/A pkt->assertShared(); 3204667SN/A } 3214902SN/A 3224902SN/A return true; 3234665SN/A} 3244665SN/A 3254665SN/A 3264665SN/Abool 3274665SN/AMSHR::promoteDeferredTargets() 3284665SN/A{ 3294903SN/A assert(targets->empty()); 3304903SN/A if (deferredTargets->empty()) { 3314665SN/A return false; 3324665SN/A } 3334665SN/A 3344903SN/A // swap targets & deferredTargets lists 3354903SN/A TargetList *tmp = targets; 3364665SN/A targets = deferredTargets; 3374903SN/A deferredTargets = tmp; 3382810SN/A 3394903SN/A assert(targets->size() == ntargets); 3404903SN/A 3414903SN/A // clear deferredTargets flags 3424903SN/A deferredTargets->resetFlags(); 3434903SN/A 3444665SN/A pendingInvalidate = false; 3454670SN/A pendingShared = false; 3464903SN/A order = targets->front().order; 3474903SN/A readyTime = std::max(curTick, targets->front().readyTime); 3484665SN/A 3494665SN/A return true; 3502810SN/A} 3512810SN/A 3522810SN/A 3532810SN/Avoid 3544670SN/AMSHR::handleFill(Packet *pkt, CacheBlk *blk) 3554668SN/A{ 3564671SN/A if (pendingShared) { 3574670SN/A // we snooped another read while this read was in 3584670SN/A // service... assert shared line on its behalf 3594670SN/A pkt->assertShared(); 3604668SN/A } 3615270SN/A 3625270SN/A if (!pkt->sharedAsserted() && !pendingInvalidate 3635270SN/A && deferredTargets->needsExclusive) { 3645270SN/A // We got an exclusive response, but we have deferred targets 3655270SN/A // which are waiting to request an exclusive copy (not because 3665270SN/A // of a pending invalidate). This can happen if the original 3675270SN/A // request was for a read-only (non-exclusive) block, but we 3685270SN/A // got an exclusive copy anyway because of the E part of the 3695270SN/A // MOESI/MESI protocol. Since we got the exclusive copy 3705270SN/A // there's no need to defer the targets, so move them up to 3715270SN/A // the regular target list. 3725270SN/A assert(!targets->needsExclusive); 3735270SN/A targets->needsExclusive = true; 3745318SN/A // if any of the deferred targets were upper-level cache 3755318SN/A // requests marked downstreamPending, need to clear that 3765318SN/A assert(!downstreamPending); // not pending here anymore 3775318SN/A deferredTargets->clearDownstreamPending(); 3785270SN/A // this clears out deferredTargets too 3795270SN/A targets->splice(targets->end(), *deferredTargets); 3805270SN/A deferredTargets->resetFlags(); 3815270SN/A } 3824668SN/A} 3834668SN/A 3844668SN/A 3855314SN/Abool 3865314SN/AMSHR::checkFunctional(PacketPtr pkt) 3875314SN/A{ 3885314SN/A // For printing, we treat the MSHR as a whole as single entity. 3895314SN/A // For other requests, we iterate over the individual targets 3905314SN/A // since that's where the actual data lies. 3915314SN/A if (pkt->isPrint()) { 3925314SN/A pkt->checkFunctional(this, addr, size, NULL); 3935314SN/A return false; 3945314SN/A } else { 3955314SN/A return (targets->checkFunctional(pkt) || 3965314SN/A deferredTargets->checkFunctional(pkt)); 3975314SN/A } 3985314SN/A} 3995314SN/A 4005314SN/A 4014668SN/Avoid 4025314SN/AMSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const 4032810SN/A{ 4045314SN/A ccprintf(os, "%s[%x:%x] %s %s %s state: %s %s %s %s\n", 4055314SN/A prefix, addr, addr+size-1, 4065314SN/A isCacheFill ? "Fill" : "", 4075314SN/A needsExclusive() ? "Excl" : "", 4085314SN/A _isUncacheable ? "Unc" : "", 4095314SN/A inService ? "InSvc" : "", 4105314SN/A downstreamPending ? "DwnPend" : "", 4115314SN/A pendingInvalidate ? "PendInv" : "", 4125314SN/A pendingShared ? "PendShared" : ""); 4132810SN/A 4145314SN/A ccprintf(os, "%s Targets:\n", prefix); 4155314SN/A targets->print(os, verbosity, prefix + " "); 4165314SN/A if (!deferredTargets->empty()) { 4175314SN/A ccprintf(os, "%s Deferred Targets:\n", prefix); 4185314SN/A deferredTargets->print(os, verbosity, prefix + " "); 4192810SN/A } 4202810SN/A} 4212810SN/A 4222810SN/AMSHR::~MSHR() 4232810SN/A{ 4242810SN/A} 425