mshr.cc revision 5730:dea5fcd1ead0
16791SN/A/* 26791SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 36791SN/A * All rights reserved. 46791SN/A * 56791SN/A * Redistribution and use in source and binary forms, with or without 66791SN/A * modification, are permitted provided that the following conditions are 76791SN/A * met: redistributions of source code must retain the above copyright 86791SN/A * notice, this list of conditions and the following disclaimer; 96791SN/A * redistributions in binary form must reproduce the above copyright 106791SN/A * notice, this list of conditions and the following disclaimer in the 116791SN/A * documentation and/or other materials provided with the distribution; 126791SN/A * neither the name of the copyright holders nor the names of its 136791SN/A * contributors may be used to endorse or promote products derived from 146791SN/A * this software without specific prior written permission. 156791SN/A * 166791SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176791SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186791SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196791SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206791SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216791SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226791SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236791SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246791SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256791SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266791SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276791SN/A * 286791SN/A * Authors: Erik Hallnor 2910441Snilay@cs.wisc.edu * Dave Greene 3010441Snilay@cs.wisc.edu */ 316791SN/A 327055SN/A/** 337055SN/A * @file 347455SN/A * Miss Status and Handling Register (MSHR) definitions. 357039SN/A */ 367039SN/A 3710301Snilay@cs.wisc.edu#include <assert.h> 387039SN/A#include <string> 396791SN/A#include <vector> 407039SN/A#include <algorithm> 417039SN/A 427039SN/A#include "mem/cache/mshr.hh" 438607SN/A#include "sim/core.hh" // for curTick 447055SN/A#include "sim/host.hh" 456791SN/A#include "base/misc.hh" 467039SN/A#include "mem/cache/cache.hh" 477039SN/A 487039SN/Ausing namespace std; 496797SN/A 506791SN/AMSHR::MSHR() 517039SN/A{ 527039SN/A inService = false; 537039SN/A ntargets = 0; 547039SN/A threadNum = -1; 557039SN/A targets = new TargetList(); 566791SN/A deferredTargets = new TargetList(); 577039SN/A} 587039SN/A 597054SN/A 607039SN/AMSHR::TargetList::TargetList() 6111025Snilay@cs.wisc.edu : needsExclusive(false), hasUpgrade(false) 627039SN/A{} 6311025Snilay@cs.wisc.edu 6411025Snilay@cs.wisc.edu 6511025Snilay@cs.wisc.eduinline void 6611025Snilay@cs.wisc.eduMSHR::TargetList::add(PacketPtr pkt, Tick readyTime, 6711025Snilay@cs.wisc.edu Counter order, bool cpuSide, bool markPending) 6811025Snilay@cs.wisc.edu{ 6911025Snilay@cs.wisc.edu if (cpuSide) { 7011025Snilay@cs.wisc.edu if (pkt->needsExclusive()) { 716791SN/A needsExclusive = true; 727055SN/A } 736791SN/A 747039SN/A if (pkt->cmd == MemCmd::UpgradeReq) { 757039SN/A hasUpgrade = true; 767039SN/A } 777039SN/A } 786791SN/A 797039SN/A if (markPending) { 8011025Snilay@cs.wisc.edu MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState); 817455SN/A if (mshr != NULL) { 826791SN/A assert(!mshr->downstreamPending); 836791SN/A mshr->downstreamPending = true; 847055SN/A } 857055SN/A } 866791SN/A 877039SN/A push_back(Target(pkt, readyTime, order, cpuSide, markPending)); 887055SN/A} 897039SN/A 906791SN/A 916791SN/Avoid 927055SN/AMSHR::TargetList::replaceUpgrades() 937055SN/A{ 946797SN/A if (!hasUpgrade) 957039SN/A return; 967055SN/A 977039SN/A Iterator end_i = end(); 986797SN/A for (Iterator i = begin(); i != end_i; ++i) { 996797SN/A if (i->pkt->cmd == MemCmd::UpgradeReq) { 10010441Snilay@cs.wisc.edu i->pkt->cmd = MemCmd::ReadExReq; 101 DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n"); 102 } 103 } 104 105 hasUpgrade = false; 106} 107 108 109void 110MSHR::TargetList::clearDownstreamPending() 111{ 112 Iterator end_i = end(); 113 for (Iterator i = begin(); i != end_i; ++i) { 114 if (i->markedPending) { 115 MSHR *mshr = dynamic_cast<MSHR*>(i->pkt->senderState); 116 if (mshr != NULL) { 117 mshr->clearDownstreamPending(); 118 } 119 } 120 } 121} 122 123 124bool 125MSHR::TargetList::checkFunctional(PacketPtr pkt) 126{ 127 Iterator end_i = end(); 128 for (Iterator i = begin(); i != end_i; ++i) { 129 if (pkt->checkFunctional(i->pkt)) { 130 return true; 131 } 132 } 133 134 return false; 135} 136 137 138void 139MSHR::TargetList:: 140print(std::ostream &os, int verbosity, const std::string &prefix) const 141{ 142 ConstIterator end_i = end(); 143 for (ConstIterator i = begin(); i != end_i; ++i) { 144 ccprintf(os, "%s%s: ", prefix, i->isCpuSide() ? "cpu" : "mem"); 145 i->pkt->print(os, verbosity, ""); 146 } 147} 148 149 150void 151MSHR::allocate(Addr _addr, int _size, PacketPtr target, 152 Tick whenReady, Counter _order) 153{ 154 addr = _addr; 155 size = _size; 156 readyTime = whenReady; 157 order = _order; 158 assert(target); 159 isForward = false; 160 _isUncacheable = target->req->isUncacheable(); 161 inService = false; 162 downstreamPending = false; 163 threadNum = 0; 164 ntargets = 1; 165 // Don't know of a case where we would allocate a new MSHR for a 166 // snoop (mem-side request), so set cpuSide to true here. 167 assert(targets->isReset()); 168 targets->add(target, whenReady, _order, true, true); 169 assert(deferredTargets->isReset()); 170 pendingInvalidate = false; 171 pendingShared = false; 172 data = NULL; 173} 174 175 176void 177MSHR::clearDownstreamPending() 178{ 179 assert(downstreamPending); 180 downstreamPending = false; 181 // recursively clear flag on any MSHRs we will be forwarding 182 // responses to 183 targets->clearDownstreamPending(); 184} 185 186bool 187MSHR::markInService() 188{ 189 assert(!inService); 190 if (isForwardNoResponse()) { 191 // we just forwarded the request packet & don't expect a 192 // response, so get rid of it 193 assert(getNumTargets() == 1); 194 popTarget(); 195 return true; 196 } 197 inService = true; 198 if (!downstreamPending) { 199 // let upstream caches know that the request has made it to a 200 // level where it's going to get a response 201 targets->clearDownstreamPending(); 202 } 203 return false; 204} 205 206 207void 208MSHR::deallocate() 209{ 210 assert(targets->empty()); 211 targets->resetFlags(); 212 assert(deferredTargets->isReset()); 213 assert(ntargets == 0); 214 inService = false; 215 //allocIter = NULL; 216 //readyIter = NULL; 217} 218 219/* 220 * Adds a target to an MSHR 221 */ 222void 223MSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order) 224{ 225 // if there's a request already in service for this MSHR, we will 226 // have to defer the new target until after the response if any of 227 // the following are true: 228 // - there are other targets already deferred 229 // - there's a pending invalidate to be applied after the response 230 // comes back (but before this target is processed) 231 // - the outstanding request is for a non-exclusive block and this 232 // target requires an exclusive block 233 if (inService && 234 (!deferredTargets->empty() || pendingInvalidate || 235 (!targets->needsExclusive && pkt->needsExclusive()))) { 236 // need to put on deferred list 237 deferredTargets->add(pkt, whenReady, _order, true, true); 238 } else { 239 // No request outstanding, or still OK to append to 240 // outstanding request: append to regular target list. Only 241 // mark pending if current request hasn't been issued yet 242 // (isn't in service). 243 targets->add(pkt, whenReady, _order, true, !inService); 244 } 245 246 ++ntargets; 247} 248 249bool 250MSHR::handleSnoop(PacketPtr pkt, Counter _order) 251{ 252 if (!inService || (pkt->isExpressSnoop() && downstreamPending)) { 253 // Request has not been issued yet, or it's been issued 254 // locally but is buffered unissued at some downstream cache 255 // which is forwarding us this snoop. Either way, the packet 256 // we're snooping logically precedes this MSHR's request, so 257 // the snoop has no impact on the MSHR, but must be processed 258 // in the standard way by the cache. The only exception is 259 // that if we're an L2+ cache buffering an UpgradeReq from a 260 // higher-level cache, and the snoop is invalidating, then our 261 // buffered upgrades must be converted to read exclusives, 262 // since the upper-level cache no longer has a valid copy. 263 // That is, even though the upper-level cache got out on its 264 // local bus first, some other invalidating transaction 265 // reached the global bus before the upgrade did. 266 if (pkt->needsExclusive()) { 267 targets->replaceUpgrades(); 268 deferredTargets->replaceUpgrades(); 269 } 270 271 return false; 272 } 273 274 // From here on down, the request issued by this MSHR logically 275 // precedes the request we're snooping. 276 277 if (pkt->needsExclusive()) { 278 // snooped request still precedes the re-request we'll have to 279 // issue for deferred targets, if any... 280 deferredTargets->replaceUpgrades(); 281 } 282 283 if (pendingInvalidate) { 284 // a prior snoop has already appended an invalidation, so 285 // logically we don't have the block anymore; no need for 286 // further snooping. 287 return true; 288 } 289 290 if (targets->needsExclusive || pkt->needsExclusive()) { 291 // actual target device (typ. PhysicalMemory) will delete the 292 // packet on reception, so we need to save a copy here 293 PacketPtr cp_pkt = new Packet(pkt, true); 294 targets->add(cp_pkt, curTick, _order, false, 295 downstreamPending && targets->needsExclusive); 296 ++ntargets; 297 298 if (targets->needsExclusive) { 299 // We're awaiting an exclusive copy, so ownership is pending. 300 // It's up to us to respond once the data arrives. 301 pkt->assertMemInhibit(); 302 pkt->setSupplyExclusive(); 303 } else { 304 // Someone else may respond before we get around to 305 // processing this snoop, which means the copied request 306 // pointer will no longer be valid 307 cp_pkt->req = NULL; 308 } 309 310 if (pkt->needsExclusive()) { 311 // This transaction will take away our pending copy 312 pendingInvalidate = true; 313 } 314 } else { 315 // Read to a read: no conflict, so no need to record as 316 // target, but make sure neither reader thinks he's getting an 317 // exclusive copy 318 pendingShared = true; 319 pkt->assertShared(); 320 } 321 322 return true; 323} 324 325 326bool 327MSHR::promoteDeferredTargets() 328{ 329 assert(targets->empty()); 330 if (deferredTargets->empty()) { 331 return false; 332 } 333 334 // swap targets & deferredTargets lists 335 TargetList *tmp = targets; 336 targets = deferredTargets; 337 deferredTargets = tmp; 338 339 assert(targets->size() == ntargets); 340 341 // clear deferredTargets flags 342 deferredTargets->resetFlags(); 343 344 pendingInvalidate = false; 345 pendingShared = false; 346 order = targets->front().order; 347 readyTime = std::max(curTick, targets->front().readyTime); 348 349 return true; 350} 351 352 353void 354MSHR::handleFill(Packet *pkt, CacheBlk *blk) 355{ 356 if (pendingShared) { 357 // we snooped another read while this read was in 358 // service... assert shared line on its behalf 359 pkt->assertShared(); 360 } 361 362 if (!pkt->sharedAsserted() && !pendingInvalidate 363 && deferredTargets->needsExclusive) { 364 // We got an exclusive response, but we have deferred targets 365 // which are waiting to request an exclusive copy (not because 366 // of a pending invalidate). This can happen if the original 367 // request was for a read-only (non-exclusive) block, but we 368 // got an exclusive copy anyway because of the E part of the 369 // MOESI/MESI protocol. Since we got the exclusive copy 370 // there's no need to defer the targets, so move them up to 371 // the regular target list. 372 assert(!targets->needsExclusive); 373 targets->needsExclusive = true; 374 // if any of the deferred targets were upper-level cache 375 // requests marked downstreamPending, need to clear that 376 assert(!downstreamPending); // not pending here anymore 377 deferredTargets->clearDownstreamPending(); 378 // this clears out deferredTargets too 379 targets->splice(targets->end(), *deferredTargets); 380 deferredTargets->resetFlags(); 381 } 382} 383 384 385bool 386MSHR::checkFunctional(PacketPtr pkt) 387{ 388 // For printing, we treat the MSHR as a whole as single entity. 389 // For other requests, we iterate over the individual targets 390 // since that's where the actual data lies. 391 if (pkt->isPrint()) { 392 pkt->checkFunctional(this, addr, size, NULL); 393 return false; 394 } else { 395 return (targets->checkFunctional(pkt) || 396 deferredTargets->checkFunctional(pkt)); 397 } 398} 399 400 401void 402MSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const 403{ 404 ccprintf(os, "%s[%x:%x] %s %s %s state: %s %s %s %s\n", 405 prefix, addr, addr+size-1, 406 isForward ? "Forward" : "", 407 isForwardNoResponse() ? "ForwNoResp" : "", 408 needsExclusive() ? "Excl" : "", 409 _isUncacheable ? "Unc" : "", 410 inService ? "InSvc" : "", 411 downstreamPending ? "DwnPend" : "", 412 pendingInvalidate ? "PendInv" : "", 413 pendingShared ? "PendShared" : ""); 414 415 ccprintf(os, "%s Targets:\n", prefix); 416 targets->print(os, verbosity, prefix + " "); 417 if (!deferredTargets->empty()) { 418 ccprintf(os, "%s Deferred Targets:\n", prefix); 419 deferredTargets->print(os, verbosity, prefix + " "); 420 } 421} 422 423MSHR::~MSHR() 424{ 425} 426