mshr.cc revision 4916
1/* 2 * Copyright (c) 2002-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Erik Hallnor 29 * Dave Greene 30 */ 31 32/** 33 * @file 34 * Miss Status and Handling Register (MSHR) definitions. 35 */ 36 37#include <assert.h> 38#include <string> 39#include <vector> 40#include <algorithm> 41 42#include "mem/cache/miss/mshr.hh" 43#include "sim/core.hh" // for curTick 44#include "sim/host.hh" 45#include "base/misc.hh" 46#include "mem/cache/cache.hh" 47 48using namespace std; 49 50MSHR::MSHR() 51{ 52 inService = false; 53 ntargets = 0; 54 threadNum = -1; 55 targets = new TargetList(); 56 deferredTargets = new TargetList(); 57} 58 59 60MSHR::TargetList::TargetList() 61 : needsExclusive(false), hasUpgrade(false) 62{} 63 64 65inline void 66MSHR::TargetList::add(PacketPtr pkt, Tick readyTime, 67 Counter order, bool cpuSide) 68{ 69 if (cpuSide) { 70 if (pkt->needsExclusive()) { 71 needsExclusive = true; 72 } 73 74 if (pkt->cmd == MemCmd::UpgradeReq) { 75 hasUpgrade = true; 76 } 77 78 MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState); 79 if (mshr != NULL) { 80 assert(!mshr->downstreamPending); 81 mshr->downstreamPending = true; 82 } 83 } 84 85 push_back(Target(pkt, readyTime, order, cpuSide)); 86} 87 88 89void 90MSHR::TargetList::replaceUpgrades() 91{ 92 if (!hasUpgrade) 93 return; 94 95 Iterator end_i = end(); 96 for (Iterator i = begin(); i != end_i; ++i) { 97 if (i->pkt->cmd == MemCmd::UpgradeReq) { 98 i->pkt->cmd = MemCmd::ReadExReq; 99 DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n"); 100 } 101 } 102 103 hasUpgrade = false; 104} 105 106 107void 108MSHR::TargetList::clearDownstreamPending() 109{ 110 Iterator end_i = end(); 111 for (Iterator i = begin(); i != end_i; ++i) { 112 MSHR *mshr = dynamic_cast<MSHR*>(i->pkt->senderState); 113 if (mshr != NULL) { 114 assert(mshr->downstreamPending); 115 mshr->downstreamPending = false; 116 } 117 } 118} 119 120 121void 122MSHR::allocate(Addr _addr, int _size, PacketPtr target, 123 Tick whenReady, Counter _order) 124{ 125 addr = _addr; 126 size = _size; 127 readyTime = whenReady; 128 order = _order; 129 assert(target); 130 isCacheFill = false; 131 _isUncacheable = target->req->isUncacheable(); 132 inService = false; 133 downstreamPending = false; 134 threadNum = 0; 135 ntargets = 1; 136 // Don't know of a case where we would allocate a new MSHR for a 137 // snoop (mem-side request), so set cpuSide to true here. 138 assert(targets->isReset()); 139 targets->add(target, whenReady, _order, true); 140 assert(deferredTargets->isReset()); 141 pendingInvalidate = false; 142 pendingShared = false; 143 data = NULL; 144} 145 146 147bool 148MSHR::markInService() 149{ 150 assert(!inService); 151 if (isSimpleForward()) { 152 // we just forwarded the request packet & don't expect a 153 // response, so get rid of it 154 assert(getNumTargets() == 1); 155 popTarget(); 156 return true; 157 } 158 inService = true; 159 if (!downstreamPending) { 160 // let upstream caches know that the request has made it to a 161 // level where it's going to get a response 162 targets->clearDownstreamPending(); 163 } 164 return false; 165} 166 167 168void 169MSHR::deallocate() 170{ 171 assert(targets->empty()); 172 targets->resetFlags(); 173 assert(deferredTargets->isReset()); 174 assert(ntargets == 0); 175 inService = false; 176 //allocIter = NULL; 177 //readyIter = NULL; 178} 179 180/* 181 * Adds a target to an MSHR 182 */ 183void 184MSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order) 185{ 186 // if there's a request already in service for this MSHR, we will 187 // have to defer the new target until after the response if any of 188 // the following are true: 189 // - there are other targets already deferred 190 // - there's a pending invalidate to be applied after the response 191 // comes back (but before this target is processed) 192 // - the outstanding request is for a non-exclusive block and this 193 // target requires an exclusive block 194 if (inService && 195 (!deferredTargets->empty() || pendingInvalidate || 196 (!targets->needsExclusive && pkt->needsExclusive()))) { 197 // need to put on deferred list 198 deferredTargets->add(pkt, whenReady, _order, true); 199 } else { 200 // no request outstanding, or still OK to append to 201 // outstanding request 202 targets->add(pkt, whenReady, _order, true); 203 } 204 205 ++ntargets; 206} 207 208bool 209MSHR::handleSnoop(PacketPtr pkt, Counter _order) 210{ 211 if (!inService || (pkt->isExpressSnoop() && downstreamPending)) { 212 // Request has not been issued yet, or it's been issued 213 // locally but is buffered unissued at some downstream cache 214 // which is forwarding us this snoop. Either way, the packet 215 // we're snooping logically precedes this MSHR's request, so 216 // the snoop has no impact on the MSHR, but must be processed 217 // in the standard way by the cache. The only exception is 218 // that if we're an L2+ cache buffering an UpgradeReq from a 219 // higher-level cache, and the snoop is invalidating, then our 220 // buffered upgrades must be converted to read exclusives, 221 // since the upper-level cache no longer has a valid copy. 222 // That is, even though the upper-level cache got out on its 223 // local bus first, some other invalidating transaction 224 // reached the global bus before the upgrade did. 225 if (pkt->needsExclusive()) { 226 targets->replaceUpgrades(); 227 deferredTargets->replaceUpgrades(); 228 } 229 230 return false; 231 } 232 233 // From here on down, the request issued by this MSHR logically 234 // precedes the request we're snooping. 235 236 if (pkt->needsExclusive()) { 237 // snooped request still precedes the re-request we'll have to 238 // issue for deferred targets, if any... 239 deferredTargets->replaceUpgrades(); 240 } 241 242 if (pendingInvalidate) { 243 // a prior snoop has already appended an invalidation, so 244 // logically we don't have the block anymore; no need for 245 // further snooping. 246 return true; 247 } 248 249 if (targets->needsExclusive || pkt->needsExclusive()) { 250 // actual target device (typ. PhysicalMemory) will delete the 251 // packet on reception, so we need to save a copy here 252 PacketPtr cp_pkt = new Packet(pkt); 253 targets->add(cp_pkt, curTick, _order, false); 254 ++ntargets; 255 256 if (targets->needsExclusive) { 257 // We're awaiting an exclusive copy, so ownership is pending. 258 // It's up to us to respond once the data arrives. 259 pkt->assertMemInhibit(); 260 pkt->setSupplyExclusive(); 261 } else { 262 // Someone else may respond before we get around to 263 // processing this snoop, which means the copied request 264 // pointer will no longer be valid 265 cp_pkt->req = NULL; 266 } 267 268 if (pkt->needsExclusive()) { 269 // This transaction will take away our pending copy 270 pendingInvalidate = true; 271 } 272 } else { 273 // Read to a read: no conflict, so no need to record as 274 // target, but make sure neither reader thinks he's getting an 275 // exclusive copy 276 pendingShared = true; 277 pkt->assertShared(); 278 } 279 280 return true; 281} 282 283 284bool 285MSHR::promoteDeferredTargets() 286{ 287 assert(targets->empty()); 288 if (deferredTargets->empty()) { 289 return false; 290 } 291 292 // swap targets & deferredTargets lists 293 TargetList *tmp = targets; 294 targets = deferredTargets; 295 deferredTargets = tmp; 296 297 assert(targets->size() == ntargets); 298 299 // clear deferredTargets flags 300 deferredTargets->resetFlags(); 301 302 pendingInvalidate = false; 303 pendingShared = false; 304 order = targets->front().order; 305 readyTime = std::max(curTick, targets->front().readyTime); 306 307 return true; 308} 309 310 311void 312MSHR::handleFill(Packet *pkt, CacheBlk *blk) 313{ 314 if (pendingShared) { 315 // we snooped another read while this read was in 316 // service... assert shared line on its behalf 317 pkt->assertShared(); 318 } 319} 320 321 322void 323MSHR::dump() 324{ 325 ccprintf(cerr, 326 "inService: %d thread: %d\n" 327 "Addr: %x ntargets %d\n" 328 "Targets:\n", 329 inService, threadNum, addr, ntargets); 330#if 0 331 TargetListIterator tar_it = targets->begin(); 332 for (int i = 0; i < ntargets; i++) { 333 assert(tar_it != targets->end()); 334 335 ccprintf(cerr, "\t%d: Addr: %x cmd: %s\n", 336 i, tar_it->pkt->getAddr(), tar_it->pkt->cmdString()); 337 338 tar_it++; 339 } 340#endif 341 ccprintf(cerr, "\n"); 342} 343 344MSHR::~MSHR() 345{ 346} 347