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

Generated on Tue Jun 18 2024 16:24:01 for gem5 by doxygen 1.11.0