gem5 v23.0.0.1
Loading...
Searching...
No Matches
base.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2013, 2018-2019 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
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2003-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
40
46#include "mem/cache/base.hh"
47
48#include "base/compiler.hh"
49#include "base/logging.hh"
50#include "debug/Cache.hh"
51#include "debug/CacheComp.hh"
52#include "debug/CachePort.hh"
53#include "debug/CacheRepl.hh"
54#include "debug/CacheVerbose.hh"
55#include "debug/HWPrefetch.hh"
57#include "mem/cache/mshr.hh"
62#include "params/BaseCache.hh"
63#include "params/WriteAllocator.hh"
64#include "sim/cur_tick.hh"
65
66namespace gem5
67{
68
70 BaseCache& _cache,
71 const std::string &_label)
72 : QueuedResponsePort(_name, queue),
73 cache{_cache},
74 queue(_cache, *this, true, _label),
75 blocked(false), mustSendRetry(false),
76 sendRetryEvent([this]{ processSendRetry(); }, _name)
77{
78}
79
80BaseCache::BaseCache(const BaseCacheParams &p, unsigned blk_size)
82 cpuSidePort (p.name + ".cpu_side_port", *this, "CpuSidePort"),
83 memSidePort(p.name + ".mem_side_port", this, "MemSidePort"),
84 mshrQueue("MSHRs", p.mshrs, 0, p.demand_mshr_reserve, p.name),
85 writeBuffer("write buffer", p.write_buffers, p.mshrs, p.name),
86 tags(p.tags),
89 writeAllocator(p.write_allocator),
90 writebackClean(p.writeback_clean),
91 tempBlockWriteback(nullptr),
93 name(), false,
95 blkSize(blk_size),
96 lookupLatency(p.tag_latency),
97 dataLatency(p.data_latency),
98 forwardLatency(p.tag_latency),
99 fillLatency(p.data_latency),
100 responseLatency(p.response_latency),
101 sequentialAccess(p.sequential_access),
102 numTarget(p.tgts_per_mshr),
103 forwardSnoops(true),
104 clusivity(p.clusivity),
105 isReadOnly(p.is_read_only),
106 replaceExpansions(p.replace_expansions),
107 moveContractions(p.move_contractions),
108 blocked(0),
109 order(0),
110 noTargetMSHR(nullptr),
111 missCount(p.max_miss_count),
112 addrRanges(p.addr_ranges.begin(), p.addr_ranges.end()),
113 system(p.system),
114 stats(*this)
115{
116 // the MSHR queue has no reserve entries as we check the MSHR
117 // queue on every single allocation, whereas the write queue has
118 // as many reserve entries as we have MSHRs, since every MSHR may
119 // eventually require a writeback, and we do not check the write
120 // buffer before committing to an MSHR
121
122 // forward snoops is overridden in init() once we can query
123 // whether the connected requestor is actually snooping or not
124
125 tempBlock = new TempCacheBlk(blkSize);
126
127 tags->tagsInit();
128 if (prefetcher)
129 prefetcher->setCache(this);
130
131 fatal_if(compressor && !dynamic_cast<CompressedTags*>(tags),
132 "The tags of compressed cache %s must derive from CompressedTags",
133 name());
134 warn_if(!compressor && dynamic_cast<CompressedTags*>(tags),
135 "Compressed cache %s does not have a compression algorithm", name());
136 if (compressor)
137 compressor->setCache(this);
138}
139
141{
142 delete tempBlock;
143}
144
145void
147{
148 assert(!blocked);
149 DPRINTF(CachePort, "Port is blocking new requests\n");
150 blocked = true;
151 // if we already scheduled a retry in this cycle, but it has not yet
152 // happened, cancel it
155 DPRINTF(CachePort, "Port descheduled retry\n");
156 mustSendRetry = true;
157 }
158}
159
160void
162{
163 assert(blocked);
164 DPRINTF(CachePort, "Port is accepting new requests\n");
165 blocked = false;
166 if (mustSendRetry) {
167 // @TODO: need to find a better time (next cycle?)
168 cache.schedule(sendRetryEvent, curTick() + 1);
169 }
170}
171
172void
174{
175 DPRINTF(CachePort, "Port is sending retry\n");
176
177 // reset the flag and call retry
178 mustSendRetry = false;
179 sendRetryReq();
180}
181
182Addr
184{
185 if (blk != tempBlock) {
186 return tags->regenerateBlkAddr(blk);
187 } else {
188 return tempBlock->getAddr();
189 }
190}
191
192void
194{
196 fatal("Cache ports on %s are not connected\n", name());
199}
200
201Port &
202BaseCache::getPort(const std::string &if_name, PortID idx)
203{
204 if (if_name == "mem_side") {
205 return memSidePort;
206 } else if (if_name == "cpu_side") {
207 return cpuSidePort;
208 } else {
209 return ClockedObject::getPort(if_name, idx);
210 }
211}
212
213bool
215{
216 for (const auto& r : addrRanges) {
217 if (r.contains(addr)) {
218 return true;
219 }
220 }
221 return false;
222}
223
224void
226{
227
228 // handle special cases for LockedRMW transactions
229 if (pkt->isLockedRMW()) {
230 Addr blk_addr = pkt->getBlockAddr(blkSize);
231
232 if (pkt->isRead()) {
233 // Read hit for LockedRMW. Since it requires exclusive
234 // permissions, there should be no outstanding access.
235 assert(!mshrQueue.findMatch(blk_addr, pkt->isSecure()));
236 // The keys to LockedRMW are that (1) we always have an MSHR
237 // allocated during the RMW interval to catch snoops and
238 // defer them until after the RMW completes, and (2) we
239 // clear permissions on the block to turn any upstream
240 // access other than the matching write into a miss, causing
241 // it to append to the MSHR as well.
242
243 // Because we hit in the cache, we have to fake an MSHR to
244 // achieve part (1). If the read had missed, this MSHR
245 // would get allocated as part of normal miss processing.
246 // Basically we need to get the MSHR in the same state as if
247 // we had missed and just received the response.
248 // Request *req2 = new Request(*(pkt->req));
249 RequestPtr req2 = std::make_shared<Request>(*(pkt->req));
250 PacketPtr pkt2 = new Packet(req2, pkt->cmd);
251 MSHR *mshr = allocateMissBuffer(pkt2, curTick(), true);
252 // Mark the MSHR "in service" (even though it's not) to prevent
253 // the cache from sending out a request.
254 mshrQueue.markInService(mshr, false);
255 // Part (2): mark block inaccessible
256 assert(blk);
259 } else {
260 assert(pkt->isWrite());
261 // All LockedRMW writes come here, as they cannot miss.
262 // Need to undo the two things described above. Block
263 // permissions were already restored earlier in this
264 // function, prior to the access() call. Now we just need
265 // to clear out the MSHR.
266
267 // Read should have already allocated MSHR.
268 MSHR *mshr = mshrQueue.findMatch(blk_addr, pkt->isSecure());
269 assert(mshr);
270 // Fake up a packet and "respond" to the still-pending
271 // LockedRMWRead, to process any pending targets and clear
272 // out the MSHR
273 PacketPtr resp_pkt =
275 resp_pkt->senderState = mshr;
276 recvTimingResp(resp_pkt);
277 }
278 }
279
280 if (pkt->needsResponse()) {
281 // These delays should have been consumed by now
282 assert(pkt->headerDelay == 0);
283 assert(pkt->payloadDelay == 0);
284
285 pkt->makeTimingResponse();
286
287 // In this case we are considering request_time that takes
288 // into account the delay of the xbar, if any, and just
289 // lat, neglecting responseLatency, modelling hit latency
290 // just as the value of lat overriden by access(), which calls
291 // the calculateAccessLatency() function.
292 cpuSidePort.schedTimingResp(pkt, request_time);
293 } else {
294 DPRINTF(Cache, "%s satisfied %s, no response needed\n", __func__,
295 pkt->print());
296
297 // queue the packet for deletion, as the sending cache is
298 // still relying on it; if the block is found in access(),
299 // CleanEvict and Writeback messages will be deleted
300 // here as well
301 pendingDelete.reset(pkt);
302 }
303}
304
305void
307 Tick forward_time, Tick request_time)
308{
309 if (writeAllocator &&
310 pkt && pkt->isWrite() && !pkt->req->isUncacheable()) {
312 pkt->getBlockAddr(blkSize));
313 }
314
315 if (mshr) {
319
320 //@todo remove hw_pf here
321
322 // Coalesce unless it was a software prefetch (see above).
323 if (pkt) {
324 assert(!pkt->isWriteback());
325 // CleanEvicts corresponding to blocks which have
326 // outstanding requests in MSHRs are simply sunk here
327 if (pkt->cmd == MemCmd::CleanEvict) {
328 pendingDelete.reset(pkt);
329 } else if (pkt->cmd == MemCmd::WriteClean) {
330 // A WriteClean should never coalesce with any
331 // outstanding cache maintenance requests.
332
333 // We use forward_time here because there is an
334 // uncached memory write, forwarded to WriteBuffer.
335 allocateWriteBuffer(pkt, forward_time);
336 } else {
337 DPRINTF(Cache, "%s coalescing MSHR for %s\n", __func__,
338 pkt->print());
339
340 assert(pkt->req->requestorId() < system->maxRequestors());
341 stats.cmdStats(pkt).mshrHits[pkt->req->requestorId()]++;
342
343 // We use forward_time here because it is the same
344 // considering new targets. We have multiple
345 // requests for the same address here. It
346 // specifies the latency to allocate an internal
347 // buffer and to schedule an event to the queued
348 // port and also takes into account the additional
349 // delay of the xbar.
350 mshr->allocateTarget(pkt, forward_time, order++,
351 allocOnFill(pkt->cmd));
352 if (mshr->getNumTargets() >= numTarget) {
353 noTargetMSHR = mshr;
355 // need to be careful with this... if this mshr isn't
356 // ready yet (i.e. time > curTick()), we don't want to
357 // move it ahead of mshrs that are ready
358 // mshrQueue.moveToFront(mshr);
359 }
360 }
361 }
362 } else {
363 // no MSHR
364 assert(pkt->req->requestorId() < system->maxRequestors());
365 stats.cmdStats(pkt).mshrMisses[pkt->req->requestorId()]++;
366 if (prefetcher && pkt->isDemand())
368
369 if (pkt->isEviction() || pkt->cmd == MemCmd::WriteClean) {
370 // We use forward_time here because there is an
371 // writeback or writeclean, forwarded to WriteBuffer.
372 allocateWriteBuffer(pkt, forward_time);
373 } else {
374 if (blk && blk->isValid()) {
375 // If we have a write miss to a valid block, we
376 // need to mark the block non-readable. Otherwise
377 // if we allow reads while there's an outstanding
378 // write miss, the read could return stale data
379 // out of the cache block... a more aggressive
380 // system could detect the overlap (if any) and
381 // forward data out of the MSHRs, but we don't do
382 // that yet. Note that we do need to leave the
383 // block valid so that it stays in the cache, in
384 // case we get an upgrade response (and hence no
385 // new data) when the write miss completes.
386 // As long as CPUs do proper store/load forwarding
387 // internally, and have a sufficiently weak memory
388 // model, this is probably unnecessary, but at some
389 // point it must have seemed like we needed it...
390 assert((pkt->needsWritable() &&
392 pkt->req->isCacheMaintenance());
394 }
395 // Here we are using forward_time, modelling the latency of
396 // a miss (outbound) just as forwardLatency, neglecting the
397 // lookupLatency component.
398 allocateMissBuffer(pkt, forward_time);
399 }
400 }
401}
402
403void
405{
406 // anything that is merely forwarded pays for the forward latency and
407 // the delay provided by the crossbar
408 Tick forward_time = clockEdge(forwardLatency) + pkt->headerDelay;
409
410 if (pkt->cmd == MemCmd::LockedRMWWriteReq) {
411 // For LockedRMW accesses, we mark the block inaccessible after the
412 // read (see below), to make sure no one gets in before the write.
413 // Now that the write is here, mark it accessible again, so the
414 // write will succeed. LockedRMWReadReq brings the block in in
415 // exclusive mode, so we know it was previously writable.
416 CacheBlk *blk = tags->findBlock(pkt->getAddr(), pkt->isSecure());
417 assert(blk && blk->isValid());
418 assert(!blk->isSet(CacheBlk::WritableBit) &&
422 }
423
424 Cycles lat;
425 CacheBlk *blk = nullptr;
426 bool satisfied = false;
427 {
428 PacketList writebacks;
429 // Note that lat is passed by reference here. The function
430 // access() will set the lat value.
431 satisfied = access(pkt, blk, lat, writebacks);
432
433 // After the evicted blocks are selected, they must be forwarded
434 // to the write buffer to ensure they logically precede anything
435 // happening below
436 doWritebacks(writebacks, clockEdge(lat + forwardLatency));
437 }
438
439 // Here we charge the headerDelay that takes into account the latencies
440 // of the bus, if the packet comes from it.
441 // The latency charged is just the value set by the access() function.
442 // In case of a hit we are neglecting response latency.
443 // In case of a miss we are neglecting forward latency.
444 Tick request_time = clockEdge(lat);
445 // Here we reset the timing of the packet.
446 pkt->headerDelay = pkt->payloadDelay = 0;
447
448 if (satisfied) {
449 // notify before anything else as later handleTimingReqHit might turn
450 // the packet in a response
451 ppHit->notify(pkt);
452
453 if (prefetcher && blk && blk->wasPrefetched()) {
454 DPRINTF(Cache, "Hit on prefetch for addr %#x (%s)\n",
455 pkt->getAddr(), pkt->isSecure() ? "s" : "ns");
456 blk->clearPrefetched();
457 }
458
459 handleTimingReqHit(pkt, blk, request_time);
460 } else {
461 handleTimingReqMiss(pkt, blk, forward_time, request_time);
462
463 ppMiss->notify(pkt);
464 }
465
466 if (prefetcher) {
467 // track time of availability of next prefetch, if any
468 Tick next_pf_time = std::max(
470 if (next_pf_time != MaxTick) {
471 schedMemSideSendEvent(next_pf_time);
472 }
473 }
474}
475
476void
478{
479 Tick completion_time = clockEdge(responseLatency) +
480 pkt->headerDelay + pkt->payloadDelay;
481
482 // Reset the bus additional time as it is now accounted for
483 pkt->headerDelay = pkt->payloadDelay = 0;
484
485 cpuSidePort.schedTimingResp(pkt, completion_time);
486}
487
488void
490{
491 assert(pkt->isResponse());
492
493 // all header delay should be paid for by the crossbar, unless
494 // this is a prefetch response from above
495 panic_if(pkt->headerDelay != 0 && pkt->cmd != MemCmd::HardPFResp,
496 "%s saw a non-zero packet delay\n", name());
497
498 const bool is_error = pkt->isError();
499
500 if (is_error) {
501 DPRINTF(Cache, "%s: Cache received %s with error\n", __func__,
502 pkt->print());
503 }
504
505 DPRINTF(Cache, "%s: Handling response %s\n", __func__,
506 pkt->print());
507
508 // if this is a write, we should be looking at an uncacheable
509 // write
510 if (pkt->isWrite() && pkt->cmd != MemCmd::LockedRMWWriteResp) {
511 assert(pkt->req->isUncacheable());
513 return;
514 }
515
516 // we have dealt with any (uncacheable) writes above, from here on
517 // we know we are dealing with an MSHR due to a miss or a prefetch
518 MSHR *mshr = dynamic_cast<MSHR*>(pkt->popSenderState());
519 assert(mshr);
520
521 if (mshr == noTargetMSHR) {
522 // we always clear at least one target
524 noTargetMSHR = nullptr;
525 }
526
527 // Initial target is used just for stats
528 const QueueEntry::Target *initial_tgt = mshr->getTarget();
529 const Tick miss_latency = curTick() - initial_tgt->recvTime;
530 if (pkt->req->isUncacheable()) {
531 assert(pkt->req->requestorId() < system->maxRequestors());
532 stats.cmdStats(initial_tgt->pkt)
533 .mshrUncacheableLatency[pkt->req->requestorId()] += miss_latency;
534 } else {
535 assert(pkt->req->requestorId() < system->maxRequestors());
536 stats.cmdStats(initial_tgt->pkt)
537 .mshrMissLatency[pkt->req->requestorId()] += miss_latency;
538 }
539
540 PacketList writebacks;
541
542 bool is_fill = !mshr->isForward &&
543 (pkt->isRead() || pkt->cmd == MemCmd::UpgradeResp ||
544 mshr->wasWholeLineWrite);
545
546 // make sure that if the mshr was due to a whole line write then
547 // the response is an invalidation
548 assert(!mshr->wasWholeLineWrite || pkt->isInvalidate());
549
550 CacheBlk *blk = tags->findBlock(pkt->getAddr(), pkt->isSecure());
551
552 if (is_fill && !is_error) {
553 DPRINTF(Cache, "Block for addr %#llx being updated in Cache\n",
554 pkt->getAddr());
555
556 const bool allocate = (writeAllocator && mshr->wasWholeLineWrite) ?
558 blk = handleFill(pkt, blk, writebacks, allocate);
559 assert(blk != nullptr);
560 ppFill->notify(pkt);
561 }
562
563 // Don't want to promote the Locked RMW Read until
564 // the locked write comes in
565 if (!mshr->hasLockedRMWReadTarget()) {
566 if (blk && blk->isValid() && pkt->isClean() && !pkt->isInvalidate()) {
567 // The block was marked not readable while there was a pending
568 // cache maintenance operation, restore its flag.
570
571 // This was a cache clean operation (without invalidate)
572 // and we have a copy of the block already. Since there
573 // is no invalidation, we can promote targets that don't
574 // require a writable copy
575 mshr->promoteReadable();
576 }
577
578 if (blk && blk->isSet(CacheBlk::WritableBit) &&
579 !pkt->req->isCacheInvalidate()) {
580 // If at this point the referenced block is writable and the
581 // response is not a cache invalidate, we promote targets that
582 // were deferred as we couldn't guarrantee a writable copy
583 mshr->promoteWritable();
584 }
585 }
586
587 serviceMSHRTargets(mshr, pkt, blk);
588 // We are stopping servicing targets early for the Locked RMW Read until
589 // the write comes.
590 if (!mshr->hasLockedRMWReadTarget()) {
591 if (mshr->promoteDeferredTargets()) {
592 // avoid later read getting stale data while write miss is
593 // outstanding.. see comment in timingAccess()
594 if (blk) {
596 }
599 } else {
600 // while we deallocate an mshr from the queue we still have to
601 // check the isFull condition before and after as we might
602 // have been using the reserved entries already
603 const bool was_full = mshrQueue.isFull();
604 mshrQueue.deallocate(mshr);
605 if (was_full && !mshrQueue.isFull()) {
607 }
608
609 // Request the bus for a prefetch if this deallocation freed enough
610 // MSHRs for a prefetch to take place
611 if (prefetcher && mshrQueue.canPrefetch() && !isBlocked()) {
612 Tick next_pf_time = std::max(
614 if (next_pf_time != MaxTick)
615 schedMemSideSendEvent(next_pf_time);
616 }
617 }
618
619 // if we used temp block, check to see if its valid and then clear it
620 if (blk == tempBlock && tempBlock->isValid()) {
621 evictBlock(blk, writebacks);
622 }
623 }
624
625 const Tick forward_time = clockEdge(forwardLatency) + pkt->headerDelay;
626 // copy writebacks to write buffer
627 doWritebacks(writebacks, forward_time);
628
629 DPRINTF(CacheVerbose, "%s: Leaving with %s\n", __func__, pkt->print());
630 delete pkt;
631}
632
633
634Tick
636{
637 // should assert here that there are no outstanding MSHRs or
638 // writebacks... that would mean that someone used an atomic
639 // access in timing mode
640
641 // We use lookupLatency here because it is used to specify the latency
642 // to access.
643 Cycles lat = lookupLatency;
644
645 CacheBlk *blk = nullptr;
646 PacketList writebacks;
647 bool satisfied = access(pkt, blk, lat, writebacks);
648
649 if (pkt->isClean() && blk && blk->isSet(CacheBlk::DirtyBit)) {
650 // A cache clean opearation is looking for a dirty
651 // block. If a dirty block is encountered a WriteClean
652 // will update any copies to the path to the memory
653 // until the point of reference.
654 DPRINTF(CacheVerbose, "%s: packet %s found block: %s\n",
655 __func__, pkt->print(), blk->print());
656 PacketPtr wb_pkt = writecleanBlk(blk, pkt->req->getDest(), pkt->id);
657 writebacks.push_back(wb_pkt);
658 pkt->setSatisfied();
659 }
660
661 // handle writebacks resulting from the access here to ensure they
662 // logically precede anything happening below
663 doWritebacksAtomic(writebacks);
664 assert(writebacks.empty());
665
666 if (!satisfied) {
667 lat += handleAtomicReqMiss(pkt, blk, writebacks);
668 }
669
670 // Note that we don't invoke the prefetcher at all in atomic mode.
671 // It's not clear how to do it properly, particularly for
672 // prefetchers that aggressively generate prefetch candidates and
673 // rely on bandwidth contention to throttle them; these will tend
674 // to pollute the cache in atomic mode since there is no bandwidth
675 // contention. If we ever do want to enable prefetching in atomic
676 // mode, though, this is the place to do it... see timingAccess()
677 // for an example (though we'd want to issue the prefetch(es)
678 // immediately rather than calling requestMemSideBus() as we do
679 // there).
680
681 // do any writebacks resulting from the response handling
682 doWritebacksAtomic(writebacks);
683
684 // if we used temp block, check to see if its valid and if so
685 // clear it out, but only do so after the call to recvAtomic is
686 // finished so that any downstream observers (such as a snoop
687 // filter), first see the fill, and only then see the eviction
688 if (blk == tempBlock && tempBlock->isValid()) {
689 // the atomic CPU calls recvAtomic for fetch and load/store
690 // sequentuially, and we may already have a tempBlock
691 // writeback from the fetch that we have not yet sent
692 if (tempBlockWriteback) {
693 // if that is the case, write the prevoius one back, and
694 // do not schedule any new event
696 } else {
697 // the writeback/clean eviction happens after the call to
698 // recvAtomic has finished (but before any successive
699 // calls), so that the response handling from the fill is
700 // allowed to happen first
702 }
703
705 }
706
707 if (pkt->needsResponse()) {
708 pkt->makeAtomicResponse();
709 }
710
711 return lat * clockPeriod();
712}
713
714void
716{
717 Addr blk_addr = pkt->getBlockAddr(blkSize);
718 bool is_secure = pkt->isSecure();
719 CacheBlk *blk = tags->findBlock(pkt->getAddr(), is_secure);
720 MSHR *mshr = mshrQueue.findMatch(blk_addr, is_secure);
721
722 pkt->pushLabel(name());
723
724 CacheBlkPrintWrapper cbpw(blk);
725
726 // Note that just because an L2/L3 has valid data doesn't mean an
727 // L1 doesn't have a more up-to-date modified copy that still
728 // needs to be found. As a result we always update the request if
729 // we have it, but only declare it satisfied if we are the owner.
730
731 // see if we have data at all (owned or otherwise)
732 bool have_data = blk && blk->isValid()
733 && pkt->trySatisfyFunctional(&cbpw, blk_addr, is_secure, blkSize,
734 blk->data);
735
736 // data we have is dirty if marked as such or if we have an
737 // in-service MSHR that is pending a modified line
738 bool have_dirty =
739 have_data && (blk->isSet(CacheBlk::DirtyBit) ||
740 (mshr && mshr->inService && mshr->isPendingModified()));
741
742 bool done = have_dirty ||
747
748 DPRINTF(CacheVerbose, "%s: %s %s%s%s\n", __func__, pkt->print(),
749 (blk && blk->isValid()) ? "valid " : "",
750 have_data ? "data " : "", done ? "done " : "");
751
752 // We're leaving the cache, so pop cache->name() label
753 pkt->popLabel();
754
755 if (done) {
756 pkt->makeResponse();
757 } else {
758 // if it came as a request from the CPU side then make sure it
759 // continues towards the memory side
760 if (from_cpu_side) {
762 } else if (cpuSidePort.isSnooping()) {
763 // if it came from the memory side, it must be a snoop request
764 // and we should only forward it if we are forwarding snoops
766 }
767 }
768}
769
770void
772 bool has_old_data)
773{
774 DataUpdate data_update(regenerateBlkAddr(blk), blk->isSecure());
775 if (ppDataUpdate->hasListeners()) {
776 if (has_old_data) {
777 data_update.oldData = std::vector<uint64_t>(blk->data,
778 blk->data + (blkSize / sizeof(uint64_t)));
779 }
780 }
781
782 // Actually perform the data update
783 if (cpkt) {
784 cpkt->writeDataToBlock(blk->data, blkSize);
785 }
786
787 if (ppDataUpdate->hasListeners()) {
788 if (cpkt) {
789 data_update.newData = std::vector<uint64_t>(blk->data,
790 blk->data + (blkSize / sizeof(uint64_t)));
791 }
792 ppDataUpdate->notify(data_update);
793 }
794}
795
796void
798{
799 assert(pkt->isRequest());
800
801 uint64_t overwrite_val;
802 bool overwrite_mem;
803 uint64_t condition_val64;
804 uint32_t condition_val32;
805
806 int offset = pkt->getOffset(blkSize);
807 uint8_t *blk_data = blk->data + offset;
808
809 assert(sizeof(uint64_t) >= pkt->getSize());
810
811 // Get a copy of the old block's contents for the probe before the update
812 DataUpdate data_update(regenerateBlkAddr(blk), blk->isSecure());
813 if (ppDataUpdate->hasListeners()) {
814 data_update.oldData = std::vector<uint64_t>(blk->data,
815 blk->data + (blkSize / sizeof(uint64_t)));
816 }
817
818 overwrite_mem = true;
819 // keep a copy of our possible write value, and copy what is at the
820 // memory address into the packet
821 pkt->writeData((uint8_t *)&overwrite_val);
822 pkt->setData(blk_data);
823
824 if (pkt->req->isCondSwap()) {
825 if (pkt->getSize() == sizeof(uint64_t)) {
826 condition_val64 = pkt->req->getExtraData();
827 overwrite_mem = !std::memcmp(&condition_val64, blk_data,
828 sizeof(uint64_t));
829 } else if (pkt->getSize() == sizeof(uint32_t)) {
830 condition_val32 = (uint32_t)pkt->req->getExtraData();
831 overwrite_mem = !std::memcmp(&condition_val32, blk_data,
832 sizeof(uint32_t));
833 } else
834 panic("Invalid size for conditional read/write\n");
835 }
836
837 if (overwrite_mem) {
838 std::memcpy(blk_data, &overwrite_val, pkt->getSize());
840
841 if (ppDataUpdate->hasListeners()) {
842 data_update.newData = std::vector<uint64_t>(blk->data,
843 blk->data + (blkSize / sizeof(uint64_t)));
844 ppDataUpdate->notify(data_update);
845 }
846 }
847}
848
851{
852 // Check both MSHR queue and write buffer for potential requests,
853 // note that null does not mean there is no request, it could
854 // simply be that it is not ready
855 MSHR *miss_mshr = mshrQueue.getNext();
856 WriteQueueEntry *wq_entry = writeBuffer.getNext();
857
858 // If we got a write buffer request ready, first priority is a
859 // full write buffer, otherwise we favour the miss requests
860 if (wq_entry && (writeBuffer.isFull() || !miss_mshr)) {
861 // need to search MSHR queue for conflicting earlier miss.
862 MSHR *conflict_mshr = mshrQueue.findPending(wq_entry);
863
864 if (conflict_mshr && conflict_mshr->order < wq_entry->order) {
865 // Service misses in order until conflict is cleared.
866 return conflict_mshr;
867
868 // @todo Note that we ignore the ready time of the conflict here
869 }
870
871 // No conflicts; issue write
872 return wq_entry;
873 } else if (miss_mshr) {
874 // need to check for conflicting earlier writeback
875 WriteQueueEntry *conflict_mshr = writeBuffer.findPending(miss_mshr);
876 if (conflict_mshr) {
877 // not sure why we don't check order here... it was in the
878 // original code but commented out.
879
880 // The only way this happens is if we are
881 // doing a write and we didn't have permissions
882 // then subsequently saw a writeback (owned got evicted)
883 // We need to make sure to perform the writeback first
884 // To preserve the dirty data, then we can issue the write
885
886 // should we return wq_entry here instead? I.e. do we
887 // have to flush writes in order? I don't think so... not
888 // for Alpha anyway. Maybe for x86?
889 return conflict_mshr;
890
891 // @todo Note that we ignore the ready time of the conflict here
892 }
893
894 // No conflicts; issue read
895 return miss_mshr;
896 }
897
898 // fall through... no pending requests. Try a prefetch.
899 assert(!miss_mshr && !wq_entry);
900 if (prefetcher && mshrQueue.canPrefetch() && !isBlocked()) {
901 // If we have a miss queue slot, we can try a prefetch
903 if (pkt) {
904 Addr pf_addr = pkt->getBlockAddr(blkSize);
905 if (tags->findBlock(pf_addr, pkt->isSecure())) {
906 DPRINTF(HWPrefetch, "Prefetch %#x has hit in cache, "
907 "dropped.\n", pf_addr);
909 // free the request and packet
910 delete pkt;
911 } else if (mshrQueue.findMatch(pf_addr, pkt->isSecure())) {
912 DPRINTF(HWPrefetch, "Prefetch %#x has hit in a MSHR, "
913 "dropped.\n", pf_addr);
915 // free the request and packet
916 delete pkt;
917 } else if (writeBuffer.findMatch(pf_addr, pkt->isSecure())) {
918 DPRINTF(HWPrefetch, "Prefetch %#x has hit in the "
919 "Write Buffer, dropped.\n", pf_addr);
921 // free the request and packet
922 delete pkt;
923 } else {
924 // Update statistic on number of prefetches issued
925 // (hwpf_mshr_misses)
926 assert(pkt->req->requestorId() < system->maxRequestors());
927 stats.cmdStats(pkt).mshrMisses[pkt->req->requestorId()]++;
928
929 // allocate an MSHR and return it, note
930 // that we send the packet straight away, so do not
931 // schedule the send
932 return allocateMissBuffer(pkt, curTick(), false);
933 }
934 }
935 }
936
937 return nullptr;
938}
939
940bool
942 PacketList &writebacks)
943{
944 bool replacement = false;
945 for (const auto& blk : evict_blks) {
946 if (blk->isValid()) {
947 replacement = true;
948
949 const MSHR* mshr =
950 mshrQueue.findMatch(regenerateBlkAddr(blk), blk->isSecure());
951 if (mshr) {
952 // Must be an outstanding upgrade or clean request on a block
953 // we're about to replace
954 assert((!blk->isSet(CacheBlk::WritableBit) &&
955 mshr->needsWritable()) || mshr->isCleaning());
956 return false;
957 }
958 }
959 }
960
961 // The victim will be replaced by a new entry, so increase the replacement
962 // counter if a valid block is being replaced
963 if (replacement) {
965
966 // Evict valid blocks associated to this victim block
967 for (auto& blk : evict_blks) {
968 if (blk->isValid()) {
969 evictBlock(blk, writebacks);
970 }
971 }
972 }
973
974 return true;
975}
976
977bool
979 PacketList &writebacks)
980{
981 // tempBlock does not exist in the tags, so don't do anything for it.
982 if (blk == tempBlock) {
983 return true;
984 }
985
986 // The compressor is called to compress the updated data, so that its
987 // metadata can be updated.
988 Cycles compression_lat = Cycles(0);
989 Cycles decompression_lat = Cycles(0);
990 const auto comp_data =
991 compressor->compress(data, compression_lat, decompression_lat);
992 std::size_t compression_size = comp_data->getSizeBits();
993
994 // Get previous compressed size
995 CompressionBlk* compression_blk = static_cast<CompressionBlk*>(blk);
996 [[maybe_unused]] const std::size_t prev_size =
997 compression_blk->getSizeBits();
998
999 // If compressed size didn't change enough to modify its co-allocatability
1000 // there is nothing to do. Otherwise we may be facing a data expansion
1001 // (block passing from more compressed to less compressed state), or a
1002 // data contraction (less to more).
1003 bool is_data_expansion = false;
1004 bool is_data_contraction = false;
1005 const CompressionBlk::OverwriteType overwrite_type =
1006 compression_blk->checkExpansionContraction(compression_size);
1007 std::string op_name = "";
1008 if (overwrite_type == CompressionBlk::DATA_EXPANSION) {
1009 op_name = "expansion";
1010 is_data_expansion = true;
1011 } else if ((overwrite_type == CompressionBlk::DATA_CONTRACTION) &&
1013 op_name = "contraction";
1014 is_data_contraction = true;
1015 }
1016
1017 // If block changed compression state, it was possibly co-allocated with
1018 // other blocks and cannot be co-allocated anymore, so one or more blocks
1019 // must be evicted to make room for the expanded/contracted block
1020 std::vector<CacheBlk*> evict_blks;
1021 if (is_data_expansion || is_data_contraction) {
1022 std::vector<CacheBlk*> evict_blks;
1023 bool victim_itself = false;
1024 CacheBlk *victim = nullptr;
1025 if (replaceExpansions || is_data_contraction) {
1026 victim = tags->findVictim(regenerateBlkAddr(blk),
1027 blk->isSecure(), compression_size, evict_blks);
1028
1029 // It is valid to return nullptr if there is no victim
1030 if (!victim) {
1031 return false;
1032 }
1033
1034 // If the victim block is itself the block won't need to be moved,
1035 // and the victim should not be evicted
1036 if (blk == victim) {
1037 victim_itself = true;
1038 auto it = std::find_if(evict_blks.begin(), evict_blks.end(),
1039 [&blk](CacheBlk* evict_blk){ return evict_blk == blk; });
1040 evict_blks.erase(it);
1041 }
1042
1043 // Print victim block's information
1044 DPRINTF(CacheRepl, "Data %s replacement victim: %s\n",
1045 op_name, victim->print());
1046 } else {
1047 // If we do not move the expanded block, we must make room for
1048 // the expansion to happen, so evict every co-allocated block
1049 const SuperBlk* superblock = static_cast<const SuperBlk*>(
1050 compression_blk->getSectorBlock());
1051 for (auto& sub_blk : superblock->blks) {
1052 if (sub_blk->isValid() && (blk != sub_blk)) {
1053 evict_blks.push_back(sub_blk);
1054 }
1055 }
1056 }
1057
1058 // Try to evict blocks; if it fails, give up on update
1059 if (!handleEvictions(evict_blks, writebacks)) {
1060 return false;
1061 }
1062
1063 DPRINTF(CacheComp, "Data %s: [%s] from %d to %d bits\n",
1064 op_name, blk->print(), prev_size, compression_size);
1065
1066 if (!victim_itself && (replaceExpansions || is_data_contraction)) {
1067 // Move the block's contents to the invalid block so that it now
1068 // co-allocates with the other existing superblock entry
1069 tags->moveBlock(blk, victim);
1070 blk = victim;
1071 compression_blk = static_cast<CompressionBlk*>(blk);
1072 }
1073 }
1074
1075 // Update the number of data expansions/contractions
1076 if (is_data_expansion) {
1078 } else if (is_data_contraction) {
1080 }
1081
1082 compression_blk->setSizeBits(compression_size);
1083 compression_blk->setDecompressionLatency(decompression_lat);
1084
1085 return true;
1086}
1087
1088void
1090{
1091 assert(pkt->isRequest());
1092
1093 assert(blk && blk->isValid());
1094 // Occasionally this is not true... if we are a lower-level cache
1095 // satisfying a string of Read and ReadEx requests from
1096 // upper-level caches, a Read will mark the block as shared but we
1097 // can satisfy a following ReadEx anyway since we can rely on the
1098 // Read requestor(s) to have buffered the ReadEx snoop and to
1099 // invalidate their blocks after receiving them.
1100 // assert(!pkt->needsWritable() || blk->isSet(CacheBlk::WritableBit));
1101 assert(pkt->getOffset(blkSize) + pkt->getSize() <= blkSize);
1102
1103 // Check RMW operations first since both isRead() and
1104 // isWrite() will be true for them
1105 if (pkt->cmd == MemCmd::SwapReq) {
1106 if (pkt->isAtomicOp()) {
1107 // Get a copy of the old block's contents for the probe before
1108 // the update
1109 DataUpdate data_update(regenerateBlkAddr(blk), blk->isSecure());
1110 if (ppDataUpdate->hasListeners()) {
1111 data_update.oldData = std::vector<uint64_t>(blk->data,
1112 blk->data + (blkSize / sizeof(uint64_t)));
1113 }
1114
1115 // extract data from cache and save it into the data field in
1116 // the packet as a return value from this atomic op
1117 int offset = tags->extractBlkOffset(pkt->getAddr());
1118 uint8_t *blk_data = blk->data + offset;
1119 pkt->setData(blk_data);
1120
1121 // execute AMO operation
1122 (*(pkt->getAtomicOp()))(blk_data);
1123
1124 // Inform of this block's data contents update
1125 if (ppDataUpdate->hasListeners()) {
1126 data_update.newData = std::vector<uint64_t>(blk->data,
1127 blk->data + (blkSize / sizeof(uint64_t)));
1128 ppDataUpdate->notify(data_update);
1129 }
1130
1131 // set block status to dirty
1133 } else {
1134 cmpAndSwap(blk, pkt);
1135 }
1136 } else if (pkt->isWrite()) {
1137 // we have the block in a writable state and can go ahead,
1138 // note that the line may be also be considered writable in
1139 // downstream caches along the path to memory, but always
1140 // Exclusive, and never Modified
1141 assert(blk->isSet(CacheBlk::WritableBit));
1142 // Write or WriteLine at the first cache with block in writable state
1143 if (blk->checkWrite(pkt)) {
1144 updateBlockData(blk, pkt, true);
1145 }
1146 // Always mark the line as dirty (and thus transition to the
1147 // Modified state) even if we are a failed StoreCond so we
1148 // supply data to any snoops that have appended themselves to
1149 // this cache before knowing the store will fail.
1151 DPRINTF(CacheVerbose, "%s for %s (write)\n", __func__, pkt->print());
1152 } else if (pkt->isRead()) {
1153 if (pkt->isLLSC()) {
1154 blk->trackLoadLocked(pkt);
1155 }
1156
1157 // all read responses have a data payload
1158 assert(pkt->hasRespData());
1159 pkt->setDataFromBlock(blk->data, blkSize);
1160 } else if (pkt->isUpgrade()) {
1161 // sanity check
1162 assert(!pkt->hasSharers());
1163
1164 if (blk->isSet(CacheBlk::DirtyBit)) {
1165 // we were in the Owned state, and a cache above us that
1166 // has the line in Shared state needs to be made aware
1167 // that the data it already has is in fact dirty
1168 pkt->setCacheResponding();
1170 }
1171 } else if (pkt->isClean()) {
1173 } else {
1174 assert(pkt->isInvalidate());
1175 invalidateBlock(blk);
1176 DPRINTF(CacheVerbose, "%s for %s (invalidation)\n", __func__,
1177 pkt->print());
1178 }
1179}
1180
1182//
1183// Access path: requests coming in from the CPU side
1184//
1186Cycles
1188 const Cycles lookup_lat) const
1189{
1190 // A tag-only access has to wait for the packet to arrive in order to
1191 // perform the tag lookup.
1192 return ticksToCycles(delay) + lookup_lat;
1193}
1194
1195Cycles
1196BaseCache::calculateAccessLatency(const CacheBlk* blk, const uint32_t delay,
1197 const Cycles lookup_lat) const
1198{
1199 Cycles lat(0);
1200
1201 if (blk != nullptr) {
1202 // As soon as the access arrives, for sequential accesses first access
1203 // tags, then the data entry. In the case of parallel accesses the
1204 // latency is dictated by the slowest of tag and data latencies.
1205 if (sequentialAccess) {
1206 lat = ticksToCycles(delay) + lookup_lat + dataLatency;
1207 } else {
1208 lat = ticksToCycles(delay) + std::max(lookup_lat, dataLatency);
1209 }
1210
1211 // Check if the block to be accessed is available. If not, apply the
1212 // access latency on top of when the block is ready to be accessed.
1213 const Tick tick = curTick() + delay;
1214 const Tick when_ready = blk->getWhenReady();
1215 if (when_ready > tick &&
1216 ticksToCycles(when_ready - tick) > lat) {
1217 lat += ticksToCycles(when_ready - tick);
1218 }
1219 } else {
1220 // In case of a miss, we neglect the data access in a parallel
1221 // configuration (i.e., the data access will be stopped as soon as
1222 // we find out it is a miss), and use the tag-only latency.
1223 lat = calculateTagOnlyLatency(delay, lookup_lat);
1224 }
1225
1226 return lat;
1227}
1228
1229bool
1231 PacketList &writebacks)
1232{
1233 // sanity check
1234 assert(pkt->isRequest());
1235
1236 gem5_assert(!(isReadOnly && pkt->isWrite()),
1237 "Should never see a write in a read-only cache %s\n",
1238 name());
1239
1240 // Access block in the tags
1241 Cycles tag_latency(0);
1242 blk = tags->accessBlock(pkt, tag_latency);
1243
1244 DPRINTF(Cache, "%s for %s %s\n", __func__, pkt->print(),
1245 blk ? "hit " + blk->print() : "miss");
1246
1247 if (pkt->req->isCacheMaintenance()) {
1248 // A cache maintenance operation is always forwarded to the
1249 // memory below even if the block is found in dirty state.
1250
1251 // We defer any changes to the state of the block until we
1252 // create and mark as in service the mshr for the downstream
1253 // packet.
1254
1255 // Calculate access latency on top of when the packet arrives. This
1256 // takes into account the bus delay.
1257 lat = calculateTagOnlyLatency(pkt->headerDelay, tag_latency);
1258
1259 return false;
1260 }
1261
1262 if (pkt->isEviction()) {
1263 // We check for presence of block in above caches before issuing
1264 // Writeback or CleanEvict to write buffer. Therefore the only
1265 // possible cases can be of a CleanEvict packet coming from above
1266 // encountering a Writeback generated in this cache peer cache and
1267 // waiting in the write buffer. Cases of upper level peer caches
1268 // generating CleanEvict and Writeback or simply CleanEvict and
1269 // CleanEvict almost simultaneously will be caught by snoops sent out
1270 // by crossbar.
1271 WriteQueueEntry *wb_entry = writeBuffer.findMatch(pkt->getAddr(),
1272 pkt->isSecure());
1273 if (wb_entry) {
1274 assert(wb_entry->getNumTargets() == 1);
1275 PacketPtr wbPkt = wb_entry->getTarget()->pkt;
1276 assert(wbPkt->isWriteback());
1277
1278 if (pkt->isCleanEviction()) {
1279 // The CleanEvict and WritebackClean snoops into other
1280 // peer caches of the same level while traversing the
1281 // crossbar. If a copy of the block is found, the
1282 // packet is deleted in the crossbar. Hence, none of
1283 // the other upper level caches connected to this
1284 // cache have the block, so we can clear the
1285 // BLOCK_CACHED flag in the Writeback if set and
1286 // discard the CleanEvict by returning true.
1287 wbPkt->clearBlockCached();
1288
1289 // A clean evict does not need to access the data array
1290 lat = calculateTagOnlyLatency(pkt->headerDelay, tag_latency);
1291
1292 return true;
1293 } else {
1294 assert(pkt->cmd == MemCmd::WritebackDirty);
1295 // Dirty writeback from above trumps our clean
1296 // writeback... discard here
1297 // Note: markInService will remove entry from writeback buffer.
1298 markInService(wb_entry);
1299 delete wbPkt;
1300 }
1301 }
1302 }
1303
1304 // The critical latency part of a write depends only on the tag access
1305 if (pkt->isWrite()) {
1306 lat = calculateTagOnlyLatency(pkt->headerDelay, tag_latency);
1307 }
1308
1309 // Writeback handling is special case. We can write the block into
1310 // the cache without having a writeable copy (or any copy at all).
1311 if (pkt->isWriteback()) {
1312 assert(blkSize == pkt->getSize());
1313
1314 // we could get a clean writeback while we are having
1315 // outstanding accesses to a block, do the simple thing for
1316 // now and drop the clean writeback so that we do not upset
1317 // any ordering/decisions about ownership already taken
1318 if (pkt->cmd == MemCmd::WritebackClean &&
1319 mshrQueue.findMatch(pkt->getAddr(), pkt->isSecure())) {
1320 DPRINTF(Cache, "Clean writeback %#llx to block with MSHR, "
1321 "dropping\n", pkt->getAddr());
1322
1323 // A writeback searches for the block, then writes the data.
1324 // As the writeback is being dropped, the data is not touched,
1325 // and we just had to wait for the time to find a match in the
1326 // MSHR. As of now assume a mshr queue search takes as long as
1327 // a tag lookup for simplicity.
1328 return true;
1329 }
1330
1331 const bool has_old_data = blk && blk->isValid();
1332 if (!blk) {
1333 // need to do a replacement
1334 blk = allocateBlock(pkt, writebacks);
1335 if (!blk) {
1336 // no replaceable block available: give up, fwd to next level.
1337 incMissCount(pkt);
1338 return false;
1339 }
1340
1342 } else if (compressor) {
1343 // This is an overwrite to an existing block, therefore we need
1344 // to check for data expansion (i.e., block was compressed with
1345 // a smaller size, and now it doesn't fit the entry anymore).
1346 // If that is the case we might need to evict blocks.
1347 if (!updateCompressionData(blk, pkt->getConstPtr<uint64_t>(),
1348 writebacks)) {
1349 invalidateBlock(blk);
1350 return false;
1351 }
1352 }
1353
1354 // only mark the block dirty if we got a writeback command,
1355 // and leave it as is for a clean writeback
1356 if (pkt->cmd == MemCmd::WritebackDirty) {
1357 // TODO: the coherent cache can assert that the dirty bit is set
1359 }
1360 // if the packet does not have sharers, it is passing
1361 // writable, and we got the writeback in Modified or Exclusive
1362 // state, if not we are in the Owned or Shared state
1363 if (!pkt->hasSharers()) {
1365 }
1366 // nothing else to do; writeback doesn't expect response
1367 assert(!pkt->needsResponse());
1368
1369 updateBlockData(blk, pkt, has_old_data);
1370 DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print());
1371 incHitCount(pkt);
1372
1373 // When the packet metadata arrives, the tag lookup will be done while
1374 // the payload is arriving. Then the block will be ready to access as
1375 // soon as the fill is done
1377 std::max(cyclesToTicks(tag_latency), (uint64_t)pkt->payloadDelay));
1378
1379 return true;
1380 } else if (pkt->cmd == MemCmd::CleanEvict) {
1381 // A CleanEvict does not need to access the data array
1382 lat = calculateTagOnlyLatency(pkt->headerDelay, tag_latency);
1383
1384 if (blk) {
1385 // Found the block in the tags, need to stop CleanEvict from
1386 // propagating further down the hierarchy. Returning true will
1387 // treat the CleanEvict like a satisfied write request and delete
1388 // it.
1389 return true;
1390 }
1391 // We didn't find the block here, propagate the CleanEvict further
1392 // down the memory hierarchy. Returning false will treat the CleanEvict
1393 // like a Writeback which could not find a replaceable block so has to
1394 // go to next level.
1395 return false;
1396 } else if (pkt->cmd == MemCmd::WriteClean) {
1397 // WriteClean handling is a special case. We can allocate a
1398 // block directly if it doesn't exist and we can update the
1399 // block immediately. The WriteClean transfers the ownership
1400 // of the block as well.
1401 assert(blkSize == pkt->getSize());
1402
1403 const bool has_old_data = blk && blk->isValid();
1404 if (!blk) {
1405 if (pkt->writeThrough()) {
1406 // if this is a write through packet, we don't try to
1407 // allocate if the block is not present
1408 return false;
1409 } else {
1410 // a writeback that misses needs to allocate a new block
1411 blk = allocateBlock(pkt, writebacks);
1412 if (!blk) {
1413 // no replaceable block available: give up, fwd to
1414 // next level.
1415 incMissCount(pkt);
1416 return false;
1417 }
1418
1420 }
1421 } else if (compressor) {
1422 // This is an overwrite to an existing block, therefore we need
1423 // to check for data expansion (i.e., block was compressed with
1424 // a smaller size, and now it doesn't fit the entry anymore).
1425 // If that is the case we might need to evict blocks.
1426 if (!updateCompressionData(blk, pkt->getConstPtr<uint64_t>(),
1427 writebacks)) {
1428 invalidateBlock(blk);
1429 return false;
1430 }
1431 }
1432
1433 // at this point either this is a writeback or a write-through
1434 // write clean operation and the block is already in this
1435 // cache, we need to update the data and the block flags
1436 assert(blk);
1437 // TODO: the coherent cache can assert that the dirty bit is set
1438 if (!pkt->writeThrough()) {
1440 }
1441 // nothing else to do; writeback doesn't expect response
1442 assert(!pkt->needsResponse());
1443
1444 updateBlockData(blk, pkt, has_old_data);
1445 DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print());
1446
1447 incHitCount(pkt);
1448
1449 // When the packet metadata arrives, the tag lookup will be done while
1450 // the payload is arriving. Then the block will be ready to access as
1451 // soon as the fill is done
1453 std::max(cyclesToTicks(tag_latency), (uint64_t)pkt->payloadDelay));
1454
1455 // If this a write-through packet it will be sent to cache below
1456 return !pkt->writeThrough();
1457 } else if (blk && (pkt->needsWritable() ?
1460 // OK to satisfy access
1461 incHitCount(pkt);
1462
1463 // Calculate access latency based on the need to access the data array
1464 if (pkt->isRead()) {
1465 lat = calculateAccessLatency(blk, pkt->headerDelay, tag_latency);
1466
1467 // When a block is compressed, it must first be decompressed
1468 // before being read. This adds to the access latency.
1469 if (compressor) {
1471 }
1472 } else {
1473 lat = calculateTagOnlyLatency(pkt->headerDelay, tag_latency);
1474 }
1475
1476 satisfyRequest(pkt, blk);
1477 maintainClusivity(pkt->fromCache(), blk);
1478
1479 return true;
1480 }
1481
1482 // Can't satisfy access normally... either no block (blk == nullptr)
1483 // or have block but need writable
1484
1485 incMissCount(pkt);
1486
1487 lat = calculateAccessLatency(blk, pkt->headerDelay, tag_latency);
1488
1489 if (!blk && pkt->isLLSC() && pkt->isWrite()) {
1490 // complete miss on store conditional... just give up now
1491 pkt->req->setExtraData(0);
1492 return true;
1493 }
1494
1495 return false;
1496}
1497
1498void
1500{
1501 if (from_cache && blk && blk->isValid() &&
1502 !blk->isSet(CacheBlk::DirtyBit) && clusivity == enums::mostly_excl) {
1503 // if we have responded to a cache, and our block is still
1504 // valid, but not dirty, and this cache is mostly exclusive
1505 // with respect to the cache above, drop the block
1506 invalidateBlock(blk);
1507 }
1508}
1509
1510CacheBlk*
1512 bool allocate)
1513{
1514 assert(pkt->isResponse());
1515 Addr addr = pkt->getAddr();
1516 bool is_secure = pkt->isSecure();
1517 const bool has_old_data = blk && blk->isValid();
1518 const std::string old_state = (debug::Cache && blk) ? blk->print() : "";
1519
1520 // When handling a fill, we should have no writes to this line.
1521 assert(addr == pkt->getBlockAddr(blkSize));
1522 assert(!writeBuffer.findMatch(addr, is_secure));
1523
1524 if (!blk) {
1525 // better have read new data...
1526 assert(pkt->hasData() || pkt->cmd == MemCmd::InvalidateResp);
1527
1528 // need to do a replacement if allocating, otherwise we stick
1529 // with the temporary storage
1530 blk = allocate ? allocateBlock(pkt, writebacks) : nullptr;
1531
1532 if (!blk) {
1533 // No replaceable block or a mostly exclusive
1534 // cache... just use temporary storage to complete the
1535 // current request and then get rid of it
1536 blk = tempBlock;
1537 tempBlock->insert(addr, is_secure);
1538 DPRINTF(Cache, "using temp block for %#llx (%s)\n", addr,
1539 is_secure ? "s" : "ns");
1540 }
1541 } else {
1542 // existing block... probably an upgrade
1543 // don't clear block status... if block is already dirty we
1544 // don't want to lose that
1545 }
1546
1547 // Block is guaranteed to be valid at this point
1548 assert(blk->isValid());
1549 assert(blk->isSecure() == is_secure);
1550 assert(regenerateBlkAddr(blk) == addr);
1551
1553
1554 // sanity check for whole-line writes, which should always be
1555 // marked as writable as part of the fill, and then later marked
1556 // dirty as part of satisfyRequest
1557 if (pkt->cmd == MemCmd::InvalidateResp) {
1558 assert(!pkt->hasSharers());
1559 }
1560
1561 // here we deal with setting the appropriate state of the line,
1562 // and we start by looking at the hasSharers flag, and ignore the
1563 // cacheResponding flag (normally signalling dirty data) if the
1564 // packet has sharers, thus the line is never allocated as Owned
1565 // (dirty but not writable), and always ends up being either
1566 // Shared, Exclusive or Modified, see Packet::setCacheResponding
1567 // for more details
1568 if (!pkt->hasSharers()) {
1569 // we could get a writable line from memory (rather than a
1570 // cache) even in a read-only cache, note that we set this bit
1571 // even for a read-only cache, possibly revisit this decision
1573
1574 // check if we got this via cache-to-cache transfer (i.e., from a
1575 // cache that had the block in Modified or Owned state)
1576 if (pkt->cacheResponding()) {
1577 // we got the block in Modified state, and invalidated the
1578 // owners copy
1580
1581 gem5_assert(!isReadOnly, "Should never see dirty snoop response "
1582 "in read-only cache %s\n", name());
1583
1584 }
1585 }
1586
1587 DPRINTF(Cache, "Block addr %#llx (%s) moving from %s to %s\n",
1588 addr, is_secure ? "s" : "ns", old_state, blk->print());
1589
1590 // if we got new data, copy it in (checking for a read response
1591 // and a response that has data is the same in the end)
1592 if (pkt->isRead()) {
1593 // sanity checks
1594 assert(pkt->hasData());
1595 assert(pkt->getSize() == blkSize);
1596
1597 updateBlockData(blk, pkt, has_old_data);
1598 }
1599 // The block will be ready when the payload arrives and the fill is done
1601 pkt->payloadDelay);
1602
1603 return blk;
1604}
1605
1606CacheBlk*
1608{
1609 // Get address
1610 const Addr addr = pkt->getAddr();
1611
1612 // Get secure bit
1613 const bool is_secure = pkt->isSecure();
1614
1615 // Block size and compression related access latency. Only relevant if
1616 // using a compressor, otherwise there is no extra delay, and the block
1617 // is fully sized
1618 std::size_t blk_size_bits = blkSize*8;
1619 Cycles compression_lat = Cycles(0);
1620 Cycles decompression_lat = Cycles(0);
1621
1622 // If a compressor is being used, it is called to compress data before
1623 // insertion. Although in Gem5 the data is stored uncompressed, even if a
1624 // compressor is used, the compression/decompression methods are called to
1625 // calculate the amount of extra cycles needed to read or write compressed
1626 // blocks.
1627 if (compressor && pkt->hasData()) {
1628 const auto comp_data = compressor->compress(
1629 pkt->getConstPtr<uint64_t>(), compression_lat, decompression_lat);
1630 blk_size_bits = comp_data->getSizeBits();
1631 }
1632
1633 // Find replacement victim
1634 std::vector<CacheBlk*> evict_blks;
1635 CacheBlk *victim = tags->findVictim(addr, is_secure, blk_size_bits,
1636 evict_blks);
1637
1638 // It is valid to return nullptr if there is no victim
1639 if (!victim)
1640 return nullptr;
1641
1642 // Print victim block's information
1643 DPRINTF(CacheRepl, "Replacement victim: %s\n", victim->print());
1644
1645 // Try to evict blocks; if it fails, give up on allocation
1646 if (!handleEvictions(evict_blks, writebacks)) {
1647 return nullptr;
1648 }
1649
1650 // Insert new block at victimized entry
1651 tags->insertBlock(pkt, victim);
1652
1653 // If using a compressor, set compression data. This must be done after
1654 // insertion, as the compression bit may be set.
1655 if (compressor) {
1656 compressor->setSizeBits(victim, blk_size_bits);
1657 compressor->setDecompressionLatency(victim, decompression_lat);
1658 }
1659
1660 return victim;
1661}
1662
1663void
1665{
1666 // If block is still marked as prefetched, then it hasn't been used
1667 if (blk->wasPrefetched()) {
1669 }
1670
1671 // Notify that the data contents for this address are no longer present
1672 updateBlockData(blk, nullptr, blk->isValid());
1673
1674 // If handling a block present in the Tags, let it do its invalidation
1675 // process, which will update stats and invalidate the block itself
1676 if (blk != tempBlock) {
1677 tags->invalidate(blk);
1678 } else {
1680 }
1681}
1682
1683void
1685{
1686 PacketPtr pkt = evictBlock(blk);
1687 if (pkt) {
1688 writebacks.push_back(pkt);
1689 }
1690}
1691
1694{
1696 "Writeback from read-only cache");
1697 assert(blk && blk->isValid() &&
1699
1701
1702 RequestPtr req = std::make_shared<Request>(
1704
1705 if (blk->isSecure())
1706 req->setFlags(Request::SECURE);
1707
1708 req->taskId(blk->getTaskId());
1709
1710 PacketPtr pkt =
1711 new Packet(req, blk->isSet(CacheBlk::DirtyBit) ?
1713
1714 DPRINTF(Cache, "Create Writeback %s writable: %d, dirty: %d\n",
1715 pkt->print(), blk->isSet(CacheBlk::WritableBit),
1717
1718 if (blk->isSet(CacheBlk::WritableBit)) {
1719 // not asserting shared means we pass the block in modified
1720 // state, mark our own block non-writeable
1722 } else {
1723 // we are in the Owned state, tell the receiver
1724 pkt->setHasSharers();
1725 }
1726
1727 // make sure the block is not marked dirty
1729
1730 pkt->allocate();
1731 pkt->setDataFromBlock(blk->data, blkSize);
1732
1733 // When a block is compressed, it must first be decompressed before being
1734 // sent for writeback.
1735 if (compressor) {
1737 }
1738
1739 return pkt;
1740}
1741
1744{
1745 RequestPtr req = std::make_shared<Request>(
1747
1748 if (blk->isSecure()) {
1749 req->setFlags(Request::SECURE);
1750 }
1751 req->taskId(blk->getTaskId());
1752
1753 PacketPtr pkt = new Packet(req, MemCmd::WriteClean, blkSize, id);
1754
1755 if (dest) {
1756 req->setFlags(dest);
1757 pkt->setWriteThrough();
1758 }
1759
1760 DPRINTF(Cache, "Create %s writable: %d, dirty: %d\n", pkt->print(),
1762
1763 if (blk->isSet(CacheBlk::WritableBit)) {
1764 // not asserting shared means we pass the block in modified
1765 // state, mark our own block non-writeable
1767 } else {
1768 // we are in the Owned state, tell the receiver
1769 pkt->setHasSharers();
1770 }
1771
1772 // make sure the block is not marked dirty
1774
1775 pkt->allocate();
1776 pkt->setDataFromBlock(blk->data, blkSize);
1777
1778 // When a block is compressed, it must first be decompressed before being
1779 // sent for writeback.
1780 if (compressor) {
1782 }
1783
1784 return pkt;
1785}
1786
1787
1788void
1790{
1791 tags->forEachBlk([this](CacheBlk &blk) { writebackVisitor(blk); });
1792}
1793
1794void
1796{
1797 tags->forEachBlk([this](CacheBlk &blk) { invalidateVisitor(blk); });
1798}
1799
1800bool
1802{
1803 return tags->anyBlk([](CacheBlk &blk) {
1804 return blk.isSet(CacheBlk::DirtyBit); });
1805}
1806
1807bool
1809{
1811}
1812
1813void
1815{
1816 if (blk.isSet(CacheBlk::DirtyBit)) {
1817 assert(blk.isValid());
1818
1819 RequestPtr request = std::make_shared<Request>(
1821
1822 request->taskId(blk.getTaskId());
1823 if (blk.isSecure()) {
1824 request->setFlags(Request::SECURE);
1825 }
1826
1827 Packet packet(request, MemCmd::WriteReq);
1828 packet.dataStatic(blk.data);
1829
1830 memSidePort.sendFunctional(&packet);
1831
1833 }
1834}
1835
1836void
1838{
1839 if (blk.isSet(CacheBlk::DirtyBit))
1840 warn_once("Invalidating dirty cache lines. " \
1841 "Expect things to break.\n");
1842
1843 if (blk.isValid()) {
1844 assert(!blk.isSet(CacheBlk::DirtyBit));
1845 invalidateBlock(&blk);
1846 }
1847}
1848
1849Tick
1851{
1852 Tick nextReady = std::min(mshrQueue.nextReadyTime(),
1854
1855 // Don't signal prefetch ready time if no MSHRs available
1856 // Will signal once enoguh MSHRs are deallocated
1857 if (prefetcher && mshrQueue.canPrefetch() && !isBlocked()) {
1858 nextReady = std::min(nextReady,
1860 }
1861
1862 return nextReady;
1863}
1864
1865
1866bool
1868{
1869 assert(mshr);
1870
1871 // use request from 1st target
1872 PacketPtr tgt_pkt = mshr->getTarget()->pkt;
1873
1874 DPRINTF(Cache, "%s: MSHR %s\n", __func__, tgt_pkt->print());
1875
1876 // if the cache is in write coalescing mode or (additionally) in
1877 // no allocation mode, and we have a write packet with an MSHR
1878 // that is not a whole-line write (due to incompatible flags etc),
1879 // then reset the write mode
1880 if (writeAllocator && writeAllocator->coalesce() && tgt_pkt->isWrite()) {
1881 if (!mshr->isWholeLineWrite()) {
1882 // if we are currently write coalescing, hold on the
1883 // MSHR as many cycles extra as we need to completely
1884 // write a cache line
1885 if (writeAllocator->delay(mshr->blkAddr)) {
1886 Tick delay = blkSize / tgt_pkt->getSize() * clockPeriod();
1887 DPRINTF(CacheVerbose, "Delaying pkt %s %llu ticks to allow "
1888 "for write coalescing\n", tgt_pkt->print(), delay);
1889 mshrQueue.delay(mshr, delay);
1890 return false;
1891 } else {
1893 }
1894 } else {
1896 }
1897 }
1898
1899 CacheBlk *blk = tags->findBlock(mshr->blkAddr, mshr->isSecure);
1900
1901 // either a prefetch that is not present upstream, or a normal
1902 // MSHR request, proceed to get the packet to send downstream
1903 PacketPtr pkt = createMissPacket(tgt_pkt, blk, mshr->needsWritable(),
1904 mshr->isWholeLineWrite());
1905
1906 mshr->isForward = (pkt == nullptr);
1907
1908 if (mshr->isForward) {
1909 // not a cache block request, but a response is expected
1910 // make copy of current packet to forward, keep current
1911 // copy for response handling
1912 pkt = new Packet(tgt_pkt, false, true);
1913 assert(!pkt->isWrite());
1914 }
1915
1916 // play it safe and append (rather than set) the sender state,
1917 // as forwarded packets may already have existing state
1918 pkt->pushSenderState(mshr);
1919
1920 if (pkt->isClean() && blk && blk->isSet(CacheBlk::DirtyBit)) {
1921 // A cache clean opearation is looking for a dirty block. Mark
1922 // the packet so that the destination xbar can determine that
1923 // there will be a follow-up write packet as well.
1924 pkt->setSatisfied();
1925 }
1926
1927 if (!memSidePort.sendTimingReq(pkt)) {
1928 // we are awaiting a retry, but we
1929 // delete the packet and will be creating a new packet
1930 // when we get the opportunity
1931 delete pkt;
1932
1933 // note that we have now masked any requestBus and
1934 // schedSendEvent (we will wait for a retry before
1935 // doing anything), and this is so even if we do not
1936 // care about this packet and might override it before
1937 // it gets retried
1938 return true;
1939 } else {
1940 // As part of the call to sendTimingReq the packet is
1941 // forwarded to all neighbouring caches (and any caches
1942 // above them) as a snoop. Thus at this point we know if
1943 // any of the neighbouring caches are responding, and if
1944 // so, we know it is dirty, and we can determine if it is
1945 // being passed as Modified, making our MSHR the ordering
1946 // point
1947 bool pending_modified_resp = !pkt->hasSharers() &&
1948 pkt->cacheResponding();
1949 markInService(mshr, pending_modified_resp);
1950
1951 if (pkt->isClean() && blk && blk->isSet(CacheBlk::DirtyBit)) {
1952 // A cache clean opearation is looking for a dirty
1953 // block. If a dirty block is encountered a WriteClean
1954 // will update any copies to the path to the memory
1955 // until the point of reference.
1956 DPRINTF(CacheVerbose, "%s: packet %s found block: %s\n",
1957 __func__, pkt->print(), blk->print());
1958 PacketPtr wb_pkt = writecleanBlk(blk, pkt->req->getDest(),
1959 pkt->id);
1960 PacketList writebacks;
1961 writebacks.push_back(wb_pkt);
1962 doWritebacks(writebacks, 0);
1963 }
1964
1965 return false;
1966 }
1967}
1968
1969bool
1971{
1972 assert(wq_entry);
1973
1974 // always a single target for write queue entries
1975 PacketPtr tgt_pkt = wq_entry->getTarget()->pkt;
1976
1977 DPRINTF(Cache, "%s: write %s\n", __func__, tgt_pkt->print());
1978
1979 // forward as is, both for evictions and uncacheable writes
1980 if (!memSidePort.sendTimingReq(tgt_pkt)) {
1981 // note that we have now masked any requestBus and
1982 // schedSendEvent (we will wait for a retry before
1983 // doing anything), and this is so even if we do not
1984 // care about this packet and might override it before
1985 // it gets retried
1986 return true;
1987 } else {
1988 markInService(wq_entry);
1989 return false;
1990 }
1991}
1992
1993void
1995{
1996 bool dirty(isDirty());
1997
1998 if (dirty) {
1999 warn("*** The cache still contains dirty data. ***\n");
2000 warn(" Make sure to drain the system using the correct flags.\n");
2001 warn(" This checkpoint will not restore correctly " \
2002 "and dirty data in the cache will be lost!\n");
2003 }
2004
2005 // Since we don't checkpoint the data in the cache, any dirty data
2006 // will be lost when restoring from a checkpoint of a system that
2007 // wasn't drained properly. Flag the checkpoint as invalid if the
2008 // cache contains dirty data.
2009 bool bad_checkpoint(dirty);
2010 SERIALIZE_SCALAR(bad_checkpoint);
2011}
2012
2013void
2015{
2016 bool bad_checkpoint;
2017 UNSERIALIZE_SCALAR(bad_checkpoint);
2018 if (bad_checkpoint) {
2019 fatal("Restoring from checkpoints with dirty caches is not "
2020 "supported in the classic memory system. Please remove any "
2021 "caches or drain them properly before taking checkpoints.\n");
2022 }
2023}
2024
2025
2027 const std::string &name)
2028 : statistics::Group(&c, name.c_str()), cache(c),
2029 ADD_STAT(hits, statistics::units::Count::get(),
2030 ("number of " + name + " hits").c_str()),
2031 ADD_STAT(misses, statistics::units::Count::get(),
2032 ("number of " + name + " misses").c_str()),
2033 ADD_STAT(hitLatency, statistics::units::Tick::get(),
2034 ("number of " + name + " hit ticks").c_str()),
2035 ADD_STAT(missLatency, statistics::units::Tick::get(),
2036 ("number of " + name + " miss ticks").c_str()),
2037 ADD_STAT(accesses, statistics::units::Count::get(),
2038 ("number of " + name + " accesses(hits+misses)").c_str()),
2039 ADD_STAT(missRate, statistics::units::Ratio::get(),
2040 ("miss rate for " + name + " accesses").c_str()),
2041 ADD_STAT(avgMissLatency, statistics::units::Rate<
2042 statistics::units::Tick, statistics::units::Count>::get(),
2043 ("average " + name + " miss latency").c_str()),
2044 ADD_STAT(mshrHits, statistics::units::Count::get(),
2045 ("number of " + name + " MSHR hits").c_str()),
2046 ADD_STAT(mshrMisses, statistics::units::Count::get(),
2047 ("number of " + name + " MSHR misses").c_str()),
2048 ADD_STAT(mshrUncacheable, statistics::units::Count::get(),
2049 ("number of " + name + " MSHR uncacheable").c_str()),
2050 ADD_STAT(mshrMissLatency, statistics::units::Tick::get(),
2051 ("number of " + name + " MSHR miss ticks").c_str()),
2052 ADD_STAT(mshrUncacheableLatency, statistics::units::Tick::get(),
2053 ("number of " + name + " MSHR uncacheable ticks").c_str()),
2054 ADD_STAT(mshrMissRate, statistics::units::Ratio::get(),
2055 ("mshr miss rate for " + name + " accesses").c_str()),
2056 ADD_STAT(avgMshrMissLatency, statistics::units::Rate<
2057 statistics::units::Tick, statistics::units::Count>::get(),
2058 ("average " + name + " mshr miss latency").c_str()),
2059 ADD_STAT(avgMshrUncacheableLatency, statistics::units::Rate<
2060 statistics::units::Tick, statistics::units::Count>::get(),
2061 ("average " + name + " mshr uncacheable latency").c_str())
2062{
2063}
2064
2065void
2067{
2068 using namespace statistics;
2069
2071 System *system = cache.system;
2072 const auto max_requestors = system->maxRequestors();
2073
2074 hits
2075 .init(max_requestors)
2076 .flags(total | nozero | nonan)
2077 ;
2078 for (int i = 0; i < max_requestors; i++) {
2079 hits.subname(i, system->getRequestorName(i));
2080 }
2081
2082 // Miss statistics
2083 misses
2084 .init(max_requestors)
2085 .flags(total | nozero | nonan)
2086 ;
2087 for (int i = 0; i < max_requestors; i++) {
2088 misses.subname(i, system->getRequestorName(i));
2089 }
2090
2091 // Hit latency statistics
2092 hitLatency
2093 .init(max_requestors)
2094 .flags(total | nozero | nonan)
2095 ;
2096 for (int i = 0; i < max_requestors; i++) {
2097 hitLatency.subname(i, system->getRequestorName(i));
2098 }
2099
2100 // Miss latency statistics
2101 missLatency
2102 .init(max_requestors)
2103 .flags(total | nozero | nonan)
2104 ;
2105 for (int i = 0; i < max_requestors; i++) {
2106 missLatency.subname(i, system->getRequestorName(i));
2107 }
2108
2109 // access formulas
2110 accesses.flags(total | nozero | nonan);
2111 accesses = hits + misses;
2112 for (int i = 0; i < max_requestors; i++) {
2113 accesses.subname(i, system->getRequestorName(i));
2114 }
2115
2116 // miss rate formulas
2117 missRate.flags(total | nozero | nonan);
2118 missRate = misses / accesses;
2119 for (int i = 0; i < max_requestors; i++) {
2120 missRate.subname(i, system->getRequestorName(i));
2121 }
2122
2123 // miss latency formulas
2124 avgMissLatency.flags(total | nozero | nonan);
2125 avgMissLatency = missLatency / misses;
2126 for (int i = 0; i < max_requestors; i++) {
2127 avgMissLatency.subname(i, system->getRequestorName(i));
2128 }
2129
2130 // MSHR statistics
2131 // MSHR hit statistics
2132 mshrHits
2133 .init(max_requestors)
2134 .flags(total | nozero | nonan)
2135 ;
2136 for (int i = 0; i < max_requestors; i++) {
2137 mshrHits.subname(i, system->getRequestorName(i));
2138 }
2139
2140 // MSHR miss statistics
2141 mshrMisses
2142 .init(max_requestors)
2143 .flags(total | nozero | nonan)
2144 ;
2145 for (int i = 0; i < max_requestors; i++) {
2146 mshrMisses.subname(i, system->getRequestorName(i));
2147 }
2148
2149 // MSHR miss latency statistics
2150 mshrMissLatency
2151 .init(max_requestors)
2152 .flags(total | nozero | nonan)
2153 ;
2154 for (int i = 0; i < max_requestors; i++) {
2155 mshrMissLatency.subname(i, system->getRequestorName(i));
2156 }
2157
2158 // MSHR uncacheable statistics
2159 mshrUncacheable
2160 .init(max_requestors)
2161 .flags(total | nozero | nonan)
2162 ;
2163 for (int i = 0; i < max_requestors; i++) {
2164 mshrUncacheable.subname(i, system->getRequestorName(i));
2165 }
2166
2167 // MSHR miss latency statistics
2168 mshrUncacheableLatency
2169 .init(max_requestors)
2170 .flags(total | nozero | nonan)
2171 ;
2172 for (int i = 0; i < max_requestors; i++) {
2173 mshrUncacheableLatency.subname(i, system->getRequestorName(i));
2174 }
2175
2176 // MSHR miss rate formulas
2177 mshrMissRate.flags(total | nozero | nonan);
2178 mshrMissRate = mshrMisses / accesses;
2179
2180 for (int i = 0; i < max_requestors; i++) {
2181 mshrMissRate.subname(i, system->getRequestorName(i));
2182 }
2183
2184 // mshrMiss latency formulas
2185 avgMshrMissLatency.flags(total | nozero | nonan);
2186 avgMshrMissLatency = mshrMissLatency / mshrMisses;
2187 for (int i = 0; i < max_requestors; i++) {
2188 avgMshrMissLatency.subname(i, system->getRequestorName(i));
2189 }
2190
2191 // mshrUncacheable latency formulas
2192 avgMshrUncacheableLatency.flags(total | nozero | nonan);
2193 avgMshrUncacheableLatency = mshrUncacheableLatency / mshrUncacheable;
2194 for (int i = 0; i < max_requestors; i++) {
2195 avgMshrUncacheableLatency.subname(i, system->getRequestorName(i));
2196 }
2197}
2198
2200 : statistics::Group(&c), cache(c),
2201
2202 ADD_STAT(demandHits, statistics::units::Count::get(),
2203 "number of demand (read+write) hits"),
2204 ADD_STAT(overallHits, statistics::units::Count::get(),
2205 "number of overall hits"),
2206 ADD_STAT(demandHitLatency, statistics::units::Tick::get(),
2207 "number of demand (read+write) hit ticks"),
2208 ADD_STAT(overallHitLatency, statistics::units::Tick::get(),
2209 "number of overall hit ticks"),
2210 ADD_STAT(demandMisses, statistics::units::Count::get(),
2211 "number of demand (read+write) misses"),
2212 ADD_STAT(overallMisses, statistics::units::Count::get(),
2213 "number of overall misses"),
2214 ADD_STAT(demandMissLatency, statistics::units::Tick::get(),
2215 "number of demand (read+write) miss ticks"),
2216 ADD_STAT(overallMissLatency, statistics::units::Tick::get(),
2217 "number of overall miss ticks"),
2218 ADD_STAT(demandAccesses, statistics::units::Count::get(),
2219 "number of demand (read+write) accesses"),
2220 ADD_STAT(overallAccesses, statistics::units::Count::get(),
2221 "number of overall (read+write) accesses"),
2222 ADD_STAT(demandMissRate, statistics::units::Ratio::get(),
2223 "miss rate for demand accesses"),
2224 ADD_STAT(overallMissRate, statistics::units::Ratio::get(),
2225 "miss rate for overall accesses"),
2226 ADD_STAT(demandAvgMissLatency, statistics::units::Rate<
2227 statistics::units::Tick, statistics::units::Count>::get(),
2228 "average overall miss latency in ticks"),
2229 ADD_STAT(overallAvgMissLatency, statistics::units::Rate<
2230 statistics::units::Tick, statistics::units::Count>::get(),
2231 "average overall miss latency"),
2232 ADD_STAT(blockedCycles, statistics::units::Cycle::get(),
2233 "number of cycles access was blocked"),
2234 ADD_STAT(blockedCauses, statistics::units::Count::get(),
2235 "number of times access was blocked"),
2236 ADD_STAT(avgBlocked, statistics::units::Rate<
2237 statistics::units::Cycle, statistics::units::Count>::get(),
2238 "average number of cycles each access was blocked"),
2239 ADD_STAT(writebacks, statistics::units::Count::get(),
2240 "number of writebacks"),
2241 ADD_STAT(demandMshrHits, statistics::units::Count::get(),
2242 "number of demand (read+write) MSHR hits"),
2243 ADD_STAT(overallMshrHits, statistics::units::Count::get(),
2244 "number of overall MSHR hits"),
2245 ADD_STAT(demandMshrMisses, statistics::units::Count::get(),
2246 "number of demand (read+write) MSHR misses"),
2247 ADD_STAT(overallMshrMisses, statistics::units::Count::get(),
2248 "number of overall MSHR misses"),
2249 ADD_STAT(overallMshrUncacheable, statistics::units::Count::get(),
2250 "number of overall MSHR uncacheable misses"),
2251 ADD_STAT(demandMshrMissLatency, statistics::units::Tick::get(),
2252 "number of demand (read+write) MSHR miss ticks"),
2253 ADD_STAT(overallMshrMissLatency, statistics::units::Tick::get(),
2254 "number of overall MSHR miss ticks"),
2255 ADD_STAT(overallMshrUncacheableLatency, statistics::units::Tick::get(),
2256 "number of overall MSHR uncacheable ticks"),
2257 ADD_STAT(demandMshrMissRate, statistics::units::Ratio::get(),
2258 "mshr miss ratio for demand accesses"),
2259 ADD_STAT(overallMshrMissRate, statistics::units::Ratio::get(),
2260 "mshr miss ratio for overall accesses"),
2261 ADD_STAT(demandAvgMshrMissLatency, statistics::units::Rate<
2262 statistics::units::Tick, statistics::units::Count>::get(),
2263 "average overall mshr miss latency"),
2264 ADD_STAT(overallAvgMshrMissLatency, statistics::units::Rate<
2265 statistics::units::Tick, statistics::units::Count>::get(),
2266 "average overall mshr miss latency"),
2267 ADD_STAT(overallAvgMshrUncacheableLatency, statistics::units::Rate<
2268 statistics::units::Tick, statistics::units::Count>::get(),
2269 "average overall mshr uncacheable latency"),
2270 ADD_STAT(replacements, statistics::units::Count::get(),
2271 "number of replacements"),
2272 ADD_STAT(dataExpansions, statistics::units::Count::get(),
2273 "number of data expansions"),
2274 ADD_STAT(dataContractions, statistics::units::Count::get(),
2275 "number of data contractions"),
2276 cmd(MemCmd::NUM_MEM_CMDS)
2277{
2278 for (int idx = 0; idx < MemCmd::NUM_MEM_CMDS; ++idx)
2279 cmd[idx].reset(new CacheCmdStats(c, MemCmd(idx).toString()));
2280}
2281
2282void
2284{
2285 using namespace statistics;
2286
2288
2289 System *system = cache.system;
2290 const auto max_requestors = system->maxRequestors();
2291
2292 for (auto &cs : cmd)
2293 cs->regStatsFromParent();
2294
2295// These macros make it easier to sum the right subset of commands and
2296// to change the subset of commands that are considered "demand" vs
2297// "non-demand"
2298#define SUM_DEMAND(s) \
2299 (cmd[MemCmd::ReadReq]->s + cmd[MemCmd::WriteReq]->s + \
2300 cmd[MemCmd::WriteLineReq]->s + cmd[MemCmd::ReadExReq]->s + \
2301 cmd[MemCmd::ReadCleanReq]->s + cmd[MemCmd::ReadSharedReq]->s)
2302
2303// should writebacks be included here? prior code was inconsistent...
2304#define SUM_NON_DEMAND(s) \
2305 (cmd[MemCmd::SoftPFReq]->s + cmd[MemCmd::HardPFReq]->s + \
2306 cmd[MemCmd::SoftPFExReq]->s)
2307
2308 demandHits.flags(total | nozero | nonan);
2309 demandHits = SUM_DEMAND(hits);
2310 for (int i = 0; i < max_requestors; i++) {
2311 demandHits.subname(i, system->getRequestorName(i));
2312 }
2313
2314 overallHits.flags(total | nozero | nonan);
2315 overallHits = demandHits + SUM_NON_DEMAND(hits);
2316 for (int i = 0; i < max_requestors; i++) {
2317 overallHits.subname(i, system->getRequestorName(i));
2318 }
2319
2320 demandMisses.flags(total | nozero | nonan);
2321 demandMisses = SUM_DEMAND(misses);
2322 for (int i = 0; i < max_requestors; i++) {
2323 demandMisses.subname(i, system->getRequestorName(i));
2324 }
2325
2326 overallMisses.flags(total | nozero | nonan);
2327 overallMisses = demandMisses + SUM_NON_DEMAND(misses);
2328 for (int i = 0; i < max_requestors; i++) {
2329 overallMisses.subname(i, system->getRequestorName(i));
2330 }
2331
2332 demandMissLatency.flags(total | nozero | nonan);
2333 demandMissLatency = SUM_DEMAND(missLatency);
2334 for (int i = 0; i < max_requestors; i++) {
2335 demandMissLatency.subname(i, system->getRequestorName(i));
2336 }
2337
2338 overallMissLatency.flags(total | nozero | nonan);
2339 overallMissLatency = demandMissLatency + SUM_NON_DEMAND(missLatency);
2340 for (int i = 0; i < max_requestors; i++) {
2341 overallMissLatency.subname(i, system->getRequestorName(i));
2342 }
2343
2344 demandHitLatency.flags(total | nozero | nonan);
2345 demandHitLatency = SUM_DEMAND(hitLatency);
2346 for (int i = 0; i < max_requestors; i++) {
2347 demandHitLatency.subname(i, system->getRequestorName(i));
2348 }
2349 overallHitLatency.flags(total | nozero | nonan);
2350 overallHitLatency = demandHitLatency + SUM_NON_DEMAND(hitLatency);
2351 for (int i = 0; i < max_requestors; i++) {
2352 overallHitLatency.subname(i, system->getRequestorName(i));
2353 }
2354
2355 demandAccesses.flags(total | nozero | nonan);
2356 demandAccesses = demandHits + demandMisses;
2357 for (int i = 0; i < max_requestors; i++) {
2358 demandAccesses.subname(i, system->getRequestorName(i));
2359 }
2360
2361 overallAccesses.flags(total | nozero | nonan);
2362 overallAccesses = overallHits + overallMisses;
2363 for (int i = 0; i < max_requestors; i++) {
2364 overallAccesses.subname(i, system->getRequestorName(i));
2365 }
2366
2367 demandMissRate.flags(total | nozero | nonan);
2368 demandMissRate = demandMisses / demandAccesses;
2369 for (int i = 0; i < max_requestors; i++) {
2370 demandMissRate.subname(i, system->getRequestorName(i));
2371 }
2372
2373 overallMissRate.flags(total | nozero | nonan);
2374 overallMissRate = overallMisses / overallAccesses;
2375 for (int i = 0; i < max_requestors; i++) {
2376 overallMissRate.subname(i, system->getRequestorName(i));
2377 }
2378
2379 demandAvgMissLatency.flags(total | nozero | nonan);
2380 demandAvgMissLatency = demandMissLatency / demandMisses;
2381 for (int i = 0; i < max_requestors; i++) {
2382 demandAvgMissLatency.subname(i, system->getRequestorName(i));
2383 }
2384
2385 overallAvgMissLatency.flags(total | nozero | nonan);
2386 overallAvgMissLatency = overallMissLatency / overallMisses;
2387 for (int i = 0; i < max_requestors; i++) {
2388 overallAvgMissLatency.subname(i, system->getRequestorName(i));
2389 }
2390
2391 blockedCycles.init(NUM_BLOCKED_CAUSES);
2392 blockedCycles
2393 .subname(Blocked_NoMSHRs, "no_mshrs")
2394 .subname(Blocked_NoTargets, "no_targets")
2395 ;
2396
2397
2398 blockedCauses.init(NUM_BLOCKED_CAUSES);
2399 blockedCauses
2400 .subname(Blocked_NoMSHRs, "no_mshrs")
2401 .subname(Blocked_NoTargets, "no_targets")
2402 ;
2403
2404 avgBlocked
2405 .subname(Blocked_NoMSHRs, "no_mshrs")
2406 .subname(Blocked_NoTargets, "no_targets")
2407 ;
2408 avgBlocked = blockedCycles / blockedCauses;
2409
2410 writebacks
2411 .init(max_requestors)
2412 .flags(total | nozero | nonan)
2413 ;
2414 for (int i = 0; i < max_requestors; i++) {
2415 writebacks.subname(i, system->getRequestorName(i));
2416 }
2417
2418 demandMshrHits.flags(total | nozero | nonan);
2419 demandMshrHits = SUM_DEMAND(mshrHits);
2420 for (int i = 0; i < max_requestors; i++) {
2421 demandMshrHits.subname(i, system->getRequestorName(i));
2422 }
2423
2424 overallMshrHits.flags(total | nozero | nonan);
2425 overallMshrHits = demandMshrHits + SUM_NON_DEMAND(mshrHits);
2426 for (int i = 0; i < max_requestors; i++) {
2427 overallMshrHits.subname(i, system->getRequestorName(i));
2428 }
2429
2430 demandMshrMisses.flags(total | nozero | nonan);
2431 demandMshrMisses = SUM_DEMAND(mshrMisses);
2432 for (int i = 0; i < max_requestors; i++) {
2433 demandMshrMisses.subname(i, system->getRequestorName(i));
2434 }
2435
2436 overallMshrMisses.flags(total | nozero | nonan);
2437 overallMshrMisses = demandMshrMisses + SUM_NON_DEMAND(mshrMisses);
2438 for (int i = 0; i < max_requestors; i++) {
2439 overallMshrMisses.subname(i, system->getRequestorName(i));
2440 }
2441
2442 demandMshrMissLatency.flags(total | nozero | nonan);
2443 demandMshrMissLatency = SUM_DEMAND(mshrMissLatency);
2444 for (int i = 0; i < max_requestors; i++) {
2445 demandMshrMissLatency.subname(i, system->getRequestorName(i));
2446 }
2447
2448 overallMshrMissLatency.flags(total | nozero | nonan);
2449 overallMshrMissLatency =
2450 demandMshrMissLatency + SUM_NON_DEMAND(mshrMissLatency);
2451 for (int i = 0; i < max_requestors; i++) {
2452 overallMshrMissLatency.subname(i, system->getRequestorName(i));
2453 }
2454
2455 overallMshrUncacheable.flags(total | nozero | nonan);
2456 overallMshrUncacheable =
2457 SUM_DEMAND(mshrUncacheable) + SUM_NON_DEMAND(mshrUncacheable);
2458 for (int i = 0; i < max_requestors; i++) {
2459 overallMshrUncacheable.subname(i, system->getRequestorName(i));
2460 }
2461
2462
2463 overallMshrUncacheableLatency.flags(total | nozero | nonan);
2464 overallMshrUncacheableLatency =
2465 SUM_DEMAND(mshrUncacheableLatency) +
2466 SUM_NON_DEMAND(mshrUncacheableLatency);
2467 for (int i = 0; i < max_requestors; i++) {
2468 overallMshrUncacheableLatency.subname(i, system->getRequestorName(i));
2469 }
2470
2471 demandMshrMissRate.flags(total | nozero | nonan);
2472 demandMshrMissRate = demandMshrMisses / demandAccesses;
2473 for (int i = 0; i < max_requestors; i++) {
2474 demandMshrMissRate.subname(i, system->getRequestorName(i));
2475 }
2476
2477 overallMshrMissRate.flags(total | nozero | nonan);
2478 overallMshrMissRate = overallMshrMisses / overallAccesses;
2479 for (int i = 0; i < max_requestors; i++) {
2480 overallMshrMissRate.subname(i, system->getRequestorName(i));
2481 }
2482
2483 demandAvgMshrMissLatency.flags(total | nozero | nonan);
2484 demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses;
2485 for (int i = 0; i < max_requestors; i++) {
2486 demandAvgMshrMissLatency.subname(i, system->getRequestorName(i));
2487 }
2488
2489 overallAvgMshrMissLatency.flags(total | nozero | nonan);
2490 overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses;
2491 for (int i = 0; i < max_requestors; i++) {
2492 overallAvgMshrMissLatency.subname(i, system->getRequestorName(i));
2493 }
2494
2495 overallAvgMshrUncacheableLatency.flags(total | nozero | nonan);
2496 overallAvgMshrUncacheableLatency =
2497 overallMshrUncacheableLatency / overallMshrUncacheable;
2498 for (int i = 0; i < max_requestors; i++) {
2499 overallAvgMshrUncacheableLatency.subname(i,
2501 }
2502
2503 dataExpansions.flags(nozero | nonan);
2504 dataContractions.flags(nozero | nonan);
2505}
2506
2507void
2509{
2510 ppHit = new ProbePointArg<PacketPtr>(this->getProbeManager(), "Hit");
2511 ppMiss = new ProbePointArg<PacketPtr>(this->getProbeManager(), "Miss");
2512 ppFill = new ProbePointArg<PacketPtr>(this->getProbeManager(), "Fill");
2513 ppDataUpdate =
2514 new ProbePointArg<DataUpdate>(this->getProbeManager(), "Data Update");
2515}
2516
2518//
2519// CpuSidePort
2520//
2522bool
2524{
2525 // Snoops shouldn't happen when bypassing caches
2526 assert(!cache.system->bypassCaches());
2527
2528 assert(pkt->isResponse());
2529
2530 // Express snoop responses from requestor to responder, e.g., from L1 to L2
2531 cache.recvTimingSnoopResp(pkt);
2532 return true;
2533}
2534
2535
2536bool
2538{
2539 if (cache.system->bypassCaches() || pkt->isExpressSnoop()) {
2540 // always let express snoop packets through even if blocked
2541 return true;
2542 } else if (blocked || mustSendRetry) {
2543 // either already committed to send a retry, or blocked
2544 mustSendRetry = true;
2545 return false;
2546 }
2547 mustSendRetry = false;
2548 return true;
2549}
2550
2551bool
2553{
2554 assert(pkt->isRequest());
2555
2556 if (cache.system->bypassCaches()) {
2557 // Just forward the packet if caches are disabled.
2558 // @todo This should really enqueue the packet rather
2559 [[maybe_unused]] bool success = cache.memSidePort.sendTimingReq(pkt);
2560 assert(success);
2561 return true;
2562 } else if (tryTiming(pkt)) {
2563 cache.recvTimingReq(pkt);
2564 return true;
2565 }
2566 return false;
2567}
2568
2569Tick
2571{
2572 if (cache.system->bypassCaches()) {
2573 // Forward the request if the system is in cache bypass mode.
2574 return cache.memSidePort.sendAtomic(pkt);
2575 } else {
2576 return cache.recvAtomic(pkt);
2577 }
2578}
2579
2580void
2582{
2583 if (cache.system->bypassCaches()) {
2584 // The cache should be flushed if we are in cache bypass mode,
2585 // so we don't need to check if we need to update anything.
2586 cache.memSidePort.sendFunctional(pkt);
2587 return;
2588 }
2589
2590 // functional request
2591 cache.functionalAccess(pkt, true);
2592}
2593
2596{
2597 return cache.getAddrRanges();
2598}
2599
2600
2602CpuSidePort::CpuSidePort(const std::string &_name, BaseCache& _cache,
2603 const std::string &_label)
2604 : CacheResponsePort(_name, _cache, _label)
2605{
2606}
2607
2609//
2610// MemSidePort
2611//
2613bool
2615{
2616 cache->recvTimingResp(pkt);
2617 return true;
2618}
2619
2620// Express snooping requests to memside port
2621void
2623{
2624 // Snoops shouldn't happen when bypassing caches
2625 assert(!cache->system->bypassCaches());
2626
2627 // handle snooping requests
2628 cache->recvTimingSnoopReq(pkt);
2629}
2630
2631Tick
2633{
2634 // Snoops shouldn't happen when bypassing caches
2635 assert(!cache->system->bypassCaches());
2636
2637 return cache->recvAtomicSnoop(pkt);
2638}
2639
2640void
2642{
2643 // Snoops shouldn't happen when bypassing caches
2644 assert(!cache->system->bypassCaches());
2645
2646 // functional snoop (note that in contrast to atomic we don't have
2647 // a specific functionalSnoop method, as they have the same
2648 // behaviour regardless)
2649 cache->functionalAccess(pkt, false);
2650}
2651
2652void
2654{
2655 // sanity check
2656 assert(!waitingOnRetry);
2657
2658 // there should never be any deferred request packets in the
2659 // queue, instead we resly on the cache to provide the packets
2660 // from the MSHR queue or write queue
2661 assert(deferredPacketReadyTime() == MaxTick);
2662
2663 // check for request packets (requests & writebacks)
2664 QueueEntry* entry = cache.getNextQueueEntry();
2665
2666 if (!entry) {
2667 // can happen if e.g. we attempt a writeback and fail, but
2668 // before the retry, the writeback is eliminated because
2669 // we snoop another cache's ReadEx.
2670 } else {
2671 // let our snoop responses go first if there are responses to
2672 // the same addresses
2673 if (checkConflictingSnoop(entry->getTarget()->pkt)) {
2674 return;
2675 }
2676 waitingOnRetry = entry->sendPacket(cache);
2677 }
2678
2679 // if we succeeded and are not waiting for a retry, schedule the
2680 // next send considering when the next queue is ready, note that
2681 // snoop responses have their own packet queue and thus schedule
2682 // their own events
2683 if (!waitingOnRetry) {
2684 schedSendEvent(cache.nextQueueReadyTime());
2685 }
2686}
2687
2689 BaseCache *_cache,
2690 const std::string &_label)
2691 : CacheRequestPort(_name, _reqQueue, _snoopRespQueue),
2692 _reqQueue(*_cache, *this, _snoopRespQueue, _label),
2693 _snoopRespQueue(*_cache, *this, true, _label), cache(_cache)
2694{
2695}
2696
2697void
2698WriteAllocator::updateMode(Addr write_addr, unsigned write_size,
2699 Addr blk_addr)
2700{
2701 // check if we are continuing where the last write ended
2702 if (nextAddr == write_addr) {
2703 delayCtr[blk_addr] = delayThreshold;
2704 // stop if we have already saturated
2705 if (mode != WriteMode::NO_ALLOCATE) {
2706 byteCount += write_size;
2707 // switch to streaming mode if we have passed the lower
2708 // threshold
2709 if (mode == WriteMode::ALLOCATE &&
2710 byteCount > coalesceLimit) {
2711 mode = WriteMode::COALESCE;
2712 DPRINTF(Cache, "Switched to write coalescing\n");
2713 } else if (mode == WriteMode::COALESCE &&
2714 byteCount > noAllocateLimit) {
2715 // and continue and switch to non-allocating mode if we
2716 // pass the upper threshold
2717 mode = WriteMode::NO_ALLOCATE;
2718 DPRINTF(Cache, "Switched to write-no-allocate\n");
2719 }
2720 }
2721 } else {
2722 // we did not see a write matching the previous one, start
2723 // over again
2724 byteCount = write_size;
2725 mode = WriteMode::ALLOCATE;
2726 resetDelay(blk_addr);
2727 }
2728 nextAddr = write_addr + write_size;
2729}
2730
2731} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
const char data[]
virtual void sendDeferredPacket()
Override the normal sendDeferredPacket and do not only consider the transmit list (used for responses...
Definition base.cc:2653
A cache request port is used for the memory-side port of the cache, and in addition to the basic timi...
Definition base.hh:152
A cache response port is used for the CPU-side port of the cache, and it is basically a simple timing...
Definition base.hh:274
CacheResponsePort(const std::string &_name, BaseCache &_cache, const std::string &_label)
Definition base.cc:69
void clearBlocked()
Return to normal operation and accept new requests.
Definition base.cc:161
EventFunctionWrapper sendRetryEvent
Definition base.hh:304
void setBlocked()
Do not accept any new requests.
Definition base.cc:146
virtual bool recvTimingSnoopResp(PacketPtr pkt) override
Receive a timing snoop response from the peer.
Definition base.cc:2523
virtual Tick recvAtomic(PacketPtr pkt) override
Receive an atomic request packet from the peer.
Definition base.cc:2570
CpuSidePort(const std::string &_name, BaseCache &_cache, const std::string &_label)
Definition base.cc:2602
virtual bool recvTimingReq(PacketPtr pkt) override
Receive a timing request from the peer.
Definition base.cc:2552
virtual bool tryTiming(PacketPtr pkt) override
Availability request from the peer.
Definition base.cc:2537
virtual void recvFunctional(PacketPtr pkt) override
Receive a functional request packet from the peer.
Definition base.cc:2581
virtual AddrRangeList getAddrRanges() const override
Get a list of the non-overlapping address ranges the owner is responsible for.
Definition base.cc:2595
virtual Tick recvAtomicSnoop(PacketPtr pkt)
Receive an atomic snoop request packet from our peer.
Definition base.cc:2632
virtual void recvFunctionalSnoop(PacketPtr pkt)
Receive a functional snoop request packet from the peer.
Definition base.cc:2641
virtual bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
Definition base.cc:2614
virtual void recvTimingSnoopReq(PacketPtr pkt)
Receive a timing snoop request from the peer.
Definition base.cc:2622
MemSidePort(const std::string &_name, BaseCache *_cache, const std::string &_label)
Definition base.cc:2688
A basic cache interface.
Definition base.hh:95
virtual void serviceMSHRTargets(MSHR *mshr, const PacketPtr pkt, CacheBlk *blk)=0
Service non-deferred MSHR targets using the received response.
virtual void functionalAccess(PacketPtr pkt, bool from_cpu_side)
Performs the access specified by the request.
Definition base.cc:715
const bool isReadOnly
Is this cache read only, for example the instruction cache, or table-walker cache.
Definition base.hh:939
virtual void recvTimingReq(PacketPtr pkt)
Performs the access specified by the request.
Definition base.cc:404
virtual void doWritebacks(PacketList &writebacks, Tick forward_time)=0
Insert writebacks into the write buffer.
const Cycles fillLatency
The latency to fill a cache block.
Definition base.hh:906
const Cycles dataLatency
The latency of data access of a cache.
Definition base.hh:896
void invalidateVisitor(CacheBlk &blk)
Cache block visitor that invalidates all blocks in the cache.
Definition base.cc:1837
virtual Cycles handleAtomicReqMiss(PacketPtr pkt, CacheBlk *&blk, PacketList &writebacks)=0
Handle a request in atomic mode that missed in this cache.
ProbePointArg< DataUpdate > * ppDataUpdate
To probe when the contents of a block are updated.
Definition base.hh:368
virtual void doWritebacksAtomic(PacketList &writebacks)=0
Send writebacks down the memory hierarchy in atomic mode.
void updateBlockData(CacheBlk *blk, const PacketPtr cpkt, bool has_old_data)
Update the data contents of a block.
Definition base.cc:771
PacketPtr tempBlockWriteback
Writebacks from the tempBlock, resulting on the response path in atomic mode, must happen after the c...
Definition base.hh:680
MSHR * allocateMissBuffer(PacketPtr pkt, Tick time, bool sched_send=true)
Definition base.hh:1169
CpuSidePort cpuSidePort
Definition base.hh:334
bool isDirty() const
Determine if there are any dirty blocks in the cache.
Definition base.cc:1801
void invalidateBlock(CacheBlk *blk)
Invalidate a cache block.
Definition base.cc:1664
MSHR * noTargetMSHR
Pointer to the MSHR that has no targets.
Definition base.hh:970
const bool writebackClean
Determine if clean lines should be written back or not.
Definition base.hh:671
bool sendWriteQueuePacket(WriteQueueEntry *wq_entry)
Similar to sendMSHR, but for a write-queue entry instead.
Definition base.cc:1970
bool inRange(Addr addr) const
Determine if an address is in the ranges covered by this cache.
Definition base.cc:214
virtual void handleTimingReqMiss(PacketPtr pkt, CacheBlk *blk, Tick forward_time, Tick request_time)=0
bool allocOnFill(MemCmd cmd) const
Determine whether we should allocate on a fill or not.
Definition base.hh:437
bool forwardSnoops
Do we forward snoops from mem side port through to cpu side port?
Definition base.hh:924
uint64_t order
Increasing order number assigned to each incoming request.
Definition base.hh:964
void incHitCount(PacketPtr pkt)
Definition base.hh:1303
virtual void satisfyRequest(PacketPtr pkt, CacheBlk *blk, bool deferred_response=false, bool pending_downgrade=false)
Perform any necessary updates to the block and perform any data exchange between the packet and the b...
Definition base.cc:1089
virtual void memWriteback() override
Write back dirty blocks in the cache using functional accesses.
Definition base.cc:1789
bool updateCompressionData(CacheBlk *&blk, const uint64_t *data, PacketList &writebacks)
When a block is overwriten, its compression information must be updated, and it may need to be recomp...
Definition base.cc:978
bool isBlocked() const
Returns true if the cache is blocked for accesses.
Definition base.hh:1222
gem5::BaseCache::CacheStats stats
ProbePointArg< PacketPtr > * ppFill
To probe when a cache fill occurs.
Definition base.hh:361
const Cycles lookupLatency
The latency of tag lookup of a cache.
Definition base.hh:890
Cycles calculateAccessLatency(const CacheBlk *blk, const uint32_t delay, const Cycles lookup_lat) const
Calculate access latency in ticks given a tag lookup latency, and whether access was a hit or miss.
Definition base.cc:1196
Tick nextQueueReadyTime() const
Find next request ready time from among possible sources.
Definition base.cc:1850
ProbePointArg< PacketPtr > * ppHit
To probe when a cache hit occurs.
Definition base.hh:355
void regProbePoints() override
Registers probes.
Definition base.cc:2508
virtual void memInvalidate() override
Invalidates all blocks in the cache.
Definition base.cc:1795
MSHRQueue mshrQueue
Miss status registers.
Definition base.hh:340
virtual PacketPtr createMissPacket(PacketPtr cpu_pkt, CacheBlk *blk, bool needs_writable, bool is_whole_line_write) const =0
Create an appropriate downstream bus request packet.
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition base.cc:202
QueueEntry * getNextQueueEntry()
Return the next queue entry to service, either a pending miss from the MSHR queue,...
Definition base.cc:850
void handleUncacheableWriteResp(PacketPtr pkt)
Handling the special case of uncacheable write responses to make recvTimingResp less cluttered.
Definition base.cc:477
const unsigned blkSize
Block size of this cache.
Definition base.hh:884
void writebackTempBlockAtomic()
Send the outstanding tempBlock writeback.
Definition base.hh:687
@ NUM_BLOCKED_CAUSES
Definition base.hh:115
@ Blocked_NoTargets
Definition base.hh:114
const Cycles forwardLatency
This is the forward latency of the cache.
Definition base.hh:903
compression::Base * compressor
Compression method being used.
Definition base.hh:349
const Cycles responseLatency
The latency of sending reponse to its upper level cache/core on a linefill.
Definition base.hh:913
PacketPtr writecleanBlk(CacheBlk *blk, Request::Flags dest, PacketId id)
Create a writeclean request for the given block.
Definition base.cc:1743
void schedMemSideSendEvent(Tick time)
Schedule a send event for the memory-side port.
Definition base.hh:1270
ProbePointArg< PacketPtr > * ppMiss
To probe when a cache miss occurs.
Definition base.hh:358
MemSidePort memSidePort
Definition base.hh:335
virtual void handleTimingReqHit(PacketPtr pkt, CacheBlk *blk, Tick request_time)
Definition base.cc:225
virtual Tick recvAtomic(PacketPtr pkt)
Performs the access specified by the request.
Definition base.cc:635
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition base.cc:2014
void cmpAndSwap(CacheBlk *blk, PacketPtr pkt)
Handle doing the Compare and Swap function for SPARC.
Definition base.cc:797
virtual void recvTimingResp(PacketPtr pkt)
Handles a response (cache line fill/write ack) from the bus.
Definition base.cc:489
virtual bool access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat, PacketList &writebacks)
Does all the processing necessary to perform the provided request.
Definition base.cc:1230
void setBlocked(BlockedCause cause)
Marks the access path of the cache as blocked for the given cause.
Definition base.hh:1232
BaseCache(const BaseCacheParams &p, unsigned blk_size)
Definition base.cc:80
Addr regenerateBlkAddr(CacheBlk *blk)
Regenerate block address using tags.
Definition base.cc:183
std::unique_ptr< Packet > pendingDelete
Upstream caches need this packet until true is returned, so hold it for deletion until a subsequent c...
Definition base.hh:398
CacheBlk * allocateBlock(const PacketPtr pkt, PacketList &writebacks)
Allocate a new block and perform any necessary writebacks.
Definition base.cc:1607
prefetch::Base * prefetcher
Prefetcher.
Definition base.hh:352
uint8_t blocked
Bit vector of the blocking reasons for the access path.
Definition base.hh:961
TempCacheBlk * tempBlock
Temporary cache block for occasional transitory use.
Definition base.hh:392
const AddrRangeList addrRanges
The address range to which the cache responds on the CPU side.
Definition base.hh:978
const int numTarget
The number of targets for each MSHR.
Definition base.hh:921
const bool moveContractions
Similar to data expansions, after a block improves its compression, it may need to be moved elsewhere...
Definition base.hh:955
WriteAllocator *const writeAllocator
The writeAllocator drive optimizations for streaming writes.
Definition base.hh:384
void markInService(MSHR *mshr, bool pending_modified_resp)
Mark a request as in service (sent downstream in the memory system), effectively making this MSHR the...
Definition base.hh:404
void allocateWriteBuffer(PacketPtr pkt, Tick time)
Definition base.hh:1187
Cycles calculateTagOnlyLatency(const uint32_t delay, const Cycles lookup_lat) const
Calculate latency of accesses that only touch the tag array.
Definition base.cc:1187
CacheBlk * handleFill(PacketPtr pkt, CacheBlk *blk, PacketList &writebacks, bool allocate)
Handle a fill operation caused by a received packet.
Definition base.cc:1511
void incMissCount(PacketPtr pkt)
Definition base.hh:1292
WriteQueue writeBuffer
Write/writeback buffer.
Definition base.hh:343
const bool replaceExpansions
when a data expansion of a compressed block happens it will not be able to co-allocate where it is at...
Definition base.hh:947
void serialize(CheckpointOut &cp) const override
Serialize the state of the caches.
Definition base.cc:1994
bool coalesce() const
Checks if the cache is coalescing writes.
Definition base.cc:1808
const bool sequentialAccess
Whether tags and data are accessed sequentially.
Definition base.hh:918
bool handleEvictions(std::vector< CacheBlk * > &evict_blks, PacketList &writebacks)
Try to evict the given blocks.
Definition base.cc:941
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition base.cc:193
PacketPtr writebackBlk(CacheBlk *blk)
Create a writeback request for the given block.
Definition base.cc:1693
void clearBlocked(BlockedCause cause)
Marks the cache as unblocked for the given cause.
Definition base.hh:1251
virtual PacketPtr evictBlock(CacheBlk *blk)=0
Evict a cache block.
void writebackVisitor(CacheBlk &blk)
Cache block visitor that writes back dirty cache blocks using functional writes.
Definition base.cc:1814
EventFunctionWrapper writebackTempBlockAtomicEvent
An event to writeback the tempBlock after recvAtomic finishes.
Definition base.hh:699
BaseTags * tags
Tag and data Storage.
Definition base.hh:346
const enums::Clusivity clusivity
Clusivity with respect to the upstream cache, determining if we fill into both this cache and the cac...
Definition base.hh:931
virtual bool sendMSHRQueuePacket(MSHR *mshr)
Take an MSHR, turn it into a suitable downstream packet, and send it out.
Definition base.cc:1867
void maintainClusivity(bool from_cache, CacheBlk *blk)
Maintain the clusivity of this cache by potentially invalidating a block.
Definition base.cc:1499
System * system
System we are currently operating in.
Definition base.hh:982
virtual CacheBlk * findVictim(Addr addr, const bool is_secure, const std::size_t size, std::vector< CacheBlk * > &evict_blks)=0
Find replacement victim based on address.
virtual void insertBlock(const PacketPtr pkt, CacheBlk *blk)
Insert the new block into the cache and update stats.
Definition base.cc:102
int extractBlkOffset(Addr addr) const
Calculate the block offset of an address.
Definition base.hh:225
virtual CacheBlk * findBlock(Addr addr, bool is_secure) const
Finds the block in the cache without touching it.
Definition base.cc:80
virtual Addr regenerateBlkAddr(const CacheBlk *blk) const =0
Regenerate the block address.
virtual void forEachBlk(std::function< void(CacheBlk &)> visitor)=0
Visit each block in the tags and apply a visitor.
virtual bool anyBlk(std::function< bool(CacheBlk &)> visitor)=0
Find if any of the blocks satisfies a condition.
virtual void invalidate(CacheBlk *blk)
This function updates the tags when a block is invalidated.
Definition base.hh:254
virtual void moveBlock(CacheBlk *src_blk, CacheBlk *dest_blk)
Move a block's metadata to another location decided by the replacement policy.
Definition base.cc:130
virtual CacheBlk * accessBlock(const PacketPtr pkt, Cycles &lat)=0
Access block and update replacement data.
Simple class to provide virtual print() method on cache blocks without allocating a vtable pointer fo...
Definition cache_blk.hh:555
A Basic Cache block.
Definition cache_blk.hh:71
void setWhenReady(const Tick tick)
Set tick at which block's data will be available for access.
Definition cache_blk.hh:278
@ ReadableBit
Read permission.
Definition cache_blk.hh:85
@ WritableBit
write permission
Definition cache_blk.hh:80
@ DirtyBit
dirty (modified)
Definition cache_blk.hh:87
Tick getWhenReady() const
Get tick at which block's data will be available for access.
Definition cache_blk.hh:265
void clearPrefetched()
Clear the prefetching bit.
Definition cache_blk.hh:255
std::string print() const override
Pretty-print tag, set and way, and interpret state bits to readable form including mapping to a MOESI...
Definition cache_blk.hh:364
bool isSet(unsigned bits) const
Checks the given coherence bits are set.
Definition cache_blk.hh:239
bool checkWrite(PacketPtr pkt)
Handle interaction of load-locked operations and stores.
Definition cache_blk.hh:412
void clearCoherenceBits(unsigned bits)
Clear the corresponding coherence bits.
Definition cache_blk.hh:231
uint32_t getTaskId() const
Get the task id associated to this block.
Definition cache_blk.hh:285
void trackLoadLocked(PacketPtr pkt)
Track the fact that a local locked was issued to the block.
Definition cache_blk.hh:327
bool wasPrefetched() const
Check if this block was the result of a hardware prefetch, yet to be touched.
Definition cache_blk.hh:249
uint8_t * data
Contains a copy of the data in this block for easy access.
Definition cache_blk.hh:103
void setCoherenceBits(unsigned bits)
Sets the corresponding coherence bits.
Definition cache_blk.hh:220
A coherent cache that can be arranged in flexible topologies.
Definition cache.hh:68
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
Tick cyclesToTicks(Cycles c) const
Tick clockPeriod() const
Cycles ticksToCycles(Tick t) const
A CompressedTags cache tag store.
A superblock is composed of sub-blocks, and each sub-block has information regarding its superblock a...
Definition super_blk.hh:52
std::size_t getSizeBits() const
Definition super_blk.cc:93
void setSizeBits(const std::size_t size)
Set size, in bits, of this compressed block's data.
Definition super_blk.cc:99
void setDecompressionLatency(const Cycles lat)
Set number of cycles needed to decompress this block.
Definition super_blk.cc:135
OverwriteType
When an overwrite happens, the data size may change an not fit in its current container any longer.
Definition super_blk.hh:75
@ DATA_EXPANSION
New data contents are considered larger than previous contents.
Definition super_blk.hh:81
@ DATA_CONTRACTION
New data contents are considered smaller than previous contents.
Definition super_blk.hh:77
OverwriteType checkExpansionContraction(const std::size_t size) const
Determines if changing the size of the block will cause a data expansion (new size is bigger) or cont...
Definition super_blk.cc:148
Cycles is a wrapper class for representing cycle counts, i.e.
Definition types.hh:79
void delay(MSHR *mshr, Tick delay_ticks)
Adds a delay to the provided MSHR and moves MSHRs that will be ready earlier than this entry to the t...
void deallocate(MSHR *mshr) override
Deallocate a MSHR and its targets.
Definition mshr_queue.cc:83
bool canPrefetch() const
Returns true if sufficient mshrs for prefetch.
void markPending(MSHR *mshr)
Mark an in service entry as pending, used to resend a request.
void markInService(MSHR *mshr, bool pending_modified_resp)
Mark the given MSHR as in service.
Miss Status and handling Register.
Definition mshr.hh:75
bool wasWholeLineWrite
Track if we sent this as a whole line write or not.
Definition mshr.hh:124
bool isPendingModified() const
Definition mshr.hh:326
void promoteReadable()
Promotes deferred targets that do not require writable.
Definition mshr.cc:659
bool isCleaning() const
Definition mshr.hh:321
int getNumTargets() const
Returns the current number of allocated targets.
Definition mshr.hh:446
QueueEntry::Target * getTarget() override
Returns a reference to the first target.
Definition mshr.hh:473
bool needsWritable() const
The pending* and post* flags are only valid if inService is true.
Definition mshr.hh:319
bool isForward
True if the entry is just a simple forward from an upper level.
Definition mshr.hh:127
bool hasLockedRMWReadTarget()
Determine if there are any LockedRMWReads in the Targets list.
Definition mshr.cc:794
bool promoteDeferredTargets()
Definition mshr.cc:597
bool isWholeLineWrite() const
Check if this MSHR contains only compatible writes, and if they span the entire cache line.
Definition mshr.hh:406
void allocateTarget(PacketPtr target, Tick when, Counter order, bool alloc_on_fill)
Add a request to the list of targets.
Definition mshr.cc:377
void promoteWritable()
Promotes deferred targets that do not require writable.
Definition mshr.cc:680
bool allocOnFill() const
Definition mshr.hh:340
@ WritebackDirty
Definition packet.hh:93
@ LockedRMWWriteReq
Definition packet.hh:118
@ WritebackClean
Definition packet.hh:94
@ LockedRMWWriteResp
Definition packet.hh:119
const std::string _name
Definition named.hh:41
virtual std::string name() const
Definition named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
bool isUpgrade() const
Definition packet.hh:596
bool isRead() const
Definition packet.hh:593
bool isSecure() const
Definition packet.hh:836
const PacketId id
Definition packet.hh:374
void writeDataToBlock(uint8_t *blk_data, int blkSize) const
Copy data from the packet to the provided block pointer, which is aligned to the given block size.
Definition packet.hh:1346
Addr getAddr() const
Definition packet.hh:807
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition packet.hh:1461
bool isError() const
Definition packet.hh:622
bool isLockedRMW() const
Definition packet.hh:621
void setWriteThrough()
A writeback/writeclean cmd gets propagated further downstream by the receiver when the flag is set.
Definition packet.hh:735
bool isAtomicOp() const
Definition packet.hh:846
bool isResponse() const
Definition packet.hh:598
void makeTimingResponse()
Definition packet.hh:1080
bool needsWritable() const
Definition packet.hh:599
void print(std::ostream &o, int verbosity=0, const std::string &prefix="") const
Definition packet.cc:368
bool isDemand() const
Definition packet.hh:595
bool isCleanEviction() const
Is this packet a clean eviction, including both actual clean evict packets, but also clean writebacks...
Definition packet.hh:1435
bool needsResponse() const
Definition packet.hh:608
void dataStatic(T *p)
Set the data pointer to the following value that should not be freed.
Definition packet.hh:1175
SenderState * senderState
This packet's sender state.
Definition packet.hh:545
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition packet.hh:449
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
Definition packet.hh:1062
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition packet.hh:431
Addr getOffset(unsigned int blk_size) const
Definition packet.hh:826
void clearBlockCached()
Definition packet.hh:761
void pushSenderState(SenderState *sender_state)
Push a new sender state to the packet and make the current sender state the predecessor of the new on...
Definition packet.cc:334
bool hasData() const
Definition packet.hh:614
SenderState * popSenderState()
Pop the top of the state stack and return a pointer to it.
Definition packet.cc:342
bool hasRespData() const
Definition packet.hh:615
bool writeThrough() const
Definition packet.hh:742
bool fromCache() const
Definition packet.hh:612
void setData(const uint8_t *p)
Copy data into the packet from the provided pointer.
Definition packet.hh:1293
bool isWrite() const
Definition packet.hh:594
void setDataFromBlock(const uint8_t *blk_data, int blkSize)
Copy data into the packet from the provided block pointer, which is aligned to the given block size.
Definition packet.hh:1312
bool trySatisfyFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
Definition packet.hh:1399
Addr getBlockAddr(unsigned int blk_size) const
Definition packet.hh:831
RequestPtr req
A pointer to the original request.
Definition packet.hh:377
unsigned getSize() const
Definition packet.hh:817
AtomicOpFunctor * getAtomicOp() const
Accessor function to atomic op.
Definition packet.hh:845
void setCacheResponding()
Snoop flags.
Definition packet.hh:653
bool isClean() const
Definition packet.hh:611
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition packet.hh:1471
bool isExpressSnoop() const
Definition packet.hh:702
bool isWriteback() const
Definition packet.hh:613
const T * getConstPtr() const
Definition packet.hh:1234
void setHasSharers()
On fills, the hasSharers flag is used by the caches in combination with the cacheResponding flag,...
Definition packet.hh:685
bool isLLSC() const
Definition packet.hh:620
bool cacheResponding() const
Definition packet.hh:659
void makeAtomicResponse()
Definition packet.hh:1074
void setSatisfied()
Set when a request hits in a cache and the cache is not going to respond.
Definition packet.hh:749
MemCmd cmd
The command field of the packet.
Definition packet.hh:372
bool isInvalidate() const
Definition packet.hh:609
void writeData(uint8_t *p) const
Copy data from the packet to the memory at the provided pointer.
Definition packet.hh:1322
bool hasSharers() const
Definition packet.hh:686
void allocate()
Allocate memory for the packet.
Definition packet.hh:1367
bool isEviction() const
Definition packet.hh:610
bool isRequest() const
Definition packet.hh:597
Ports are used to interface objects to each other.
Definition port.hh:62
bool isConnected() const
Is this port currently connected to a peer?
Definition port.hh:133
ProbePointArg generates a point for the class of Arg.
Definition probe.hh:263
A queue entry is holding packets that will be serviced as soon as resources are available.
const Tick recvTime
Time when request was received (for stats)
PacketPtr pkt
Pending request packet.
A queue entry base class, to be used by both the MSHRs and write-queue entries.
virtual bool sendPacket(BaseCache &cache)=0
Send this queue entry as a downstream packet, with the exact behaviour depending on the specific entr...
virtual Target * getTarget()=0
Returns a pointer to the first target.
Addr blkAddr
Block aligned address.
Counter order
Order number assigned to disambiguate writes and misses.
bool inService
True if the entry has been sent downstream.
bool isSecure
True if the entry targets the secure memory space.
Entry * findMatch(Addr blk_addr, bool is_secure, bool ignore_uncacheable=true) const
Find the first entry that matches the provided address.
Definition queue.hh:168
Entry * findPending(const QueueEntry *entry) const
Find any pending requests that overlap the given request of a different queue.
Definition queue.hh:207
bool isFull() const
Definition queue.hh:150
bool trySatisfyFunctional(PacketPtr pkt)
Definition queue.hh:186
Tick nextReadyTime() const
Definition queue.hh:229
Entry * getNext() const
Returns the WriteQueueEntry at the head of the readyList.
Definition queue.hh:221
bool trySatisfyFunctional(PacketPtr pkt)
Check the list of buffered packets against the supplied functional request.
Definition qport.hh:164
A queued port is a port that has an infinite queue for outgoing packets and thus decouples the module...
Definition qport.hh:62
bool trySatisfyFunctional(PacketPtr pkt)
Check the list of buffered packets against the supplied functional request.
Definition qport.hh:99
void schedTimingResp(PacketPtr pkt, Tick when)
Schedule the sending of a timing response.
Definition qport.hh:94
bool sendTimingReq(PacketPtr pkt)
Attempt to send a timing request to the responder port by calling its corresponding receive function.
Definition port.hh:530
void sendFunctional(PacketPtr pkt) const
Send a functional request packet, where the data is instantly updated everywhere in the memory system...
Definition port.hh:508
@ SECURE
The request targets the secure memory space.
Definition request.hh:186
@ funcRequestorId
This requestor id is used for functional requests that don't come from a particular device.
Definition request.hh:279
@ wbRequestorId
This requestor id is used for writeback requests by the caches.
Definition request.hh:274
void sendFunctionalSnoop(PacketPtr pkt) const
Send a functional snoop request packet, where the data is instantly updated everywhere in the memory ...
Definition port.hh:369
bool isSnooping() const
Find out if the peer request port is snooping or not.
Definition port.hh:314
void sendRangeChange() const
Called by the owner to send a range change.
Definition port.hh:319
std::vector< SectorSubBlk * > blks
List of blocks associated to this sector.
SectorBlk * getSectorBlock() const
Get sector block associated to this block.
Definition sector_blk.cc:52
A basic compression superblock.
Definition super_blk.hh:171
std::string getRequestorName(RequestorID requestor_id)
Get the name of an object for a given request id.
Definition system.cc:526
RequestorID maxRequestors()
Get the number of requestors registered in the system.
Definition system.hh:495
virtual bool isValid() const
Checks if the entry is valid.
bool isSecure() const
Check if this block holds data from the secure memory space.
Special instance of CacheBlk for use with tempBlk that deals with its block address regeneration.
Definition cache_blk.hh:501
void insert(const Addr addr, const bool is_secure) override
Insert the block by assigning it a tag and marking it valid.
Definition cache_blk.hh:531
Addr getAddr() const
Get block's address.
Definition cache_blk.hh:542
void invalidate() override
Invalidate the block and clear all state.
Definition cache_blk.hh:524
bool coalesce() const
Should writes be coalesced? This is true if the mode is set to NO_ALLOCATE.
Definition base.hh:1392
bool delay(Addr blk_addr)
Access whether we need to delay the current write.
Definition base.hh:1423
void reset()
Reset the write allocator state, meaning that it allocates for writes and has not recorded any inform...
Definition base.hh:1411
bool allocate() const
Should writes allocate?
Definition base.hh:1401
void updateMode(Addr write_addr, unsigned write_size, Addr blk_addr)
Update the write mode based on the current write packet.
Definition base.cc:2698
void resetDelay(Addr blk_addr)
Clear delay counter for the input block.
Definition base.hh:1437
int getNumTargets() const
Returns the current number of allocated targets.
Target * getTarget() override
Returns a reference to the first target.
Cycles getDecompressionLatency(const CacheBlk *blk)
Get the decompression latency if the block is compressed.
Definition base.cc:196
static void setSizeBits(CacheBlk *blk, const std::size_t size_bits)
Set the size of the compressed block, in bits.
Definition base.cc:224
static void setDecompressionLatency(CacheBlk *blk, const Cycles lat)
Set the decompression latency of compressed block.
Definition base.cc:214
virtual std::unique_ptr< CompressionData > compress(const std::vector< Chunk > &chunks, Cycles &comp_lat, Cycles &decomp_lat)=0
Apply the compression process to the cache line.
void incrDemandMhsrMisses()
Definition base.hh:396
void pfHitInCache()
Definition base.hh:402
virtual PacketPtr getPacket()=0
void prefetchUnused()
Definition base.hh:390
virtual Tick nextPrefetchReadyTime() const =0
Statistics container.
Definition group.hh:93
STL list class.
Definition stl.hh:51
STL vector class.
Definition stl.hh:37
Declaration of a compressed set associative tag store using superblocks.
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition group.hh:75
static const Priority Delayed_Writeback_Pri
For some reason "delayed" inter-cluster writebacks are scheduled before regular writebacks (which hav...
Definition eventq.hh:175
void deschedule(Event &event)
Definition eventq.hh:1021
bool scheduled() const
Determine if the current event is scheduled.
Definition eventq.hh:458
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition logging.hh:236
#define gem5_assert(cond,...)
The assert macro will function like a normal assert, but will use panic instead of straight abort().
Definition logging.hh:317
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
ProbeManager * getProbeManager()
Get the probe manager for this object.
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
virtual void regStats()
Callback to set stat parameters.
Definition group.cc:68
#define warn(...)
Definition logging.hh:256
#define warn_once(...)
Definition logging.hh:260
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition logging.hh:283
#define SUM_DEMAND(s)
#define SUM_NON_DEMAND(s)
Declares a basic cache interface BaseCache.
Definition of a basic cache compressor.
Miss and writeback queue declarations.
Miss Status and Handling Register (MSHR) declaration.
Bitfield< 4, 0 > mode
Definition misc_types.hh:74
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 29 > c
Definition misc_types.hh:53
Bitfield< 0 > p
Bitfield< 15 > system
Definition misc.hh:1004
Bitfield< 3 > addr
Definition types.hh:84
const FlagsType nonan
Don't print if this is NAN.
Definition info.hh:69
const FlagsType nozero
Don't print if this is zero.
Definition info.hh:67
const FlagsType total
Print the total.
Definition info.hh:59
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
std::shared_ptr< Request > RequestPtr
Definition request.hh:94
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
std::ostream CheckpointOut
Definition serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition types.hh:245
uint64_t Tick
Tick count type.
Definition types.hh:58
uint64_t PacketId
Definition packet.hh:74
const Tick MaxTick
Definition types.hh:60
Generic queue entry.
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568
void regStatsFromParent()
Callback to register stats from parent CacheStats::regStats().
Definition base.cc:2066
statistics::Vector mshrUncacheableLatency
Total tick latency of each MSHR miss, per command and thread.
Definition base.hh:1029
statistics::Vector mshrHits
Number of misses that hit in the MSHRs per command and thread.
Definition base.hh:1021
CacheCmdStats(BaseCache &c, const std::string &name)
Definition base.cc:2026
statistics::Vector mshrMisses
Number of misses that miss in the MSHRs, per command and thread.
Definition base.hh:1023
statistics::Vector mshrMissLatency
Total tick latency of each MSHR miss, per command and thread.
Definition base.hh:1027
statistics::Scalar replacements
Number of replacements of valid blocks.
Definition base.hh:1130
statistics::Scalar dataContractions
Number of data contractions (blocks that had their compression factor improved).
Definition base.hh:1139
CacheStats(BaseCache &c)
Definition base.cc:2199
void regStats() override
Callback to set stat parameters.
Definition base.cc:2283
statistics::Scalar dataExpansions
Number of data expansions.
Definition base.hh:1133
std::vector< std::unique_ptr< CacheCmdStats > > cmd
Per-command statistics.
Definition base.hh:1142
statistics::Vector writebacks
Number of blocks written back per thread.
Definition base.hh:1093
CacheCmdStats & cmdStats(const PacketPtr p)
Definition base.hh:1044
A data contents update is composed of the updated block's address, the old contents,...
Definition base.hh:124
std::vector< uint64_t > newData
The new data contents.
Definition base.hh:132
std::vector< uint64_t > oldData
The stale data contents.
Definition base.hh:130
Copyright (c) 2018 Inria All rights reserved.
const std::string & name()
Definition trace.cc:48

Generated on Mon Jul 10 2023 15:32:01 for gem5 by doxygen 1.9.7