cache.cc (11483:d4c2e56d18b2) | cache.cc (11484:08b33c52a16d) |
---|---|
1/* 2 * Copyright (c) 2010-2016 ARM Limited 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 308 unchanged lines hidden (view full) --- 317 if (old_blk->isDirty() || writebackClean) 318 writebacks.push_back(writebackBlk(old_blk)); 319 else 320 writebacks.push_back(cleanEvictBlk(old_blk)); 321 tags->invalidate(old_blk); 322 old_blk->invalidate(); 323 } 324 | 1/* 2 * Copyright (c) 2010-2016 ARM Limited 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 308 unchanged lines hidden (view full) --- 317 if (old_blk->isDirty() || writebackClean) 318 writebacks.push_back(writebackBlk(old_blk)); 319 else 320 writebacks.push_back(cleanEvictBlk(old_blk)); 321 tags->invalidate(old_blk); 322 old_blk->invalidate(); 323 } 324 |
325 blk = NULL; | 325 blk = nullptr; |
326 // lookupLatency is the latency in case the request is uncacheable. 327 lat = lookupLatency; 328 return false; 329 } 330 331 ContextID id = pkt->req->hasContextId() ? 332 pkt->req->contextId() : InvalidContextID; 333 // Here lat is the value passed as parameter to accessBlock() function --- 55 unchanged lines hidden (view full) --- 389 // any ordering/decisions about ownership already taken 390 if (pkt->cmd == MemCmd::WritebackClean && 391 mshrQueue.findMatch(pkt->getAddr(), pkt->isSecure())) { 392 DPRINTF(Cache, "Clean writeback %#llx to block with MSHR, " 393 "dropping\n", pkt->getAddr()); 394 return true; 395 } 396 | 326 // lookupLatency is the latency in case the request is uncacheable. 327 lat = lookupLatency; 328 return false; 329 } 330 331 ContextID id = pkt->req->hasContextId() ? 332 pkt->req->contextId() : InvalidContextID; 333 // Here lat is the value passed as parameter to accessBlock() function --- 55 unchanged lines hidden (view full) --- 389 // any ordering/decisions about ownership already taken 390 if (pkt->cmd == MemCmd::WritebackClean && 391 mshrQueue.findMatch(pkt->getAddr(), pkt->isSecure())) { 392 DPRINTF(Cache, "Clean writeback %#llx to block with MSHR, " 393 "dropping\n", pkt->getAddr()); 394 return true; 395 } 396 |
397 if (blk == NULL) { | 397 if (blk == nullptr) { |
398 // need to do a replacement 399 blk = allocateBlock(pkt->getAddr(), pkt->isSecure(), writebacks); | 398 // need to do a replacement 399 blk = allocateBlock(pkt->getAddr(), pkt->isSecure(), writebacks); |
400 if (blk == NULL) { | 400 if (blk == nullptr) { |
401 // no replaceable block available: give up, fwd to next level. 402 incMissCount(pkt); 403 return false; 404 } 405 tags->insertBlock(pkt, blk); 406 407 blk->status = (BlkValid | BlkReadable); 408 if (pkt->isSecure()) { --- 13 unchanged lines hidden (view full) --- 422 } 423 // nothing else to do; writeback doesn't expect response 424 assert(!pkt->needsResponse()); 425 std::memcpy(blk->data, pkt->getConstPtr<uint8_t>(), blkSize); 426 DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print()); 427 incHitCount(pkt); 428 return true; 429 } else if (pkt->cmd == MemCmd::CleanEvict) { | 401 // no replaceable block available: give up, fwd to next level. 402 incMissCount(pkt); 403 return false; 404 } 405 tags->insertBlock(pkt, blk); 406 407 blk->status = (BlkValid | BlkReadable); 408 if (pkt->isSecure()) { --- 13 unchanged lines hidden (view full) --- 422 } 423 // nothing else to do; writeback doesn't expect response 424 assert(!pkt->needsResponse()); 425 std::memcpy(blk->data, pkt->getConstPtr<uint8_t>(), blkSize); 426 DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print()); 427 incHitCount(pkt); 428 return true; 429 } else if (pkt->cmd == MemCmd::CleanEvict) { |
430 if (blk != NULL) { | 430 if (blk != nullptr) { |
431 // Found the block in the tags, need to stop CleanEvict from 432 // propagating further down the hierarchy. Returning true will 433 // treat the CleanEvict like a satisfied write request and delete 434 // it. 435 return true; 436 } 437 // We didn't find the block here, propagate the CleanEvict further 438 // down the memory hierarchy. Returning false will treat the CleanEvict 439 // like a Writeback which could not find a replaceable block so has to 440 // go to next level. 441 return false; | 431 // Found the block in the tags, need to stop CleanEvict from 432 // propagating further down the hierarchy. Returning true will 433 // treat the CleanEvict like a satisfied write request and delete 434 // it. 435 return true; 436 } 437 // We didn't find the block here, propagate the CleanEvict further 438 // down the memory hierarchy. Returning false will treat the CleanEvict 439 // like a Writeback which could not find a replaceable block so has to 440 // go to next level. 441 return false; |
442 } else if ((blk != NULL) && | 442 } else if ((blk != nullptr) && |
443 (pkt->needsWritable() ? blk->isWritable() : 444 blk->isReadable())) { 445 // OK to satisfy access 446 incHitCount(pkt); 447 satisfyCpuSideRequest(pkt, blk); 448 return true; 449 } 450 | 443 (pkt->needsWritable() ? blk->isWritable() : 444 blk->isReadable())) { 445 // OK to satisfy access 446 incHitCount(pkt); 447 satisfyCpuSideRequest(pkt, blk); 448 return true; 449 } 450 |
451 // Can't satisfy access normally... either no block (blk == NULL) | 451 // Can't satisfy access normally... either no block (blk == nullptr) |
452 // or have block but need writable 453 454 incMissCount(pkt); 455 | 452 // or have block but need writable 453 454 incMissCount(pkt); 455 |
456 if (blk == NULL && pkt->isLLSC() && pkt->isWrite()) { | 456 if (blk == nullptr && pkt->isLLSC() && pkt->isWrite()) { |
457 // complete miss on store conditional... just give up now 458 pkt->req->setExtraData(0); 459 return true; 460 } 461 462 return false; 463} 464 --- 204 unchanged lines hidden (view full) --- 669 670 // anything that is merely forwarded pays for the forward latency and 671 // the delay provided by the crossbar 672 Tick forward_time = clockEdge(forwardLatency) + pkt->headerDelay; 673 674 // We use lookupLatency here because it is used to specify the latency 675 // to access. 676 Cycles lat = lookupLatency; | 457 // complete miss on store conditional... just give up now 458 pkt->req->setExtraData(0); 459 return true; 460 } 461 462 return false; 463} 464 --- 204 unchanged lines hidden (view full) --- 669 670 // anything that is merely forwarded pays for the forward latency and 671 // the delay provided by the crossbar 672 Tick forward_time = clockEdge(forwardLatency) + pkt->headerDelay; 673 674 // We use lookupLatency here because it is used to specify the latency 675 // to access. 676 Cycles lat = lookupLatency; |
677 CacheBlk *blk = NULL; | 677 CacheBlk *blk = nullptr; |
678 bool satisfied = false; 679 { 680 PacketList writebacks; 681 // Note that lat is passed by reference here. The function 682 // access() calls accessBlock() which can modify lat value. 683 satisfied = access(pkt, blk, lat, writebacks); 684 685 // copy writebacks to write buffer here to ensure they logically --- 322 unchanged lines hidden (view full) --- 1008 1009 return lat * clockPeriod(); 1010 } 1011 1012 // should assert here that there are no outstanding MSHRs or 1013 // writebacks... that would mean that someone used an atomic 1014 // access in timing mode 1015 | 678 bool satisfied = false; 679 { 680 PacketList writebacks; 681 // Note that lat is passed by reference here. The function 682 // access() calls accessBlock() which can modify lat value. 683 satisfied = access(pkt, blk, lat, writebacks); 684 685 // copy writebacks to write buffer here to ensure they logically --- 322 unchanged lines hidden (view full) --- 1008 1009 return lat * clockPeriod(); 1010 } 1011 1012 // should assert here that there are no outstanding MSHRs or 1013 // writebacks... that would mean that someone used an atomic 1014 // access in timing mode 1015 |
1016 CacheBlk *blk = NULL; | 1016 CacheBlk *blk = nullptr; |
1017 PacketList writebacks; 1018 bool satisfied = access(pkt, blk, lat, writebacks); 1019 1020 // handle writebacks resulting from the access here to ensure they 1021 // logically proceed anything happening below 1022 doWritebacksAtomic(writebacks); 1023 1024 if (!satisfied) { --- 5 unchanged lines hidden (view full) --- 1030 (pkt->req->isUncacheable() && pkt->isWrite())) { 1031 lat += ticksToCycles(memSidePort->sendAtomic(pkt)); 1032 return lat * clockPeriod(); 1033 } 1034 // only misses left 1035 1036 PacketPtr bus_pkt = createMissPacket(pkt, blk, pkt->needsWritable()); 1037 | 1017 PacketList writebacks; 1018 bool satisfied = access(pkt, blk, lat, writebacks); 1019 1020 // handle writebacks resulting from the access here to ensure they 1021 // logically proceed anything happening below 1022 doWritebacksAtomic(writebacks); 1023 1024 if (!satisfied) { --- 5 unchanged lines hidden (view full) --- 1030 (pkt->req->isUncacheable() && pkt->isWrite())) { 1031 lat += ticksToCycles(memSidePort->sendAtomic(pkt)); 1032 return lat * clockPeriod(); 1033 } 1034 // only misses left 1035 1036 PacketPtr bus_pkt = createMissPacket(pkt, blk, pkt->needsWritable()); 1037 |
1038 bool is_forward = (bus_pkt == NULL); | 1038 bool is_forward = (bus_pkt == nullptr); |
1039 1040 if (is_forward) { 1041 // just forwarding the same request to the next level 1042 // no local cache operation involved 1043 bus_pkt = pkt; 1044 } 1045 1046 DPRINTF(Cache, "Sending an atomic %s for %#llx (%s)\n", --- 223 unchanged lines hidden (view full) --- 1270 // we have dealt with any (uncacheable) writes above, from here on 1271 // we know we are dealing with an MSHR due to a miss or a prefetch 1272 MSHR *mshr = dynamic_cast<MSHR*>(pkt->popSenderState()); 1273 assert(mshr); 1274 1275 if (mshr == noTargetMSHR) { 1276 // we always clear at least one target 1277 clearBlocked(Blocked_NoTargets); | 1039 1040 if (is_forward) { 1041 // just forwarding the same request to the next level 1042 // no local cache operation involved 1043 bus_pkt = pkt; 1044 } 1045 1046 DPRINTF(Cache, "Sending an atomic %s for %#llx (%s)\n", --- 223 unchanged lines hidden (view full) --- 1270 // we have dealt with any (uncacheable) writes above, from here on 1271 // we know we are dealing with an MSHR due to a miss or a prefetch 1272 MSHR *mshr = dynamic_cast<MSHR*>(pkt->popSenderState()); 1273 assert(mshr); 1274 1275 if (mshr == noTargetMSHR) { 1276 // we always clear at least one target 1277 clearBlocked(Blocked_NoTargets); |
1278 noTargetMSHR = NULL; | 1278 noTargetMSHR = nullptr; |
1279 } 1280 1281 // Initial target is used just for stats 1282 MSHR::Target *initial_tgt = mshr->getTarget(); 1283 int stats_cmd_idx = initial_tgt->pkt->cmdToIndex(); 1284 Tick miss_latency = curTick() - initial_tgt->recvTime; 1285 1286 if (pkt->req->isUncacheable()) { --- 23 unchanged lines hidden (view full) --- 1310 1311 CacheBlk *blk = tags->findBlock(pkt->getAddr(), pkt->isSecure()); 1312 1313 if (is_fill && !is_error) { 1314 DPRINTF(Cache, "Block for addr %#llx being updated in Cache\n", 1315 pkt->getAddr()); 1316 1317 blk = handleFill(pkt, blk, writebacks, mshr->allocOnFill); | 1279 } 1280 1281 // Initial target is used just for stats 1282 MSHR::Target *initial_tgt = mshr->getTarget(); 1283 int stats_cmd_idx = initial_tgt->pkt->cmdToIndex(); 1284 Tick miss_latency = curTick() - initial_tgt->recvTime; 1285 1286 if (pkt->req->isUncacheable()) { --- 23 unchanged lines hidden (view full) --- 1310 1311 CacheBlk *blk = tags->findBlock(pkt->getAddr(), pkt->isSecure()); 1312 1313 if (is_fill && !is_error) { 1314 DPRINTF(Cache, "Block for addr %#llx being updated in Cache\n", 1315 pkt->getAddr()); 1316 1317 blk = handleFill(pkt, blk, writebacks, mshr->allocOnFill); |
1318 assert(blk != NULL); | 1318 assert(blk != nullptr); |
1319 } 1320 1321 // allow invalidation responses originating from write-line 1322 // requests to be discarded 1323 bool is_invalidate = pkt->isInvalidate(); 1324 1325 // First offset for critical word first calculations 1326 int initial_offset = initial_tgt->pkt->getOffset(blkSize); --- 28 unchanged lines hidden (view full) --- 1355 // from above. 1356 if (tgt_pkt->cmd == MemCmd::WriteLineReq) { 1357 assert(!is_error); 1358 // we got the block in a writable state, so promote 1359 // any deferred targets if possible 1360 mshr->promoteWritable(); 1361 // NB: we use the original packet here and not the response! 1362 blk = handleFill(tgt_pkt, blk, writebacks, mshr->allocOnFill); | 1319 } 1320 1321 // allow invalidation responses originating from write-line 1322 // requests to be discarded 1323 bool is_invalidate = pkt->isInvalidate(); 1324 1325 // First offset for critical word first calculations 1326 int initial_offset = initial_tgt->pkt->getOffset(blkSize); --- 28 unchanged lines hidden (view full) --- 1355 // from above. 1356 if (tgt_pkt->cmd == MemCmd::WriteLineReq) { 1357 assert(!is_error); 1358 // we got the block in a writable state, so promote 1359 // any deferred targets if possible 1360 mshr->promoteWritable(); 1361 // NB: we use the original packet here and not the response! 1362 blk = handleFill(tgt_pkt, blk, writebacks, mshr->allocOnFill); |
1363 assert(blk != NULL); | 1363 assert(blk != nullptr); |
1364 1365 // treat as a fill, and discard the invalidation 1366 // response 1367 is_fill = true; 1368 is_invalidate = false; 1369 } 1370 1371 if (is_fill) { --- 283 unchanged lines hidden (view full) --- 1655 return true; 1656} 1657 1658CacheBlk* 1659Cache::allocateBlock(Addr addr, bool is_secure, PacketList &writebacks) 1660{ 1661 CacheBlk *blk = tags->findVictim(addr); 1662 | 1364 1365 // treat as a fill, and discard the invalidation 1366 // response 1367 is_fill = true; 1368 is_invalidate = false; 1369 } 1370 1371 if (is_fill) { --- 283 unchanged lines hidden (view full) --- 1655 return true; 1656} 1657 1658CacheBlk* 1659Cache::allocateBlock(Addr addr, bool is_secure, PacketList &writebacks) 1660{ 1661 CacheBlk *blk = tags->findVictim(addr); 1662 |
1663 // It is valid to return NULL if there is no victim | 1663 // It is valid to return nullptr if there is no victim |
1664 if (!blk) 1665 return nullptr; 1666 1667 if (blk->isValid()) { 1668 Addr repl_addr = tags->regenerateBlkAddr(blk->tag, blk->set); 1669 MSHR *repl_mshr = mshrQueue.findMatch(repl_addr, blk->isSecure()); 1670 if (repl_mshr) { 1671 // must be an outstanding upgrade request 1672 // on a block we're about to replace... 1673 assert(!blk->isWritable() || blk->isDirty()); 1674 assert(repl_mshr->needsWritable()); 1675 // too hard to replace block with transient state 1676 // allocation failed, block not inserted | 1664 if (!blk) 1665 return nullptr; 1666 1667 if (blk->isValid()) { 1668 Addr repl_addr = tags->regenerateBlkAddr(blk->tag, blk->set); 1669 MSHR *repl_mshr = mshrQueue.findMatch(repl_addr, blk->isSecure()); 1670 if (repl_mshr) { 1671 // must be an outstanding upgrade request 1672 // on a block we're about to replace... 1673 assert(!blk->isWritable() || blk->isDirty()); 1674 assert(repl_mshr->needsWritable()); 1675 // too hard to replace block with transient state 1676 // allocation failed, block not inserted |
1677 return NULL; | 1677 return nullptr; |
1678 } else { 1679 DPRINTF(Cache, "replacement: replacing %#llx (%s) with %#llx " 1680 "(%s): %s\n", repl_addr, blk->isSecure() ? "s" : "ns", 1681 addr, is_secure ? "s" : "ns", 1682 blk->isDirty() ? "writeback" : "clean"); 1683 1684 if (blk->wasPrefetched()) { 1685 unusedPrefetches++; --- 35 unchanged lines hidden (view full) --- 1721#if TRACING_ON 1722 CacheBlk::State old_state = blk ? blk->status : 0; 1723#endif 1724 1725 // When handling a fill, we should have no writes to this line. 1726 assert(addr == blockAlign(addr)); 1727 assert(!writeBuffer.findMatch(addr, is_secure)); 1728 | 1678 } else { 1679 DPRINTF(Cache, "replacement: replacing %#llx (%s) with %#llx " 1680 "(%s): %s\n", repl_addr, blk->isSecure() ? "s" : "ns", 1681 addr, is_secure ? "s" : "ns", 1682 blk->isDirty() ? "writeback" : "clean"); 1683 1684 if (blk->wasPrefetched()) { 1685 unusedPrefetches++; --- 35 unchanged lines hidden (view full) --- 1721#if TRACING_ON 1722 CacheBlk::State old_state = blk ? blk->status : 0; 1723#endif 1724 1725 // When handling a fill, we should have no writes to this line. 1726 assert(addr == blockAlign(addr)); 1727 assert(!writeBuffer.findMatch(addr, is_secure)); 1728 |
1729 if (blk == NULL) { | 1729 if (blk == nullptr) { |
1730 // better have read new data... 1731 assert(pkt->hasData()); 1732 1733 // only read responses and write-line requests have data; 1734 // note that we don't write the data here for write-line - that 1735 // happens in the subsequent satisfyCpuSideRequest. 1736 assert(pkt->isRead() || pkt->cmd == MemCmd::WriteLineReq); 1737 1738 // need to do a replacement if allocating, otherwise we stick 1739 // with the temporary storage | 1730 // better have read new data... 1731 assert(pkt->hasData()); 1732 1733 // only read responses and write-line requests have data; 1734 // note that we don't write the data here for write-line - that 1735 // happens in the subsequent satisfyCpuSideRequest. 1736 assert(pkt->isRead() || pkt->cmd == MemCmd::WriteLineReq); 1737 1738 // need to do a replacement if allocating, otherwise we stick 1739 // with the temporary storage |
1740 blk = allocate ? allocateBlock(addr, is_secure, writebacks) : NULL; | 1740 blk = allocate ? allocateBlock(addr, is_secure, writebacks) : nullptr; |
1741 | 1741 |
1742 if (blk == NULL) { | 1742 if (blk == nullptr) { |
1743 // No replaceable block or a mostly exclusive 1744 // cache... just use temporary storage to complete the 1745 // current request and then get rid of it 1746 assert(!tempBlock->isValid()); 1747 blk = tempBlock; 1748 tempBlock->set = tags->extractSet(addr); 1749 tempBlock->tag = tags->extractTag(addr); 1750 // @todo: set security state as well... --- 553 unchanged lines hidden (view full) --- 2304 // of the block. 2305 if (is_timing) { 2306 Packet snoop_pkt(pkt, true, false); 2307 snoop_pkt.setExpressSnoop(); 2308 // Assert that packet is either Writeback or CleanEvict and not a 2309 // prefetch request because prefetch requests need an MSHR and may 2310 // generate a snoop response. 2311 assert(pkt->isEviction()); | 1743 // No replaceable block or a mostly exclusive 1744 // cache... just use temporary storage to complete the 1745 // current request and then get rid of it 1746 assert(!tempBlock->isValid()); 1747 blk = tempBlock; 1748 tempBlock->set = tags->extractSet(addr); 1749 tempBlock->tag = tags->extractTag(addr); 1750 // @todo: set security state as well... --- 553 unchanged lines hidden (view full) --- 2304 // of the block. 2305 if (is_timing) { 2306 Packet snoop_pkt(pkt, true, false); 2307 snoop_pkt.setExpressSnoop(); 2308 // Assert that packet is either Writeback or CleanEvict and not a 2309 // prefetch request because prefetch requests need an MSHR and may 2310 // generate a snoop response. 2311 assert(pkt->isEviction()); |
2312 snoop_pkt.senderState = NULL; | 2312 snoop_pkt.senderState = nullptr; |
2313 cpuSidePort->sendTimingSnoopReq(&snoop_pkt); 2314 // Writeback/CleanEvict snoops do not generate a snoop response. 2315 assert(!(snoop_pkt.cacheResponding())); 2316 return snoop_pkt.isBlockCached(); 2317 } else { 2318 cpuSidePort->sendAtomicSnoop(pkt); 2319 return pkt->isBlockCached(); 2320 } --- 27 unchanged lines hidden (view full) --- 2348 tgt_pkt->cmdString(), tgt_pkt->getAddr(), 2349 tgt_pkt->getSize()); 2350 2351 CacheBlk *blk = tags->findBlock(mshr->blkAddr, mshr->isSecure); 2352 2353 if (tgt_pkt->cmd == MemCmd::HardPFReq && forwardSnoops) { 2354 // we should never have hardware prefetches to allocated 2355 // blocks | 2313 cpuSidePort->sendTimingSnoopReq(&snoop_pkt); 2314 // Writeback/CleanEvict snoops do not generate a snoop response. 2315 assert(!(snoop_pkt.cacheResponding())); 2316 return snoop_pkt.isBlockCached(); 2317 } else { 2318 cpuSidePort->sendAtomicSnoop(pkt); 2319 return pkt->isBlockCached(); 2320 } --- 27 unchanged lines hidden (view full) --- 2348 tgt_pkt->cmdString(), tgt_pkt->getAddr(), 2349 tgt_pkt->getSize()); 2350 2351 CacheBlk *blk = tags->findBlock(mshr->blkAddr, mshr->isSecure); 2352 2353 if (tgt_pkt->cmd == MemCmd::HardPFReq && forwardSnoops) { 2354 // we should never have hardware prefetches to allocated 2355 // blocks |
2356 assert(blk == NULL); | 2356 assert(blk == nullptr); |
2357 2358 // We need to check the caches above us to verify that 2359 // they don't have a copy of this block in the dirty state 2360 // at the moment. Without this check we could get a stale 2361 // copy from memory that might get used in place of the 2362 // dirty one. 2363 Packet snoop_pkt(tgt_pkt, true, false); 2364 snoop_pkt.setExpressSnoop(); --- 45 unchanged lines hidden (view full) --- 2410 return false; 2411 } 2412 } 2413 2414 // either a prefetch that is not present upstream, or a normal 2415 // MSHR request, proceed to get the packet to send downstream 2416 PacketPtr pkt = createMissPacket(tgt_pkt, blk, mshr->needsWritable()); 2417 | 2357 2358 // We need to check the caches above us to verify that 2359 // they don't have a copy of this block in the dirty state 2360 // at the moment. Without this check we could get a stale 2361 // copy from memory that might get used in place of the 2362 // dirty one. 2363 Packet snoop_pkt(tgt_pkt, true, false); 2364 snoop_pkt.setExpressSnoop(); --- 45 unchanged lines hidden (view full) --- 2410 return false; 2411 } 2412 } 2413 2414 // either a prefetch that is not present upstream, or a normal 2415 // MSHR request, proceed to get the packet to send downstream 2416 PacketPtr pkt = createMissPacket(tgt_pkt, blk, mshr->needsWritable()); 2417 |
2418 mshr->isForward = (pkt == NULL); | 2418 mshr->isForward = (pkt == nullptr); |
2419 2420 if (mshr->isForward) { 2421 // not a cache block request, but a response is expected 2422 // make copy of current packet to forward, keep current 2423 // copy for response handling 2424 pkt = new Packet(tgt_pkt, false, true); 2425 assert(!pkt->isWrite()); 2426 } --- 236 unchanged lines hidden --- | 2419 2420 if (mshr->isForward) { 2421 // not a cache block request, but a response is expected 2422 // make copy of current packet to forward, keep current 2423 // copy for response handling 2424 pkt = new Packet(tgt_pkt, false, true); 2425 assert(!pkt->isWrite()); 2426 } --- 236 unchanged lines hidden --- |