mshr.cc revision 7667:aa8fd8f6a495
1/* 2 * Copyright (c) 2002-2005 The Regents of The University of Michigan 3 * Copyright (c) 2010 Advanced Micro Devices, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer; 10 * redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution; 13 * neither the name of the copyright holders nor the names of its 14 * contributors may be used to endorse or promote products derived from 15 * this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * Authors: Erik Hallnor 30 * Dave Greene 31 */ 32 33/** 34 * @file 35 * Miss Status and Handling Register (MSHR) definitions. 36 */ 37 38#include <algorithm> 39#include <cassert> 40#include <string> 41#include <vector> 42 43#include "base/misc.hh" 44#include "base/types.hh" 45#include "mem/cache/cache.hh" 46#include "mem/cache/mshr.hh" 47#include "sim/core.hh" 48 49using namespace std; 50 51MSHR::MSHR() 52{ 53 inService = false; 54 ntargets = 0; 55 threadNum = InvalidThreadID; 56 targets = new TargetList(); 57 deferredTargets = new TargetList(); 58} 59 60 61MSHR::TargetList::TargetList() 62 : needsExclusive(false), hasUpgrade(false) 63{} 64 65 66inline void 67MSHR::TargetList::add(PacketPtr pkt, Tick readyTime, 68 Counter order, Target::Source source, bool markPending) 69{ 70 if (source != Target::FromSnoop) { 71 if (pkt->needsExclusive()) { 72 needsExclusive = true; 73 } 74 75 if (pkt->isUpgrade()) { 76 hasUpgrade = true; 77 } 78 } 79 80 if (markPending) { 81 MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState); 82 if (mshr != NULL) { 83 assert(!mshr->downstreamPending); 84 mshr->downstreamPending = true; 85 } 86 } 87 88 push_back(Target(pkt, readyTime, order, source, markPending)); 89} 90 91 92static void 93replaceUpgrade(PacketPtr pkt) 94{ 95 if (pkt->cmd == MemCmd::UpgradeReq) { 96 pkt->cmd = MemCmd::ReadExReq; 97 DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n"); 98 } else if (pkt->cmd == MemCmd::SCUpgradeReq) { 99 pkt->cmd = MemCmd::SCUpgradeFailReq; 100 DPRINTF(Cache, "Replacing SCUpgradeReq with SCUpgradeFailReq\n"); 101 } 102} 103 104 105void 106MSHR::TargetList::replaceUpgrades() 107{ 108 if (!hasUpgrade) 109 return; 110 111 Iterator end_i = end(); 112 for (Iterator i = begin(); i != end_i; ++i) { 113 replaceUpgrade(i->pkt); 114 } 115 116 hasUpgrade = false; 117} 118 119 120void 121MSHR::TargetList::clearDownstreamPending() 122{ 123 Iterator end_i = end(); 124 for (Iterator i = begin(); i != end_i; ++i) { 125 if (i->markedPending) { 126 MSHR *mshr = dynamic_cast<MSHR*>(i->pkt->senderState); 127 if (mshr != NULL) { 128 mshr->clearDownstreamPending(); 129 } 130 } 131 } 132} 133 134 135bool 136MSHR::TargetList::checkFunctional(PacketPtr pkt) 137{ 138 Iterator end_i = end(); 139 for (Iterator i = begin(); i != end_i; ++i) { 140 if (pkt->checkFunctional(i->pkt)) { 141 return true; 142 } 143 } 144 145 return false; 146} 147 148 149void 150MSHR::TargetList:: 151print(std::ostream &os, int verbosity, const std::string &prefix) const 152{ 153 ConstIterator end_i = end(); 154 for (ConstIterator i = begin(); i != end_i; ++i) { 155 const char *s; 156 switch (i->source) { 157 case Target::FromCPU: s = "FromCPU"; 158 case Target::FromSnoop: s = "FromSnoop"; 159 case Target::FromPrefetcher: s = "FromPrefetcher"; 160 default: s = ""; 161 } 162 ccprintf(os, "%s%s: ", prefix, s); 163 i->pkt->print(os, verbosity, ""); 164 } 165} 166 167 168void 169MSHR::allocate(Addr _addr, int _size, PacketPtr target, 170 Tick whenReady, Counter _order) 171{ 172 addr = _addr; 173 size = _size; 174 readyTime = whenReady; 175 order = _order; 176 assert(target); 177 isForward = false; 178 _isUncacheable = target->req->isUncacheable(); 179 inService = false; 180 downstreamPending = false; 181 threadNum = 0; 182 ntargets = 1; 183 assert(targets->isReset()); 184 // Don't know of a case where we would allocate a new MSHR for a 185 // snoop (mem-side request), so set source according to request here 186 Target::Source source = (target->cmd == MemCmd::HardPFReq) ? 187 Target::FromPrefetcher : Target::FromCPU; 188 targets->add(target, whenReady, _order, source, true); 189 assert(deferredTargets->isReset()); 190 data = NULL; 191} 192 193 194void 195MSHR::clearDownstreamPending() 196{ 197 assert(downstreamPending); 198 downstreamPending = false; 199 // recursively clear flag on any MSHRs we will be forwarding 200 // responses to 201 targets->clearDownstreamPending(); 202} 203 204bool 205MSHR::markInService(PacketPtr pkt) 206{ 207 assert(!inService); 208 if (isForwardNoResponse()) { 209 // we just forwarded the request packet & don't expect a 210 // response, so get rid of it 211 assert(getNumTargets() == 1); 212 popTarget(); 213 return true; 214 } 215 inService = true; 216 pendingDirty = (targets->needsExclusive || 217 (!pkt->sharedAsserted() && pkt->memInhibitAsserted())); 218 postInvalidate = postDowngrade = false; 219 220 if (!downstreamPending) { 221 // let upstream caches know that the request has made it to a 222 // level where it's going to get a response 223 targets->clearDownstreamPending(); 224 } 225 return false; 226} 227 228 229void 230MSHR::deallocate() 231{ 232 assert(targets->empty()); 233 targets->resetFlags(); 234 assert(deferredTargets->isReset()); 235 assert(ntargets == 0); 236 inService = false; 237} 238 239/* 240 * Adds a target to an MSHR 241 */ 242void 243MSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order) 244{ 245 // if there's a request already in service for this MSHR, we will 246 // have to defer the new target until after the response if any of 247 // the following are true: 248 // - there are other targets already deferred 249 // - there's a pending invalidate to be applied after the response 250 // comes back (but before this target is processed) 251 // - this target requires an exclusive block and either we're not 252 // getting an exclusive block back or we have already snooped 253 // another read request that will downgrade our exclusive block 254 // to shared 255 256 // assume we'd never issue a prefetch when we've got an 257 // outstanding miss 258 assert(pkt->cmd != MemCmd::HardPFReq); 259 260 if (inService && 261 (!deferredTargets->empty() || hasPostInvalidate() || 262 (pkt->needsExclusive() && 263 (!isPendingDirty() || hasPostDowngrade() || isForward)))) { 264 // need to put on deferred list 265 if (hasPostInvalidate()) 266 replaceUpgrade(pkt); 267 deferredTargets->add(pkt, whenReady, _order, Target::FromCPU, true); 268 } else { 269 // No request outstanding, or still OK to append to 270 // outstanding request: append to regular target list. Only 271 // mark pending if current request hasn't been issued yet 272 // (isn't in service). 273 targets->add(pkt, whenReady, _order, Target::FromCPU, !inService); 274 } 275 276 ++ntargets; 277} 278 279bool 280MSHR::handleSnoop(PacketPtr pkt, Counter _order) 281{ 282 if (!inService || (pkt->isExpressSnoop() && downstreamPending)) { 283 // Request has not been issued yet, or it's been issued 284 // locally but is buffered unissued at some downstream cache 285 // which is forwarding us this snoop. Either way, the packet 286 // we're snooping logically precedes this MSHR's request, so 287 // the snoop has no impact on the MSHR, but must be processed 288 // in the standard way by the cache. The only exception is 289 // that if we're an L2+ cache buffering an UpgradeReq from a 290 // higher-level cache, and the snoop is invalidating, then our 291 // buffered upgrades must be converted to read exclusives, 292 // since the upper-level cache no longer has a valid copy. 293 // That is, even though the upper-level cache got out on its 294 // local bus first, some other invalidating transaction 295 // reached the global bus before the upgrade did. 296 if (pkt->needsExclusive()) { 297 targets->replaceUpgrades(); 298 deferredTargets->replaceUpgrades(); 299 } 300 301 return false; 302 } 303 304 // From here on down, the request issued by this MSHR logically 305 // precedes the request we're snooping. 306 if (pkt->needsExclusive()) { 307 // snooped request still precedes the re-request we'll have to 308 // issue for deferred targets, if any... 309 deferredTargets->replaceUpgrades(); 310 } 311 312 if (hasPostInvalidate()) { 313 // a prior snoop has already appended an invalidation, so 314 // logically we don't have the block anymore; no need for 315 // further snooping. 316 return true; 317 } 318 319 if (isPendingDirty() || pkt->isInvalidate()) { 320 // We need to save and replay the packet in two cases: 321 // 1. We're awaiting an exclusive copy, so ownership is pending, 322 // and we need to respond after we receive data. 323 // 2. It's an invalidation (e.g., UpgradeReq), and we need 324 // to forward the snoop up the hierarchy after the current 325 // transaction completes. 326 327 // Actual target device (typ. PhysicalMemory) will delete the 328 // packet on reception, so we need to save a copy here. 329 PacketPtr cp_pkt = new Packet(pkt, true); 330 targets->add(cp_pkt, curTick, _order, Target::FromSnoop, 331 downstreamPending && targets->needsExclusive); 332 ++ntargets; 333 334 if (isPendingDirty()) { 335 pkt->assertMemInhibit(); 336 pkt->setSupplyExclusive(); 337 } 338 339 if (pkt->needsExclusive()) { 340 // This transaction will take away our pending copy 341 postInvalidate = true; 342 } 343 } 344 345 if (!pkt->needsExclusive()) { 346 // This transaction will get a read-shared copy, downgrading 347 // our copy if we had an exclusive one 348 postDowngrade = true; 349 pkt->assertShared(); 350 } 351 352 return true; 353} 354 355 356bool 357MSHR::promoteDeferredTargets() 358{ 359 assert(targets->empty()); 360 if (deferredTargets->empty()) { 361 return false; 362 } 363 364 // swap targets & deferredTargets lists 365 TargetList *tmp = targets; 366 targets = deferredTargets; 367 deferredTargets = tmp; 368 369 assert(targets->size() == ntargets); 370 371 // clear deferredTargets flags 372 deferredTargets->resetFlags(); 373 374 order = targets->front().order; 375 readyTime = std::max(curTick, targets->front().readyTime); 376 377 return true; 378} 379 380 381void 382MSHR::handleFill(Packet *pkt, CacheBlk *blk) 383{ 384 if (!pkt->sharedAsserted() 385 && !(hasPostInvalidate() || hasPostDowngrade()) 386 && deferredTargets->needsExclusive) { 387 // We got an exclusive response, but we have deferred targets 388 // which are waiting to request an exclusive copy (not because 389 // of a pending invalidate). This can happen if the original 390 // request was for a read-only (non-exclusive) block, but we 391 // got an exclusive copy anyway because of the E part of the 392 // MOESI/MESI protocol. Since we got the exclusive copy 393 // there's no need to defer the targets, so move them up to 394 // the regular target list. 395 assert(!targets->needsExclusive); 396 targets->needsExclusive = true; 397 // if any of the deferred targets were upper-level cache 398 // requests marked downstreamPending, need to clear that 399 assert(!downstreamPending); // not pending here anymore 400 deferredTargets->clearDownstreamPending(); 401 // this clears out deferredTargets too 402 targets->splice(targets->end(), *deferredTargets); 403 deferredTargets->resetFlags(); 404 } 405} 406 407 408bool 409MSHR::checkFunctional(PacketPtr pkt) 410{ 411 // For printing, we treat the MSHR as a whole as single entity. 412 // For other requests, we iterate over the individual targets 413 // since that's where the actual data lies. 414 if (pkt->isPrint()) { 415 pkt->checkFunctional(this, addr, size, NULL); 416 return false; 417 } else { 418 return (targets->checkFunctional(pkt) || 419 deferredTargets->checkFunctional(pkt)); 420 } 421} 422 423 424void 425MSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const 426{ 427 ccprintf(os, "%s[%x:%x] %s %s %s state: %s %s %s %s\n", 428 prefix, addr, addr+size-1, 429 isForward ? "Forward" : "", 430 isForwardNoResponse() ? "ForwNoResp" : "", 431 needsExclusive() ? "Excl" : "", 432 _isUncacheable ? "Unc" : "", 433 inService ? "InSvc" : "", 434 downstreamPending ? "DwnPend" : "", 435 hasPostInvalidate() ? "PostInv" : "", 436 hasPostDowngrade() ? "PostDowngr" : ""); 437 438 ccprintf(os, "%s Targets:\n", prefix); 439 targets->print(os, verbosity, prefix + " "); 440 if (!deferredTargets->empty()) { 441 ccprintf(os, "%s Deferred Targets:\n", prefix); 442 deferredTargets->print(os, verbosity, prefix + " "); 443 } 444} 445 446MSHR::~MSHR() 447{ 448} 449