cache.cc (11600:a38c3f9c82d1) cache.cc (11601:382e0637fae0)
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

--- 132 unchanged lines hidden (view full) ---

141 if (overwrite_mem) {
142 std::memcpy(blk_data, &overwrite_val, pkt->getSize());
143 blk->status |= BlkDirty;
144 }
145}
146
147
148void
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

--- 132 unchanged lines hidden (view full) ---

141 if (overwrite_mem) {
142 std::memcpy(blk_data, &overwrite_val, pkt->getSize());
143 blk->status |= BlkDirty;
144 }
145}
146
147
148void
149Cache::satisfyCpuSideRequest(PacketPtr pkt, CacheBlk *blk,
150 bool deferred_response, bool pending_downgrade)
149Cache::satisfyRequest(PacketPtr pkt, CacheBlk *blk,
150 bool deferred_response, bool pending_downgrade)
151{
152 assert(pkt->isRequest());
153
154 assert(blk && blk->isValid());
155 // Occasionally this is not true... if we are a lower-level cache
156 // satisfying a string of Read and ReadEx requests from
157 // upper-level caches, a Read will mark the block as shared but we
158 // can satisfy a following ReadEx anyway since we can rely on the

--- 66 unchanged lines hidden (view full) ---

225 // copy of the line
226 if (blk->isDirty()) {
227 // special considerations if we're owner:
228 if (!deferred_response) {
229 // respond with the line in Modified state
230 // (cacheResponding set, hasSharers not set)
231 pkt->setCacheResponding();
232
151{
152 assert(pkt->isRequest());
153
154 assert(blk && blk->isValid());
155 // Occasionally this is not true... if we are a lower-level cache
156 // satisfying a string of Read and ReadEx requests from
157 // upper-level caches, a Read will mark the block as shared but we
158 // can satisfy a following ReadEx anyway since we can rely on the

--- 66 unchanged lines hidden (view full) ---

225 // copy of the line
226 if (blk->isDirty()) {
227 // special considerations if we're owner:
228 if (!deferred_response) {
229 // respond with the line in Modified state
230 // (cacheResponding set, hasSharers not set)
231 pkt->setCacheResponding();
232
233 if (clusivity == Enums::mostly_excl) {
234 // if this cache is mostly exclusive with
235 // respect to the cache above, drop the
236 // block, no need to first unset the dirty
237 // bit
238 invalidateBlock(blk);
239 } else {
240 // if this cache is mostly inclusive, we
241 // keep the block in the Exclusive state,
242 // and pass it upwards as Modified
243 // (writable and dirty), hence we have
244 // multiple caches, all on the same path
245 // towards memory, all considering the
246 // same block writable, but only one
247 // considering it Modified
233 // if this cache is mostly inclusive, we
234 // keep the block in the Exclusive state,
235 // and pass it upwards as Modified
236 // (writable and dirty), hence we have
237 // multiple caches, all on the same path
238 // towards memory, all considering the
239 // same block writable, but only one
240 // considering it Modified
248
241
249 // we get away with multiple caches (on
250 // the same path to memory) considering
251 // the block writeable as we always enter
252 // the cache hierarchy through a cache,
253 // and first snoop upwards in all other
254 // branches
255 blk->status &= ~BlkDirty;
256 }
242 // we get away with multiple caches (on
243 // the same path to memory) considering
244 // the block writeable as we always enter
245 // the cache hierarchy through a cache,
246 // and first snoop upwards in all other
247 // branches
248 blk->status &= ~BlkDirty;
257 } else {
258 // if we're responding after our own miss,
259 // there's a window where the recipient didn't
260 // know it was getting ownership and may not
261 // have responded to snoops correctly, so we
262 // have to respond with a shared line
263 pkt->setHasSharers();
264 }

--- 163 unchanged lines hidden (view full) ---

428 // it.
429 return true;
430 }
431 // We didn't find the block here, propagate the CleanEvict further
432 // down the memory hierarchy. Returning false will treat the CleanEvict
433 // like a Writeback which could not find a replaceable block so has to
434 // go to next level.
435 return false;
249 } else {
250 // if we're responding after our own miss,
251 // there's a window where the recipient didn't
252 // know it was getting ownership and may not
253 // have responded to snoops correctly, so we
254 // have to respond with a shared line
255 pkt->setHasSharers();
256 }

--- 163 unchanged lines hidden (view full) ---

420 // it.
421 return true;
422 }
423 // We didn't find the block here, propagate the CleanEvict further
424 // down the memory hierarchy. Returning false will treat the CleanEvict
425 // like a Writeback which could not find a replaceable block so has to
426 // go to next level.
427 return false;
436 } else if ((blk != nullptr) &&
437 (pkt->needsWritable() ? blk->isWritable() :
438 blk->isReadable())) {
428 } else if (blk && (pkt->needsWritable() ? blk->isWritable() :
429 blk->isReadable())) {
439 // OK to satisfy access
440 incHitCount(pkt);
430 // OK to satisfy access
431 incHitCount(pkt);
441 satisfyCpuSideRequest(pkt, blk);
432 satisfyRequest(pkt, blk);
433 maintainClusivity(pkt->fromCache(), blk);
434
442 return true;
443 }
444
445 // Can't satisfy access normally... either no block (blk == nullptr)
446 // or have block but need writable
447
448 incMissCount(pkt);
449
450 if (blk == nullptr && pkt->isLLSC() && pkt->isWrite()) {
451 // complete miss on store conditional... just give up now
452 pkt->req->setExtraData(0);
453 return true;
454 }
455
456 return false;
457}
458
459void
435 return true;
436 }
437
438 // Can't satisfy access normally... either no block (blk == nullptr)
439 // or have block but need writable
440
441 incMissCount(pkt);
442
443 if (blk == nullptr && pkt->isLLSC() && pkt->isWrite()) {
444 // complete miss on store conditional... just give up now
445 pkt->req->setExtraData(0);
446 return true;
447 }
448
449 return false;
450}
451
452void
453Cache::maintainClusivity(bool from_cache, CacheBlk *blk)
454{
455 if (from_cache && blk && blk->isValid() && !blk->isDirty() &&
456 clusivity == Enums::mostly_excl) {
457 // if we have responded to a cache, and our block is still
458 // valid, but not dirty, and this cache is mostly exclusive
459 // with respect to the cache above, drop the block
460 invalidateBlock(blk);
461 }
462}
463
464void
460Cache::doWritebacks(PacketList& writebacks, Tick forward_time)
461{
462 while (!writebacks.empty()) {
463 PacketPtr wbPkt = writebacks.front();
464 // We use forwardLatency here because we are copying writebacks to
465 // write buffer. Call isCachedAbove for both Writebacks and
466 // CleanEvicts. If isCachedAbove returns true we set BLOCK_CACHED flag
467 // in Writebacks and discard CleanEvicts.

--- 600 unchanged lines hidden (view full) ---

1068 // note the use of pkt, not bus_pkt here.
1069
1070 // write-line request to the cache that promoted
1071 // the write to a whole line
1072 blk = handleFill(pkt, blk, writebacks,
1073 allocOnFill(pkt->cmd));
1074 assert(blk != NULL);
1075 is_invalidate = false;
465Cache::doWritebacks(PacketList& writebacks, Tick forward_time)
466{
467 while (!writebacks.empty()) {
468 PacketPtr wbPkt = writebacks.front();
469 // We use forwardLatency here because we are copying writebacks to
470 // write buffer. Call isCachedAbove for both Writebacks and
471 // CleanEvicts. If isCachedAbove returns true we set BLOCK_CACHED flag
472 // in Writebacks and discard CleanEvicts.

--- 600 unchanged lines hidden (view full) ---

1073 // note the use of pkt, not bus_pkt here.
1074
1075 // write-line request to the cache that promoted
1076 // the write to a whole line
1077 blk = handleFill(pkt, blk, writebacks,
1078 allocOnFill(pkt->cmd));
1079 assert(blk != NULL);
1080 is_invalidate = false;
1076 satisfyCpuSideRequest(pkt, blk);
1081 satisfyRequest(pkt, blk);
1077 } else if (bus_pkt->isRead() ||
1078 bus_pkt->cmd == MemCmd::UpgradeResp) {
1079 // we're updating cache state to allow us to
1080 // satisfy the upstream request from the cache
1081 blk = handleFill(bus_pkt, blk, writebacks,
1082 allocOnFill(pkt->cmd));
1082 } else if (bus_pkt->isRead() ||
1083 bus_pkt->cmd == MemCmd::UpgradeResp) {
1084 // we're updating cache state to allow us to
1085 // satisfy the upstream request from the cache
1086 blk = handleFill(bus_pkt, blk, writebacks,
1087 allocOnFill(pkt->cmd));
1083 satisfyCpuSideRequest(pkt, blk);
1088 satisfyRequest(pkt, blk);
1089 maintainClusivity(pkt->fromCache(), blk);
1084 } else {
1085 // we're satisfying the upstream request without
1086 // modifying cache state, e.g., a write-through
1087 pkt->makeAtomicResponse();
1088 }
1089 }
1090 delete bus_pkt;
1091 }

--- 221 unchanged lines hidden (view full) ---

1313
1314 // allow invalidation responses originating from write-line
1315 // requests to be discarded
1316 bool is_invalidate = pkt->isInvalidate();
1317
1318 // First offset for critical word first calculations
1319 int initial_offset = initial_tgt->pkt->getOffset(blkSize);
1320
1090 } else {
1091 // we're satisfying the upstream request without
1092 // modifying cache state, e.g., a write-through
1093 pkt->makeAtomicResponse();
1094 }
1095 }
1096 delete bus_pkt;
1097 }

