1/* 2 * Copyright (c) 2010-2015 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 --- 54 unchanged lines hidden (view full) --- 63#include "mem/cache/prefetch/base.hh" 64#include "sim/sim_exit.hh" 65 66Cache::Cache(const CacheParams *p) 67 : BaseCache(p, p->system->cacheLineSize()), 68 tags(p->tags), 69 prefetcher(p->prefetcher), 70 doFastWrites(true), |
71 prefetchOnAccess(p->prefetch_on_access), 72 clusivity(p->clusivity), 73 tempBlockWriteback(nullptr), 74 writebackTempBlockAtomicEvent(this, false, 75 EventBase::Delayed_Writeback_Pri) |
76{ 77 tempBlock = new CacheBlk(); 78 tempBlock->data = new uint8_t[blkSize]; 79 80 cpuSidePort = new CpuSidePort(p->name + ".cpu_side", this, 81 "CpuSidePort"); 82 memSidePort = new MemSidePort(p->name + ".mem_side", this, 83 "MemSidePort"); --- 113 unchanged lines hidden (view full) --- 197 assert(pkt->cmd == MemCmd::ReadExReq || 198 pkt->cmd == MemCmd::SCUpgradeFailReq); 199 200 // if we have a dirty copy, make sure the recipient 201 // keeps it marked dirty 202 if (blk->isDirty()) { 203 pkt->assertMemInhibit(); 204 } |
205 // on ReadExReq we give up our copy unconditionally, 206 // even if this cache is mostly inclusive, we may want 207 // to revisit this 208 invalidateBlock(blk); |
209 } else if (blk->isWritable() && !pending_downgrade && 210 !pkt->sharedAsserted() && 211 pkt->cmd != MemCmd::ReadCleanReq) { 212 // we can give the requester an exclusive copy (by not 213 // asserting shared line) on a read request if: 214 // - we have an exclusive copy at this level (& below) 215 // - we don't have a pending snoop from below 216 // signaling another read request 217 // - no other cache above has a copy (otherwise it 218 // would have asseretd shared line on request) 219 // - we are not satisfying an instruction fetch (this 220 // prevents dirty data in the i-cache) 221 222 if (blk->isDirty()) { 223 // special considerations if we're owner: 224 if (!deferred_response) { 225 // if we are responding immediately and can 226 // signal that we're transferring ownership |
227 // (inhibit set) along with exclusivity 228 // (shared not set), do so |
229 pkt->assertMemInhibit(); |
230 231 // if this cache is mostly inclusive, we keep 232 // the block as writable (exclusive), and pass 233 // it upwards as writable and dirty 234 // (modified), hence we have multiple caches 235 // considering the same block writable, 236 // something that we get away with due to the 237 // fact that: 1) this cache has been 238 // considered the ordering points and 239 // responded to all snoops up till now, and 2) 240 // we always snoop upwards before consulting 241 // the local cache, both on a normal request 242 // (snooping done by the crossbar), and on a 243 // snoop |
244 blk->status &= ~BlkDirty; |
245 246 // if this cache is mostly exclusive with 247 // respect to the cache above, drop the block 248 if (clusivity == Enums::mostly_excl) { 249 invalidateBlock(blk); 250 } |
251 } else { 252 // if we're responding after our own miss, 253 // there's a window where the recipient didn't 254 // know it was getting ownership and may not 255 // have responded to snoops correctly, so we 256 // can't pass off ownership *or* exclusivity 257 pkt->assertShared(); 258 } 259 } 260 } else { 261 // otherwise only respond with a shared copy 262 pkt->assertShared(); 263 } 264 } 265 } else { 266 // Upgrade or Invalidate, since we have it Exclusively (E or 267 // M), we ack then invalidate. 268 assert(pkt->isUpgrade() || pkt->isInvalidate()); |
269 270 // for invalidations we could be looking at the temp block 271 // (for upgrades we always allocate) 272 invalidateBlock(blk); |
273 DPRINTF(Cache, "%s for %s addr %#llx size %d (invalidation)\n", 274 __func__, pkt->cmdString(), pkt->getAddr(), pkt->getSize()); 275 } 276} 277 278 279///////////////////////////////////////////////////// 280// --- 501 unchanged lines hidden (view full) --- 782 } 783 // We use forward_time here because it is the same 784 // considering new targets. We have multiple 785 // requests for the same address here. It 786 // specifies the latency to allocate an internal 787 // buffer and to schedule an event to the queued 788 // port and also takes into account the additional 789 // delay of the xbar. |
790 mshr->allocateTarget(pkt, forward_time, order++, 791 allocOnFill(pkt->cmd)); |
792 if (mshr->getNumTargets() == numTarget) { 793 noTargetMSHR = mshr; 794 setBlocked(Blocked_NoTargets); 795 // need to be careful with this... if this mshr isn't 796 // ready yet (i.e. time > curTick()), we don't want to 797 // move it ahead of mshrs that are ready 798 // mshrQueue.moveToFront(mshr); 799 } --- 249 unchanged lines hidden (view full) --- 1049 // an invalidate request 1050 satisfyCpuSideRequest(pkt, blk); 1051 } 1052 } else if (pkt->cmd == MemCmd::WriteLineReq) { 1053 // note the use of pkt, not bus_pkt here. 1054 1055 // write-line request to the cache that promoted 1056 // the write to a whole line |
1057 blk = handleFill(pkt, blk, writebacks, 1058 allocOnFill(pkt->cmd)); |
1059 satisfyCpuSideRequest(pkt, blk); 1060 } else if (bus_pkt->isRead() || 1061 bus_pkt->cmd == MemCmd::UpgradeResp) { 1062 // we're updating cache state to allow us to 1063 // satisfy the upstream request from the cache |
1064 blk = handleFill(bus_pkt, blk, writebacks, 1065 allocOnFill(pkt->cmd)); |
1066 satisfyCpuSideRequest(pkt, blk); 1067 } else { 1068 // we're satisfying the upstream request without 1069 // modifying cache state, e.g., a write-through 1070 pkt->makeAtomicResponse(); 1071 } 1072 } 1073 delete bus_pkt; --- 6 unchanged lines hidden (view full) --- 1080 // rely on bandwidth contention to throttle them; these will tend 1081 // to pollute the cache in atomic mode since there is no bandwidth 1082 // contention. If we ever do want to enable prefetching in atomic 1083 // mode, though, this is the place to do it... see timingAccess() 1084 // for an example (though we'd want to issue the prefetch(es) 1085 // immediately rather than calling requestMemSideBus() as we do 1086 // there). 1087 |
1088 // do any writebacks resulting from the response handling |
1089 doWritebacksAtomic(writebacks); 1090 |
1091 // if we used temp block, check to see if its valid and if so 1092 // clear it out, but only do so after the call to recvAtomic is 1093 // finished so that any downstream observers (such as a snoop 1094 // filter), first see the fill, and only then see the eviction 1095 if (blk == tempBlock && tempBlock->isValid()) { 1096 // the atomic CPU calls recvAtomic for fetch and load/store 1097 // sequentuially, and we may already have a tempBlock 1098 // writeback from the fetch that we have not yet sent 1099 if (tempBlockWriteback) { 1100 // if that is the case, write the prevoius one back, and 1101 // do not schedule any new event 1102 writebackTempBlockAtomic(); 1103 } else { 1104 // the writeback/clean eviction happens after the call to 1105 // recvAtomic has finished (but before any successive 1106 // calls), so that the response handling from the fill is 1107 // allowed to happen first 1108 schedule(writebackTempBlockAtomicEvent, curTick()); 1109 } 1110 1111 tempBlockWriteback = blk->isDirty() ? writebackBlk(blk) : 1112 cleanEvictBlk(blk); 1113 blk->invalidate(); 1114 } 1115 |
1116 if (pkt->needsResponse()) { 1117 pkt->makeAtomicResponse(); 1118 } 1119 1120 return lat * clockPeriod(); 1121} 1122 1123 --- 139 unchanged lines hidden (view full) --- 1263 (pkt->isRead() || pkt->cmd == MemCmd::UpgradeResp); 1264 1265 CacheBlk *blk = tags->findBlock(pkt->getAddr(), pkt->isSecure()); 1266 1267 if (is_fill && !is_error) { 1268 DPRINTF(Cache, "Block for addr %#llx being updated in Cache\n", 1269 pkt->getAddr()); 1270 |
1271 blk = handleFill(pkt, blk, writebacks, mshr->allocOnFill); |
1272 assert(blk != NULL); 1273 } 1274 1275 // allow invalidation responses originating from write-line 1276 // requests to be discarded 1277 bool is_invalidate = pkt->isInvalidate(); 1278 1279 // First offset for critical word first calculations --- 27 unchanged lines hidden (view full) --- 1307 // state. We "catch up" with that logic here, which is duplicated 1308 // from above. 1309 if (tgt_pkt->cmd == MemCmd::WriteLineReq) { 1310 assert(!is_error); 1311 // we got the block in exclusive state, so promote any 1312 // deferred targets if possible 1313 mshr->promoteExclusive(); 1314 // NB: we use the original packet here and not the response! |
1315 blk = handleFill(tgt_pkt, blk, writebacks, mshr->allocOnFill); |
1316 assert(blk != NULL); 1317 1318 // treat as a fill, and discard the invalidation 1319 // response 1320 is_fill = true; 1321 is_invalidate = false; 1322 } 1323 --- 87 unchanged lines hidden (view full) --- 1411 mshr->popTarget(); 1412 } 1413 1414 if (blk && blk->isValid()) { 1415 // an invalidate response stemming from a write line request 1416 // should not invalidate the block, so check if the 1417 // invalidation should be discarded 1418 if (is_invalidate || mshr->hasPostInvalidate()) { |
1419 invalidateBlock(blk); |
1420 } else if (mshr->hasPostDowngrade()) { 1421 blk->status &= ~BlkWritable; 1422 } 1423 } 1424 1425 if (mshr->promoteDeferredTargets()) { 1426 // avoid later read getting stale data while write miss is 1427 // outstanding.. see comment in timingAccess() --- 207 unchanged lines hidden (view full) --- 1635 writebacks.push_back(cleanEvictBlk(blk)); 1636 } 1637 } 1638 } 1639 1640 return blk; 1641} 1642 |
1643void 1644Cache::invalidateBlock(CacheBlk *blk) 1645{ 1646 if (blk != tempBlock) 1647 tags->invalidate(blk); 1648 blk->invalidate(); 1649} |
1650 1651// Note that the reason we return a list of writebacks rather than 1652// inserting them directly in the write buffer is that this function 1653// is called by both atomic and timing-mode accesses, and in atomic 1654// mode we don't mess with the write buffer (we just perform the 1655// writebacks atomically once the original request is complete). 1656CacheBlk* |
1657Cache::handleFill(PacketPtr pkt, CacheBlk *blk, PacketList &writebacks, 1658 bool allocate) |
1659{ 1660 assert(pkt->isResponse() || pkt->cmd == MemCmd::WriteLineReq); 1661 Addr addr = pkt->getAddr(); 1662 bool is_secure = pkt->isSecure(); 1663#if TRACING_ON 1664 CacheBlk::State old_state = blk ? blk->status : 0; 1665#endif 1666 --- 7 unchanged lines hidden (view full) --- 1674 // better have read new data... 1675 assert(pkt->hasData()); 1676 1677 // only read responses and write-line requests have data; 1678 // note that we don't write the data here for write-line - that 1679 // happens in the subsequent satisfyCpuSideRequest. 1680 assert(pkt->isRead() || pkt->cmd == MemCmd::WriteLineReq); 1681 |
1682 // need to do a replacement if allocating, otherwise we stick 1683 // with the temporary storage 1684 blk = allocate ? allocateBlock(addr, is_secure, writebacks) : NULL; 1685 |
1686 if (blk == NULL) { |
1687 // No replaceable block or a mostly exclusive 1688 // cache... just use temporary storage to complete the 1689 // current request and then get rid of it |
1690 assert(!tempBlock->isValid()); 1691 blk = tempBlock; 1692 tempBlock->set = tags->extractSet(addr); 1693 tempBlock->tag = tags->extractTag(addr); 1694 // @todo: set security state as well... 1695 DPRINTF(Cache, "using temp block for %#llx (%s)\n", addr, 1696 is_secure ? "s" : "ns"); 1697 } else { --- 237 unchanged lines hidden (view full) --- 1935 1936 if (respond) { 1937 // prevent anyone else from responding, cache as well as 1938 // memory, and also prevent any memory from even seeing the 1939 // request (with current inhibited semantics), note that this 1940 // applies both to reads and writes and that for writes it 1941 // works thanks to the fact that we still have dirty data and 1942 // will write it back at a later point |
1943 assert(!pkt->memInhibitAsserted()); |
1944 pkt->assertMemInhibit(); 1945 if (have_exclusive) { 1946 // in the case of an uncacheable request there is no point 1947 // in setting the exclusive flag, but since the recipient 1948 // does not care there is no harm in doing so, in any case 1949 // it is just a hint 1950 pkt->setSupplyExclusive(); 1951 } --- 18 unchanged lines hidden (view full) --- 1970 assert(pkt->needsResponse()); 1971 delete pkt->req; 1972 delete pkt; 1973 } 1974 1975 // Do this last in case it deallocates block data or something 1976 // like that 1977 if (invalidate) { |
1978 invalidateBlock(blk); |
1979 } 1980 1981 DPRINTF(Cache, "new state is %s\n", blk->print()); 1982 1983 return snoop_delay; 1984} 1985 1986 --- 613 unchanged lines hidden --- |