--- 221 unchanged lines hidden (view full) ---

1319
1320 // allow invalidation responses originating from write-line
1321 // requests to be discarded
1322 bool is_invalidate = pkt->isInvalidate();
1323
1324 // First offset for critical word first calculations
1325 int initial_offset = initial_tgt->pkt->getOffset(blkSize);
1326
1327 bool from_cache = false;
1328
1321 while (mshr->hasTargets()) {
1322 MSHR::Target *target = mshr->getTarget();
1323 Packet *tgt_pkt = target->pkt;
1324
1325 switch (target->source) {
1326 case MSHR::Target::FromCPU:
1327 Tick completion_time;
1328 // Here we charge on completion_time the delay of the xbar if the

--- 6 unchanged lines hidden (view full) ---

1335 // immediately with dummy data so the core would be able to
1336 // retire it. This request completes right here, so we
1337 // deallocate it.
1338 delete tgt_pkt->req;
1339 delete tgt_pkt;
1340 break; // skip response
1341 }
1342
1329 while (mshr->hasTargets()) {
1330 MSHR::Target *target = mshr->getTarget();
1331 Packet *tgt_pkt = target->pkt;
1332
1333 switch (target->source) {
1334 case MSHR::Target::FromCPU:
1335 Tick completion_time;
1336 // Here we charge on completion_time the delay of the xbar if the

--- 6 unchanged lines hidden (view full) ---

1343 // immediately with dummy data so the core would be able to
1344 // retire it. This request completes right here, so we
1345 // deallocate it.
1346 delete tgt_pkt->req;
1347 delete tgt_pkt;
1348 break; // skip response
1349 }
1350
1351 // keep track of whether we have responded to another
1352 // cache
1353 from_cache = from_cache || tgt_pkt->fromCache();
1354
1343 // unlike the other packet flows, where data is found in other
1344 // caches or memory and brought back, write-line requests always
1345 // have the data right away, so the above check for "is fill?"
1346 // cannot actually be determined until examining the stored MSHR
1347 // state. We "catch up" with that logic here, which is duplicated
1348 // from above.
1349 if (tgt_pkt->cmd == MemCmd::WriteLineReq) {
1350 assert(!is_error);

--- 6 unchanged lines hidden (view full) ---

1357
1358 // treat as a fill, and discard the invalidation
1359 // response
1360 is_fill = true;
1361 is_invalidate = false;
1362 }
1363
1364 if (is_fill) {
1355 // unlike the other packet flows, where data is found in other
1356 // caches or memory and brought back, write-line requests always
1357 // have the data right away, so the above check for "is fill?"
1358 // cannot actually be determined until examining the stored MSHR
1359 // state. We "catch up" with that logic here, which is duplicated
1360 // from above.
1361 if (tgt_pkt->cmd == MemCmd::WriteLineReq) {
1362 assert(!is_error);

--- 6 unchanged lines hidden (view full) ---

1369
1370 // treat as a fill, and discard the invalidation
1371 // response
1372 is_fill = true;
1373 is_invalidate = false;
1374 }
1375
1376 if (is_fill) {
1365 satisfyCpuSideRequest(tgt_pkt, blk,
1366 true, mshr->hasPostDowngrade());
1377 satisfyRequest(tgt_pkt, blk, true, mshr->hasPostDowngrade());
1367
1368 // How many bytes past the first request is this one
1369 int transfer_offset =
1370 tgt_pkt->getOffset(blkSize) - initial_offset;
1371 if (transfer_offset < 0) {
1372 transfer_offset += blkSize;
1373 }
1374

--- 71 unchanged lines hidden (view full) ---

1446
1447 default:
1448 panic("Illegal target->source enum %d\n", target->source);
1449 }
1450
1451 mshr->popTarget();
1452 }
1453
1378
1379 // How many bytes past the first request is this one
1380 int transfer_offset =
1381 tgt_pkt->getOffset(blkSize) - initial_offset;
1382 if (transfer_offset < 0) {
1383 transfer_offset += blkSize;
1384 }
1385

--- 71 unchanged lines hidden (view full) ---

1457
1458 default:
1459 panic("Illegal target->source enum %d\n", target->source);
1460 }
1461
1462 mshr->popTarget();
1463 }
1464
1465 maintainClusivity(from_cache, blk);
1466
1454 if (blk && blk->isValid()) {
1455 // an invalidate response stemming from a write line request
1456 // should not invalidate the block, so check if the
1457 // invalidation should be discarded
1458 if (is_invalidate || mshr->hasPostInvalidate()) {
1459 invalidateBlock(blk);
1460 } else if (mshr->hasPostDowngrade()) {
1461 blk->status &= ~BlkWritable;

--- 258 unchanged lines hidden (view full) ---

1720 assert(!writeBuffer.findMatch(addr, is_secure));
1721
1722 if (blk == nullptr) {
1723 // better have read new data...
1724 assert(pkt->hasData());
1725
1726 // only read responses and write-line requests have data;
1727 // note that we don't write the data here for write-line - that
1467 if (blk && blk->isValid()) {
1468 // an invalidate response stemming from a write line request
1469 // should not invalidate the block, so check if the
1470 // invalidation should be discarded
1471 if (is_invalidate || mshr->hasPostInvalidate()) {
1472 invalidateBlock(blk);
1473 } else if (mshr->hasPostDowngrade()) {
1474 blk->status &= ~BlkWritable;

--- 258 unchanged lines hidden (view full) ---

1733 assert(!writeBuffer.findMatch(addr, is_secure));
1734
1735 if (blk == nullptr) {
1736 // better have read new data...
1737 assert(pkt->hasData());
1738
1739 // only read responses and write-line requests have data;
1740 // note that we don't write the data here for write-line - that
1728 // happens in the subsequent satisfyCpuSideRequest.
1741 // happens in the subsequent call to satisfyRequest
1729 assert(pkt->isRead() || pkt->cmd == MemCmd::WriteLineReq);
1730
1731 // need to do a replacement if allocating, otherwise we stick
1732 // with the temporary storage
1733 blk = allocate ? allocateBlock(addr, is_secure, writebacks) : nullptr;
1734
1735 if (blk == nullptr) {
1736 // No replaceable block or a mostly exclusive

--- 22 unchanged lines hidden (view full) ---

1759 }
1760
1761 if (is_secure)
1762 blk->status |= BlkSecure;
1763 blk->status |= BlkValid | BlkReadable;
1764
1765 // sanity check for whole-line writes, which should always be
1766 // marked as writable as part of the fill, and then later marked
1742 assert(pkt->isRead() || pkt->cmd == MemCmd::WriteLineReq);
1743
1744 // need to do a replacement if allocating, otherwise we stick
1745 // with the temporary storage
1746 blk = allocate ? allocateBlock(addr, is_secure, writebacks) : nullptr;
1747
1748 if (blk == nullptr) {
1749 // No replaceable block or a mostly exclusive

--- 22 unchanged lines hidden (view full) ---

1772 }
1773
1774 if (is_secure)
1775 blk->status |= BlkSecure;
1776 blk->status |= BlkValid | BlkReadable;
1777
1778 // sanity check for whole-line writes, which should always be
1779 // marked as writable as part of the fill, and then later marked
1767 // dirty as part of satisfyCpuSideRequest
1780 // dirty as part of satisfyRequest
1768 if (pkt->cmd == MemCmd::WriteLineReq) {
1769 assert(!pkt->hasSharers());
1770 // at the moment other caches do not respond to the
1771 // invalidation requests corresponding to a whole-line write
1772 assert(!pkt->cacheResponding());
1773 }
1774
1775 // here we deal with setting the appropriate state of the line,

--- 894 unchanged lines hidden ---
1781 if (pkt->cmd == MemCmd::WriteLineReq) {
1782 assert(!pkt->hasSharers());
1783 // at the moment other caches do not respond to the
1784 // invalidation requests corresponding to a whole-line write
1785 assert(!pkt->cacheResponding());
1786 }
1787
1788 // here we deal with setting the appropriate state of the line,

--- 894 unchanged lines hidden ---