gem5 v24.0.0.0
Loading...
Searching...
No Matches
coherent_xbar.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011-2020 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) 2006 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/coherent_xbar.hh"
47
48#include "base/compiler.hh"
49#include "base/logging.hh"
50#include "base/trace.hh"
51#include "debug/AddrRanges.hh"
52#include "debug/CoherentXBar.hh"
53#include "sim/system.hh"
54
55namespace gem5
56{
57
58CoherentXBar::CoherentXBar(const CoherentXBarParams &p)
59 : BaseXBar(p), system(p.system), snoopFilter(p.snoop_filter),
60 snoopResponseLatency(p.snoop_response_latency),
61 maxOutstandingSnoopCheck(p.max_outstanding_snoops),
62 maxRoutingTableSizeCheck(p.max_routing_table_size),
63 pointOfCoherency(p.point_of_coherency),
64 pointOfUnification(p.point_of_unification),
65
66 ADD_STAT(snoops, statistics::units::Count::get(), "Total snoops"),
67 ADD_STAT(snoopTraffic, statistics::units::Byte::get(), "Total snoop traffic"),
68 ADD_STAT(snoopFanout, statistics::units::Count::get(),
69 "Request fanout histogram")
70{
71 // create the ports based on the size of the memory-side port and
72 // CPU-side port vector ports, and the presence of the default port,
73 // the ports are enumerated starting from zero
74 for (int i = 0; i < p.port_mem_side_ports_connection_count; ++i) {
75 std::string portName = csprintf("%s.mem_side_port[%d]", name(), i);
76 RequestPort* bp = new CoherentXBarRequestPort(portName, *this, i);
77 memSidePorts.push_back(bp);
78 reqLayers.push_back(new ReqLayer(*bp, *this,
79 csprintf("reqLayer%d", i)));
80 snoopLayers.push_back(
81 new SnoopRespLayer(*bp, *this, csprintf("snoopLayer%d", i)));
82 }
83
84 // see if we have a default CPU-side-port device connected and if so add
85 // our corresponding memory-side port
86 if (p.port_default_connection_count) {
88 std::string portName = name() + ".default";
89 RequestPort* bp = new CoherentXBarRequestPort(portName, *this,
91 memSidePorts.push_back(bp);
92 reqLayers.push_back(new ReqLayer(*bp, *this, csprintf("reqLayer%d",
94 snoopLayers.push_back(new SnoopRespLayer(*bp, *this,
95 csprintf("snoopLayer%d",
97 }
98
99 // create the CPU-side ports, once again starting at zero
100 for (int i = 0; i < p.port_cpu_side_ports_connection_count; ++i) {
101 std::string portName = csprintf("%s.cpu_side_port[%d]", name(), i);
103 *this, i);
104 cpuSidePorts.push_back(bp);
105 respLayers.push_back(new RespLayer(*bp, *this,
106 csprintf("respLayer%d", i)));
107 snoopRespPorts.push_back(new SnoopRespPort(*bp, *this));
108 }
109}
110
112{
113 for (auto l: reqLayers)
114 delete l;
115 for (auto l: respLayers)
116 delete l;
117 for (auto l: snoopLayers)
118 delete l;
119 for (auto p: snoopRespPorts)
120 delete p;
121}
122
123void
125{
127
128 // iterate over our CPU-side ports and determine which of our
129 // neighbouring memory-side ports are snooping and add them as snoopers
130 for (const auto& p: cpuSidePorts) {
131 // check if the connected memory-side port is snooping
132 if (p->isSnooping()) {
133 DPRINTF(AddrRanges, "Adding snooping requestor %s\n",
134 p->getPeer());
135 snoopPorts.push_back(p);
136 }
137 }
138
139 if (snoopPorts.empty())
140 warn("CoherentXBar %s has no snooping ports attached!\n", name());
141
142 // inform the snoop filter about the CPU-side ports so it can create
143 // its own internal representation
144 if (snoopFilter)
146}
147
148bool
150{
151 // determine the source port based on the id
152 ResponsePort *src_port = cpuSidePorts[cpu_side_port_id];
153
154 // remember if the packet is an express snoop
155 bool is_express_snoop = pkt->isExpressSnoop();
156 bool cache_responding = pkt->cacheResponding();
157 // for normal requests, going downstream, the express snoop flag
158 // and the cache responding flag should always be the same
159 assert(is_express_snoop == cache_responding);
160
161 // determine the destination based on the destination address range
162 PortID mem_side_port_id = findPort(pkt);
163
164 // test if the crossbar should be considered occupied for the current
165 // port, and exclude express snoops from the check
166 if (!is_express_snoop &&
167 !reqLayers[mem_side_port_id]->tryTiming(src_port)) {
168 DPRINTF(CoherentXBar, "%s: src %s packet %s BUSY\n", __func__,
169 src_port->name(), pkt->print());
170 return false;
171 }
172
173 DPRINTF(CoherentXBar, "%s: src %s packet %s\n", __func__,
174 src_port->name(), pkt->print());
175
176 // store size and command as they might be modified when
177 // forwarding the packet
178 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
179 unsigned int pkt_cmd = pkt->cmdToIndex();
180
181 // store the old header delay so we can restore it if needed
182 Tick old_header_delay = pkt->headerDelay;
183
184 // a request sees the frontend and forward latency
185 Tick xbar_delay = (frontendLatency + forwardLatency) * clockPeriod();
186
187 // set the packet header and payload delay
188 calcPacketTiming(pkt, xbar_delay);
189
190 // determine how long to be crossbar layer is busy
191 Tick packetFinishTime = clockEdge(headerLatency) + pkt->payloadDelay;
192
193 // is this the destination point for this packet? (e.g. true if
194 // this xbar is the PoC for a cache maintenance operation to the
195 // PoC) otherwise the destination is any cache that can satisfy
196 // the request
197 const bool is_destination = isDestination(pkt);
198
199 const bool snoop_caches = !system->bypassCaches() &&
200 pkt->cmd != MemCmd::WriteClean;
201 if (snoop_caches) {
202 assert(pkt->snoopDelay == 0);
203
204 if (pkt->isClean() && !is_destination) {
205 // before snooping we need to make sure that the memory
206 // below is not busy and the cache clean request can be
207 // forwarded to it
208 if (!memSidePorts[mem_side_port_id]->tryTiming(pkt)) {
209 DPRINTF(CoherentXBar, "%s: src %s packet %s RETRY\n", __func__,
210 src_port->name(), pkt->print());
211
212 // update the layer state and schedule an idle event
213 reqLayers[mem_side_port_id]->failedTiming(src_port,
214 clockEdge(Cycles(1)));
215 return false;
216 }
217 }
218
219
220 // the packet is a memory-mapped request and should be
221 // broadcasted to our snoopers but the source
222 if (snoopFilter) {
223 // check with the snoop filter where to forward this packet
224 auto sf_res = snoopFilter->lookupRequest(pkt, *src_port);
225 // the time required by a packet to be delivered through
226 // the xbar has to be charged also with to lookup latency
227 // of the snoop filter
228 pkt->headerDelay += sf_res.second * clockPeriod();
229 DPRINTF(CoherentXBar, "%s: src %s packet %s SF size: %i lat: %i\n",
230 __func__, src_port->name(), pkt->print(),
231 sf_res.first.size(), sf_res.second);
232
233 if (pkt->isEviction()) {
234 // for block-evicting packets, i.e. writebacks and
235 // clean evictions, there is no need to snoop up, as
236 // all we do is determine if the block is cached or
237 // not, instead just set it here based on the snoop
238 // filter result
239 if (!sf_res.first.empty())
240 pkt->setBlockCached();
241 } else {
242 forwardTiming(pkt, cpu_side_port_id, sf_res.first);
243 }
244 } else {
245 forwardTiming(pkt, cpu_side_port_id);
246 }
247
248 // add the snoop delay to our header delay, and then reset it
249 pkt->headerDelay += pkt->snoopDelay;
250 pkt->snoopDelay = 0;
251 }
252
253 // set up a sensible starting point
254 bool success = true;
255
256 // remember if the packet will generate a snoop response by
257 // checking if a cache set the cacheResponding flag during the
258 // snooping above
259 const bool expect_snoop_resp = !cache_responding && pkt->cacheResponding();
260 bool expect_response = pkt->needsResponse() && !pkt->cacheResponding();
261
262 const bool sink_packet = sinkPacket(pkt);
263
264 // in certain cases the crossbar is responsible for responding
265 bool respond_directly = false;
266 // store the original address as an address mapper could possibly
267 // modify the address upon a sendTimingRequest
268 const Addr addr(pkt->getAddr());
269 if (sink_packet) {
270 DPRINTF(CoherentXBar, "%s: Not forwarding %s\n", __func__,
271 pkt->print());
272 } else {
273 // determine if we are forwarding the packet, or responding to
274 // it
275 if (forwardPacket(pkt)) {
276 // if we are passing on, rather than sinking, a packet to
277 // which an upstream cache has committed to responding,
278 // the line was needs writable, and the responding only
279 // had an Owned copy, so we need to immidiately let the
280 // downstream caches know, bypass any flow control
281 if (pkt->cacheResponding()) {
282 pkt->setExpressSnoop();
283 }
284
285 // make sure that the write request (e.g., WriteClean)
286 // will stop at the memory below if this crossbar is its
287 // destination
288 if (pkt->isWrite() && is_destination) {
289 pkt->clearWriteThrough();
290 }
291
292 // since it is a normal request, attempt to send the packet
293 success = memSidePorts[mem_side_port_id]->sendTimingReq(pkt);
294 } else {
295 // no need to forward, turn this packet around and respond
296 // directly
297 assert(pkt->needsResponse());
298
299 respond_directly = true;
300 assert(!expect_snoop_resp);
301 expect_response = false;
302 }
303 }
304
305 if (snoopFilter && snoop_caches) {
306 // Let the snoop filter know about the success of the send operation
307 snoopFilter->finishRequest(!success, addr, pkt->isSecure());
308 }
309
310 // check if we were successful in sending the packet onwards
311 if (!success) {
312 // express snoops should never be forced to retry
313 assert(!is_express_snoop);
314
315 // restore the header delay
316 pkt->headerDelay = old_header_delay;
317
318 DPRINTF(CoherentXBar, "%s: src %s packet %s RETRY\n", __func__,
319 src_port->name(), pkt->print());
320
321 // update the layer state and schedule an idle event
322 reqLayers[mem_side_port_id]->failedTiming(src_port,
323 clockEdge(Cycles(1)));
324 } else {
325 // express snoops currently bypass the crossbar state entirely
326 if (!is_express_snoop) {
327 // if this particular request will generate a snoop
328 // response
329 if (expect_snoop_resp) {
330 // we should never have an exsiting request outstanding
331 assert(outstandingSnoop.find(pkt->req) ==
332 outstandingSnoop.end());
333 outstandingSnoop.insert(pkt->req);
334
335 // basic sanity check on the outstanding snoops
337 "%s: Outstanding snoop requests exceeded %d\n",
339 }
340
341 // remember where to route the normal response to
342 if (expect_response || expect_snoop_resp) {
343 assert(routeTo.find(pkt->req) == routeTo.end());
344 routeTo[pkt->req] = cpu_side_port_id;
345
347 "%s: Routing table exceeds %d packets\n",
349 }
350
351 // update the layer state and schedule an idle event
352 reqLayers[mem_side_port_id]->succeededTiming(packetFinishTime);
353 }
354
355 // stats updates only consider packets that were successfully sent
356 pktCount[cpu_side_port_id][mem_side_port_id]++;
357 pktSize[cpu_side_port_id][mem_side_port_id] += pkt_size;
358 transDist[pkt_cmd]++;
359
360 if (is_express_snoop) {
361 snoops++;
362 snoopTraffic += pkt_size;
363 }
364 }
365
366 if (sink_packet)
367 // queue the packet for deletion
368 pendingDelete.reset(pkt);
369
370 // normally we respond to the packet we just received if we need to
371 PacketPtr rsp_pkt = pkt;
372 PortID rsp_port_id = cpu_side_port_id;
373
374 // If this is the destination of the cache clean operation the
375 // crossbar is responsible for responding. This crossbar will
376 // respond when the cache clean is complete. A cache clean
377 // is complete either:
378 // * direcly, if no cache above had a dirty copy of the block
379 // as indicated by the satisfied flag of the packet, or
380 // * when the crossbar has seen both the cache clean request
381 // (CleanSharedReq, CleanInvalidReq) and the corresponding
382 // write (WriteClean) which updates the block in the memory
383 // below.
384 if (success &&
385 ((pkt->isClean() && pkt->satisfied()) ||
386 pkt->cmd == MemCmd::WriteClean) &&
387 is_destination) {
388 PacketPtr deferred_rsp = pkt->isWrite() ? nullptr : pkt;
389 auto cmo_lookup = outstandingCMO.find(pkt->id);
390 if (cmo_lookup != outstandingCMO.end()) {
391 // the cache clean request has already reached this xbar
392 respond_directly = true;
393 if (pkt->isWrite()) {
394 rsp_pkt = cmo_lookup->second;
395 assert(rsp_pkt);
396
397 // determine the destination
398 const auto route_lookup = routeTo.find(rsp_pkt->req);
399 assert(route_lookup != routeTo.end());
400 rsp_port_id = route_lookup->second;
401 assert(rsp_port_id != InvalidPortID);
402 assert(rsp_port_id < respLayers.size());
403 // remove the request from the routing table
404 routeTo.erase(route_lookup);
405 }
406 outstandingCMO.erase(cmo_lookup);
407 } else {
408 respond_directly = false;
409 outstandingCMO.emplace(pkt->id, deferred_rsp);
410 if (!pkt->isWrite()) {
411 assert(routeTo.find(pkt->req) == routeTo.end());
412 routeTo[pkt->req] = cpu_side_port_id;
413
415 "%s: Routing table exceeds %d packets\n",
417 }
418 }
419 }
420
421
422 if (respond_directly) {
423 assert(rsp_pkt->needsResponse());
424 assert(success);
425
426 rsp_pkt->makeResponse();
427
428 if (snoopFilter && !system->bypassCaches()) {
429 // let the snoop filter inspect the response and update its state
430 snoopFilter->updateResponse(rsp_pkt, *cpuSidePorts[rsp_port_id]);
431 }
432
433 // we send the response after the current packet, even if the
434 // response is not for this packet (e.g. cache clean operation
435 // where both the request and the write packet have to cross
436 // the destination xbar before the response is sent.)
437 Tick response_time = clockEdge() + pkt->headerDelay;
438 rsp_pkt->headerDelay = 0;
439
440 cpuSidePorts[rsp_port_id]->schedTimingResp(rsp_pkt, response_time);
441 }
442
443 return success;
444}
445
446bool
448{
449 // determine the source port based on the id
450 RequestPort *src_port = memSidePorts[mem_side_port_id];
451
452 // determine the destination
453 const auto route_lookup = routeTo.find(pkt->req);
454 assert(route_lookup != routeTo.end());
455 const PortID cpu_side_port_id = route_lookup->second;
456 assert(cpu_side_port_id != InvalidPortID);
457 assert(cpu_side_port_id < respLayers.size());
458
459 // test if the crossbar should be considered occupied for the
460 // current port
461 if (!respLayers[cpu_side_port_id]->tryTiming(src_port)) {
462 DPRINTF(CoherentXBar, "%s: src %s packet %s BUSY\n", __func__,
463 src_port->name(), pkt->print());
464 return false;
465 }
466
467 DPRINTF(CoherentXBar, "%s: src %s packet %s\n", __func__,
468 src_port->name(), pkt->print());
469
470 // store size and command as they might be modified when
471 // forwarding the packet
472 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
473 unsigned int pkt_cmd = pkt->cmdToIndex();
474
475 // a response sees the response latency
476 Tick xbar_delay = responseLatency * clockPeriod();
477
478 // set the packet header and payload delay
479 calcPacketTiming(pkt, xbar_delay);
480
481 // determine how long to be crossbar layer is busy
482 Tick packetFinishTime = clockEdge(headerLatency) + pkt->payloadDelay;
483
484 if (snoopFilter && !system->bypassCaches()) {
485 // let the snoop filter inspect the response and update its state
486 snoopFilter->updateResponse(pkt, *cpuSidePorts[cpu_side_port_id]);
487 }
488
489 // send the packet through the destination CPU-side port and pay for
490 // any outstanding header delay
491 Tick latency = pkt->headerDelay;
492 pkt->headerDelay = 0;
493 cpuSidePorts[cpu_side_port_id]->schedTimingResp(pkt, curTick()
494 + latency);
495
496 // remove the request from the routing table
497 routeTo.erase(route_lookup);
498
499 respLayers[cpu_side_port_id]->succeededTiming(packetFinishTime);
500
501 // stats updates
502 pktCount[cpu_side_port_id][mem_side_port_id]++;
503 pktSize[cpu_side_port_id][mem_side_port_id] += pkt_size;
504 transDist[pkt_cmd]++;
505
506 return true;
507}
508
509void
511{
512 DPRINTF(CoherentXBar, "%s: src %s packet %s\n", __func__,
513 memSidePorts[mem_side_port_id]->name(), pkt->print());
514
515 // update stats here as we know the forwarding will succeed
516 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
517 transDist[pkt->cmdToIndex()]++;
518 snoops++;
519 snoopTraffic += pkt_size;
520
521 // we should only see express snoops from caches
522 assert(pkt->isExpressSnoop());
523
524 // set the packet header and payload delay, for now use forward latency
525 // @todo Assess the choice of latency further
527
528 // remember if a cache has already committed to responding so we
529 // can see if it changes during the snooping
530 const bool cache_responding = pkt->cacheResponding();
531
532 assert(pkt->snoopDelay == 0);
533
534 if (snoopFilter) {
535 // let the Snoop Filter work its magic and guide probing
536 auto sf_res = snoopFilter->lookupSnoop(pkt);
537 // the time required by a packet to be delivered through
538 // the xbar has to be charged also with to lookup latency
539 // of the snoop filter
540 pkt->headerDelay += sf_res.second * clockPeriod();
541 DPRINTF(CoherentXBar, "%s: src %s packet %s SF size: %i lat: %i\n",
542 __func__, memSidePorts[mem_side_port_id]->name(),
543 pkt->print(), sf_res.first.size(), sf_res.second);
544
545 // forward to all snoopers
546 forwardTiming(pkt, InvalidPortID, sf_res.first);
547 } else {
549 }
550
551 // add the snoop delay to our header delay, and then reset it
552 pkt->headerDelay += pkt->snoopDelay;
553 pkt->snoopDelay = 0;
554
555 // if we can expect a response, remember how to route it
556 if (!cache_responding && pkt->cacheResponding()) {
557 assert(routeTo.find(pkt->req) == routeTo.end());
558 routeTo[pkt->req] = mem_side_port_id;
559 }
560
561 // a snoop request came from a connected CPU-side-port device (one of
562 // our memory-side ports), and if it is not coming from the CPU-side-port
563 // device responsible for the address range something is
564 // wrong, hence there is nothing further to do as the packet
565 // would be going back to where it came from
566 assert(findPort(pkt) == mem_side_port_id);
567}
568
569bool
571{
572 // determine the source port based on the id
573 ResponsePort* src_port = cpuSidePorts[cpu_side_port_id];
574
575 // get the destination
576 const auto route_lookup = routeTo.find(pkt->req);
577 assert(route_lookup != routeTo.end());
578 const PortID dest_port_id = route_lookup->second;
579 assert(dest_port_id != InvalidPortID);
580
581 // determine if the response is from a snoop request we
582 // created as the result of a normal request (in which case it
583 // should be in the outstandingSnoop), or if we merely forwarded
584 // someone else's snoop request
585 const bool forwardAsSnoop = outstandingSnoop.find(pkt->req) ==
586 outstandingSnoop.end();
587
588 // test if the crossbar should be considered occupied for the
589 // current port, note that the check is bypassed if the response
590 // is being passed on as a normal response since this is occupying
591 // the response layer rather than the snoop response layer
592 if (forwardAsSnoop) {
593 assert(dest_port_id < snoopLayers.size());
594 if (!snoopLayers[dest_port_id]->tryTiming(src_port)) {
595 DPRINTF(CoherentXBar, "%s: src %s packet %s BUSY\n", __func__,
596 src_port->name(), pkt->print());
597 return false;
598 }
599 } else {
600 // get the memory-side port that mirrors this CPU-side port internally
601 RequestPort* snoop_port = snoopRespPorts[cpu_side_port_id];
602 assert(dest_port_id < respLayers.size());
603 if (!respLayers[dest_port_id]->tryTiming(snoop_port)) {
604 DPRINTF(CoherentXBar, "%s: src %s packet %s BUSY\n", __func__,
605 snoop_port->name(), pkt->print());
606 return false;
607 }
608 }
609
610 DPRINTF(CoherentXBar, "%s: src %s packet %s\n", __func__,
611 src_port->name(), pkt->print());
612
613 // store size and command as they might be modified when
614 // forwarding the packet
615 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
616 unsigned int pkt_cmd = pkt->cmdToIndex();
617
618 // responses are never express snoops
619 assert(!pkt->isExpressSnoop());
620
621 // a snoop response sees the snoop response latency, and if it is
622 // forwarded as a normal response, the response latency
623 Tick xbar_delay =
624 (forwardAsSnoop ? snoopResponseLatency : responseLatency) *
625 clockPeriod();
626
627 // set the packet header and payload delay
628 calcPacketTiming(pkt, xbar_delay);
629
630 // determine how long to be crossbar layer is busy
631 Tick packetFinishTime = clockEdge(headerLatency) + pkt->payloadDelay;
632
633 // forward it either as a snoop response or a normal response
634 if (forwardAsSnoop) {
635 // this is a snoop response to a snoop request we forwarded,
636 // e.g. coming from the L1 and going to the L2, and it should
637 // be forwarded as a snoop response
638
639 if (snoopFilter) {
640 // update the probe filter so that it can properly track the line
642 *cpuSidePorts[cpu_side_port_id],
643 *memSidePorts[dest_port_id]);
644 }
645
646 [[maybe_unused]] bool success =
647 memSidePorts[dest_port_id]->sendTimingSnoopResp(pkt);
648 pktCount[cpu_side_port_id][dest_port_id]++;
649 pktSize[cpu_side_port_id][dest_port_id] += pkt_size;
650 assert(success);
651
652 snoopLayers[dest_port_id]->succeededTiming(packetFinishTime);
653 } else {
654 // we got a snoop response on one of our CPU-side ports,
655 // i.e. from a coherent requestor connected to the crossbar, and
656 // since we created the snoop request as part of recvTiming,
657 // this should now be a normal response again
658 outstandingSnoop.erase(pkt->req);
659
660 // this is a snoop response from a coherent requestor, hence it
661 // should never go back to where the snoop response came from,
662 // but instead to where the original request came from
663 assert(cpu_side_port_id != dest_port_id);
664
665 if (snoopFilter) {
666 // update the probe filter so that it can properly track
667 // the line
669 *cpuSidePorts[cpu_side_port_id],
670 *cpuSidePorts[dest_port_id]);
671 }
672
673 DPRINTF(CoherentXBar, "%s: src %s packet %s FWD RESP\n", __func__,
674 src_port->name(), pkt->print());
675
676 // as a normal response, it should go back to a requestor through
677 // one of our CPU-side ports, we also pay for any outstanding
678 // header latency
679 Tick latency = pkt->headerDelay;
680 pkt->headerDelay = 0;
681 cpuSidePorts[dest_port_id]->schedTimingResp(pkt,
682 curTick() + latency);
683
684 respLayers[dest_port_id]->succeededTiming(packetFinishTime);
685 }
686
687 // remove the request from the routing table
688 routeTo.erase(route_lookup);
689
690 // stats updates
691 transDist[pkt_cmd]++;
692 snoops++;
693 snoopTraffic += pkt_size;
694
695 return true;
696}
697
698
699void
700CoherentXBar::forwardTiming(PacketPtr pkt, PortID exclude_cpu_side_port_id,
702{
703 DPRINTF(CoherentXBar, "%s for %s\n", __func__, pkt->print());
704
705 // snoops should only happen if the system isn't bypassing caches
706 assert(!system->bypassCaches());
707
708 unsigned fanout = 0;
709
710 for (const auto& p: dests) {
711 // we could have gotten this request from a snooping requestor
712 // (corresponding to our own CPU-side port that is also in
713 // snoopPorts) and should not send it back to where it came
714 // from
715 if (exclude_cpu_side_port_id == InvalidPortID ||
716 p->getId() != exclude_cpu_side_port_id) {
717 // cache is not allowed to refuse snoop
718 p->sendTimingSnoopReq(pkt);
719 fanout++;
720 }
721 }
722
723 // Stats for fanout of this forward operation
724 snoopFanout.sample(fanout);
725}
726
727void
729{
730 // responses and snoop responses never block on forwarding them,
731 // so the retry will always be coming from a port to which we
732 // tried to forward a request
733 reqLayers[mem_side_port_id]->recvRetry();
734}
735
736Tick
738 MemBackdoorPtr *backdoor)
739{
740 DPRINTF(CoherentXBar, "%s: src %s packet %s\n", __func__,
741 cpuSidePorts[cpu_side_port_id]->name(), pkt->print());
742
743 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
744 unsigned int pkt_cmd = pkt->cmdToIndex();
745
746 MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
747 Tick snoop_response_latency = 0;
748
749 // is this the destination point for this packet? (e.g. true if
750 // this xbar is the PoC for a cache maintenance operation to the
751 // PoC) otherwise the destination is any cache that can satisfy
752 // the request
753 const bool is_destination = isDestination(pkt);
754
755 const bool snoop_caches = !system->bypassCaches() &&
756 pkt->cmd != MemCmd::WriteClean;
757 if (snoop_caches) {
758 // forward to all snoopers but the source
759 std::pair<MemCmd, Tick> snoop_result;
760 if (snoopFilter) {
761 // check with the snoop filter where to forward this packet
762 auto sf_res =
764 *cpuSidePorts [cpu_side_port_id]);
765 snoop_response_latency += sf_res.second * clockPeriod();
766 DPRINTF(CoherentXBar, "%s: src %s packet %s SF size: %i lat: %i\n",
767 __func__, cpuSidePorts[cpu_side_port_id]->name(),
768 pkt->print(), sf_res.first.size(), sf_res.second);
769
770 // let the snoop filter know about the success of the send
771 // operation, and do it even before sending it onwards to
772 // avoid situations where atomic upward snoops sneak in
773 // between and change the filter state
774 snoopFilter->finishRequest(false, pkt->getAddr(), pkt->isSecure());
775
776 if (pkt->isEviction()) {
777 // for block-evicting packets, i.e. writebacks and
778 // clean evictions, there is no need to snoop up, as
779 // all we do is determine if the block is cached or
780 // not, instead just set it here based on the snoop
781 // filter result
782 if (!sf_res.first.empty())
783 pkt->setBlockCached();
784 } else {
785 snoop_result = forwardAtomic(pkt, cpu_side_port_id,
786 InvalidPortID, sf_res.first);
787 }
788 } else {
789 snoop_result = forwardAtomic(pkt, cpu_side_port_id);
790 }
791 snoop_response_cmd = snoop_result.first;
792 snoop_response_latency += snoop_result.second;
793 }
794
795 // set up a sensible default value
796 Tick response_latency = 0;
797
798 const bool sink_packet = sinkPacket(pkt);
799
800 // even if we had a snoop response, we must continue and also
801 // perform the actual request at the destination
802 PortID mem_side_port_id = findPort(pkt);
803
804 if (sink_packet) {
805 DPRINTF(CoherentXBar, "%s: Not forwarding %s\n", __func__,
806 pkt->print());
807 } else {
808 if (forwardPacket(pkt)) {
809 // make sure that the write request (e.g., WriteClean)
810 // will stop at the memory below if this crossbar is its
811 // destination
812 if (pkt->isWrite() && is_destination) {
813 pkt->clearWriteThrough();
814 }
815
816 // forward the request to the appropriate destination
817 auto mem_side_port = memSidePorts[mem_side_port_id];
818 response_latency = backdoor ?
819 mem_side_port->sendAtomicBackdoor(pkt, *backdoor) :
820 mem_side_port->sendAtomic(pkt);
821 } else {
822 // if it does not need a response we sink the packet above
823 assert(pkt->needsResponse());
824
825 pkt->makeResponse();
826 }
827 }
828
829 // stats updates for the request
830 pktCount[cpu_side_port_id][mem_side_port_id]++;
831 pktSize[cpu_side_port_id][mem_side_port_id] += pkt_size;
832 transDist[pkt_cmd]++;
833
834
835 // if lower levels have replied, tell the snoop filter
836 if (!system->bypassCaches() && snoopFilter && pkt->isResponse()) {
837 snoopFilter->updateResponse(pkt, *cpuSidePorts[cpu_side_port_id]);
838 }
839
840 // if we got a response from a snooper, restore it here
841 if (snoop_response_cmd != MemCmd::InvalidCmd) {
842 // no one else should have responded
843 assert(!pkt->isResponse());
844 pkt->cmd = snoop_response_cmd;
845 response_latency = snoop_response_latency;
846 }
847
848 // If this is the destination of the cache clean operation the
849 // crossbar is responsible for responding. This crossbar will
850 // respond when the cache clean is complete. An atomic cache clean
851 // is complete when the crossbars receives the cache clean
852 // request (CleanSharedReq, CleanInvalidReq), as either:
853 // * no cache above had a dirty copy of the block as indicated by
854 // the satisfied flag of the packet, or
855 // * the crossbar has already seen the corresponding write
856 // (WriteClean) which updates the block in the memory below.
857 if (pkt->isClean() && isDestination(pkt) && pkt->satisfied()) {
858 auto it = outstandingCMO.find(pkt->id);
859 assert(it != outstandingCMO.end());
860 // we are responding right away
861 outstandingCMO.erase(it);
862 } else if (pkt->cmd == MemCmd::WriteClean && isDestination(pkt)) {
863 // if this is the destination of the operation, the xbar
864 // sends the responce to the cache clean operation only
865 // after having encountered the cache clean request
866 [[maybe_unused]] auto ret = outstandingCMO.emplace(pkt->id, nullptr);
867 // in atomic mode we know that the WriteClean packet should
868 // precede the clean request
869 assert(ret.second);
870 }
871
872 // add the response data
873 if (pkt->isResponse()) {
874 pkt_size = pkt->hasData() ? pkt->getSize() : 0;
875 pkt_cmd = pkt->cmdToIndex();
876
877 // stats updates
878 pktCount[cpu_side_port_id][mem_side_port_id]++;
879 pktSize[cpu_side_port_id][mem_side_port_id] += pkt_size;
880 transDist[pkt_cmd]++;
881 }
882
883 // @todo: Not setting header time
884 pkt->payloadDelay = response_latency;
885 return response_latency;
886}
887
888Tick
890{
891 DPRINTF(CoherentXBar, "%s: src %s packet %s\n", __func__,
892 memSidePorts[mem_side_port_id]->name(), pkt->print());
893
894 // add the request snoop data
895 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
896 snoops++;
897 snoopTraffic += pkt_size;
898
899 // forward to all snoopers
900 std::pair<MemCmd, Tick> snoop_result;
901 Tick snoop_response_latency = 0;
902 if (snoopFilter) {
903 auto sf_res = snoopFilter->lookupSnoop(pkt);
904 snoop_response_latency += sf_res.second * clockPeriod();
905 DPRINTF(CoherentXBar, "%s: src %s packet %s SF size: %i lat: %i\n",
906 __func__, memSidePorts[mem_side_port_id]->name(),
907 pkt->print(), sf_res.first.size(), sf_res.second);
908 snoop_result = forwardAtomic(pkt, InvalidPortID, mem_side_port_id,
909 sf_res.first);
910 } else {
911 snoop_result = forwardAtomic(pkt, InvalidPortID);
912 }
913 MemCmd snoop_response_cmd = snoop_result.first;
914 snoop_response_latency += snoop_result.second;
915
916 if (snoop_response_cmd != MemCmd::InvalidCmd)
917 pkt->cmd = snoop_response_cmd;
918
919 // add the response snoop data
920 if (pkt->isResponse()) {
921 snoops++;
922 }
923
924 // @todo: Not setting header time
925 pkt->payloadDelay = snoop_response_latency;
926 return snoop_response_latency;
927}
928
930CoherentXBar::forwardAtomic(PacketPtr pkt, PortID exclude_cpu_side_port_id,
931 PortID source_mem_side_port_id,
933{
934 // the packet may be changed on snoops, record the original
935 // command to enable us to restore it between snoops so that
936 // additional snoops can take place properly
937 MemCmd orig_cmd = pkt->cmd;
938 MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
939 Tick snoop_response_latency = 0;
940
941 // snoops should only happen if the system isn't bypassing caches
942 assert(!system->bypassCaches());
943
944 unsigned fanout = 0;
945
946 for (const auto& p: dests) {
947 // we could have gotten this request from a snooping memory-side port
948 // (corresponding to our own CPU-side port that is also in
949 // snoopPorts) and should not send it back to where it came
950 // from
951 if (exclude_cpu_side_port_id != InvalidPortID &&
952 p->getId() == exclude_cpu_side_port_id)
953 continue;
954
955 Tick latency = p->sendAtomicSnoop(pkt);
956 fanout++;
957
958 // in contrast to a functional access, we have to keep on
959 // going as all snoopers must be updated even if we get a
960 // response
961 if (!pkt->isResponse())
962 continue;
963
964 // response from snoop agent
965 assert(pkt->cmd != orig_cmd);
966 assert(pkt->cacheResponding());
967 // should only happen once
968 assert(snoop_response_cmd == MemCmd::InvalidCmd);
969 // save response state
970 snoop_response_cmd = pkt->cmd;
971 snoop_response_latency = latency;
972
973 if (snoopFilter) {
974 // Handle responses by the snoopers and differentiate between
975 // responses to requests from above and snoops from below
976 if (source_mem_side_port_id != InvalidPortID) {
977 // Getting a response for a snoop from below
978 assert(exclude_cpu_side_port_id == InvalidPortID);
980 *memSidePorts[source_mem_side_port_id]);
981 } else {
982 // Getting a response for a request from above
983 assert(source_mem_side_port_id == InvalidPortID);
985 *cpuSidePorts[exclude_cpu_side_port_id]);
986 }
987 }
988 // restore original packet state for remaining snoopers
989 pkt->cmd = orig_cmd;
990 }
991
992 // Stats for fanout
993 snoopFanout.sample(fanout);
994
995 // the packet is restored as part of the loop and any potential
996 // snoop response is part of the returned pair
997 return std::make_pair(snoop_response_cmd, snoop_response_latency);
998}
999
1000void
1002 MemBackdoorPtr &backdoor)
1003{
1004 PortID dest_id = findPort(req.range());
1005 memSidePorts[dest_id]->sendMemBackdoorReq(req, backdoor);
1006}
1007
1008void
1010{
1011 if (!pkt->isPrint()) {
1012 // don't do DPRINTFs on PrintReq as it clutters up the output
1013 DPRINTF(CoherentXBar, "%s: src %s packet %s\n", __func__,
1014 cpuSidePorts[cpu_side_port_id]->name(), pkt->print());
1015 }
1016
1017 if (!system->bypassCaches()) {
1018 // forward to all snoopers but the source
1019 forwardFunctional(pkt, cpu_side_port_id);
1020 }
1021
1022 // there is no need to continue if the snooping has found what we
1023 // were looking for and the packet is already a response
1024 if (!pkt->isResponse()) {
1025 // since our CPU-side ports are queued ports we need to check
1026 // them as well
1027 for (const auto& p : cpuSidePorts) {
1028 // if we find a response that has the data, then the
1029 // downstream caches/memories may be out of date, so simply stop
1030 // here
1031 if (p->trySatisfyFunctional(pkt)) {
1032 if (pkt->needsResponse())
1033 pkt->makeResponse();
1034 return;
1035 }
1036 }
1037
1038 PortID dest_id = findPort(pkt);
1039
1040 memSidePorts[dest_id]->sendFunctional(pkt);
1041 }
1042}
1043
1044void
1046{
1047 if (!pkt->isPrint()) {
1048 // don't do DPRINTFs on PrintReq as it clutters up the output
1049 DPRINTF(CoherentXBar, "%s: src %s packet %s\n", __func__,
1050 memSidePorts[mem_side_port_id]->name(), pkt->print());
1051 }
1052
1053 for (const auto& p : cpuSidePorts) {
1054 if (p->trySatisfyFunctional(pkt)) {
1055 if (pkt->needsResponse())
1056 pkt->makeResponse();
1057 return;
1058 }
1059 }
1060
1061 // forward to all snoopers
1063}
1064
1065void
1067{
1068 // snoops should only happen if the system isn't bypassing caches
1069 assert(!system->bypassCaches());
1070
1071 for (const auto& p: snoopPorts) {
1072 // we could have gotten this request from a snooping requestor
1073 // (corresponding to our own CPU-side port that is also in
1074 // snoopPorts) and should not send it back to where it came
1075 // from
1076 if (exclude_cpu_side_port_id == InvalidPortID ||
1077 p->getId() != exclude_cpu_side_port_id)
1078 p->sendFunctionalSnoop(pkt);
1079
1080 // if we get a response we are done
1081 if (pkt->isResponse()) {
1082 break;
1083 }
1084 }
1085}
1086
1087bool
1089{
1090 // we can sink the packet if:
1091 // 1) the crossbar is the point of coherency, and a cache is
1092 // responding after being snooped
1093 // 2) the crossbar is the point of coherency, and the packet is a
1094 // coherency packet (not a read or a write) that does not
1095 // require a response
1096 // 3) this is a clean evict or clean writeback, but the packet is
1097 // found in a cache above this crossbar
1098 // 4) a cache is responding after being snooped, and the packet
1099 // either does not need the block to be writable, or the cache
1100 // that has promised to respond (setting the cache responding
1101 // flag) is providing writable and thus had a Modified block,
1102 // and no further action is needed
1103 return (pointOfCoherency && pkt->cacheResponding()) ||
1104 (pointOfCoherency && !(pkt->isRead() || pkt->isWrite()) &&
1105 !pkt->needsResponse()) ||
1106 (pkt->isCleanEviction() && pkt->isBlockCached()) ||
1107 (pkt->cacheResponding() &&
1108 (!pkt->needsWritable() || pkt->responderHadWritable()));
1109}
1110
1111bool
1113{
1114 // we are forwarding the packet if:
1115 // 1) this is a cache clean request to the PoU/PoC and this
1116 // crossbar is above the PoU/PoC
1117 // 2) this is a read or a write
1118 // 3) this crossbar is above the point of coherency
1119 if (pkt->isClean()) {
1120 return !isDestination(pkt);
1121 }
1122 return pkt->isRead() || pkt->isWrite() || !pointOfCoherency;
1123}
1124
1125
1126void
1128{
1130
1131 snoopFanout.init(0, snoopPorts.size(), 1);
1132}
1133
1134} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
The base crossbar contains the common elements of the non-coherent and coherent crossbar.
Definition xbar.hh:72
PortID defaultPortID
Port that handles requests that don't match any of the interfaces.
Definition xbar.hh:390
std::vector< RequestPort * > memSidePorts
Definition xbar.hh:387
const Cycles headerLatency
Cycles the layer is occupied processing the packet header.
Definition xbar.hh:315
const Cycles frontendLatency
Cycles of front-end pipeline including the delay to accept the request and to decode the address.
Definition xbar.hh:311
PortID findPort(AddrRange addr_range, PacketPtr pkt=nullptr)
Find which port connected to this crossbar (if any) should be given a packet with this address range.
Definition xbar.cc:334
statistics::Vector transDist
Stats for transaction distribution and data passing through the crossbar.
Definition xbar.hh:409
std::unordered_map< RequestPtr, PortID > routeTo
Remember where request packets came from so that we can route responses to the appropriate port.
Definition xbar.hh:327
statistics::Vector2d pktCount
Definition xbar.hh:410
std::vector< QueuedResponsePort * > cpuSidePorts
The memory-side ports and CPU-side ports of the crossbar.
Definition xbar.hh:386
void regStats() override
Callback to set stat parameters.
Definition xbar.cc:554
const Cycles forwardLatency
Definition xbar.hh:312
statistics::Vector2d pktSize
Definition xbar.hh:411
void calcPacketTiming(PacketPtr pkt, Tick header_delay)
Calculate the timing parameters for the packet.
Definition xbar.cc:108
const Cycles responseLatency
Definition xbar.hh:313
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 clockPeriod() const
Declaration of the coherent crossbar memory-side port type, one will be instantiated for each of the ...
Declaration of the coherent crossbar CPU-side port type, one will be instantiated for each of the mem...
Internal class to bridge between an incoming snoop response from a CPU-side port and forwarding it th...
A coherent crossbar connects a number of (potentially) snooping requestors and responders,...
std::vector< RespLayer * > respLayers
void recvReqRetry(PortID mem_side_port_id)
bool recvTimingResp(PacketPtr pkt, PortID mem_side_port_id)
bool sinkPacket(const PacketPtr pkt) const
Determine if the crossbar should sink the packet, as opposed to forwarding it, or responding.
std::vector< SnoopRespLayer * > snoopLayers
bool recvTimingSnoopResp(PacketPtr pkt, PortID cpu_side_port_id)
void recvMemBackdoorReq(const MemBackdoorReq &req, MemBackdoorPtr &backdoor)
Function called by the port when the crossbar receives a request for a memory backdoor.
std::unordered_map< PacketId, PacketPtr > outstandingCMO
Store the outstanding cache maintenance that we are expecting snoop responses from so we can determin...
std::vector< SnoopRespPort * > snoopRespPorts
Tick recvAtomicSnoop(PacketPtr pkt, PortID mem_side_port_id)
bool recvTimingReq(PacketPtr pkt, PortID cpu_side_port_id)
System * system
Keep a pointer to the system to be allow to querying memory system properties.
std::vector< ReqLayer * > reqLayers
Declare the layers of this crossbar, one vector for requests, one for responses, and one for snoop re...
std::vector< QueuedResponsePort * > snoopPorts
std::unordered_set< RequestPtr > outstandingSnoop
Store the outstanding requests that we are expecting snoop responses from so we can determine which s...
void forwardTiming(PacketPtr pkt, PortID exclude_cpu_side_port_id)
Forward a timing packet to our snoopers, potentially excluding one of the connected coherent requesto...
void recvTimingSnoopReq(PacketPtr pkt, PortID mem_side_port_id)
const Cycles snoopResponseLatency
Cycles of snoop response latency.
void recvFunctional(PacketPtr pkt, PortID cpu_side_port_id)
Function called by the port when the crossbar is receiving a Functional transaction.
std::unique_ptr< Packet > pendingDelete
Upstream caches need this packet until true is returned, so hold it for deletion until a subsequent c...
CoherentXBar(const CoherentXBarParams &p)
virtual void regStats()
Callback to set stat parameters.
void forwardFunctional(PacketPtr pkt, PortID exclude_cpu_side_port_id)
Forward a functional packet to our snoopers, potentially excluding one of the connected coherent requ...
std::pair< MemCmd, Tick > forwardAtomic(PacketPtr pkt, PortID exclude_cpu_side_port_id)
Forward an atomic packet to our snoopers, potentially excluding one of the connected coherent request...
statistics::Scalar snoopTraffic
statistics::Scalar snoops
SnoopFilter * snoopFilter
A snoop filter that tracks cache line residency and can restrict the broadcast needed for probes.
bool isDestination(const PacketPtr pkt) const
Determine if the packet's destination is the memory below.
void recvFunctionalSnoop(PacketPtr pkt, PortID mem_side_port_id)
Function called by the port when the crossbar is receiving a functional snoop transaction.
const unsigned int maxOutstandingSnoopCheck
Maximum number of outstading snoops sanity check.
statistics::Distribution snoopFanout
virtual void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
bool forwardPacket(const PacketPtr pkt)
Determine if the crossbar should forward the packet, as opposed to responding to it.
const unsigned int maxRoutingTableSizeCheck
Maximum routing table size sanity check.
const bool pointOfCoherency
Is this crossbar the point of coherency?
Tick recvAtomicBackdoor(PacketPtr pkt, PortID cpu_side_port_id, MemBackdoorPtr *backdoor=nullptr)
Cycles is a wrapper class for representing cycle counts, i.e.
Definition types.hh:79
const AddrRange & range() const
Definition backdoor.hh:140
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
void setExpressSnoop()
The express snoop flag is used for two purposes.
Definition packet.hh:701
bool responderHadWritable() const
Definition packet.hh:719
bool isRead() const
Definition packet.hh:593
bool isSecure() const
Definition packet.hh:836
const PacketId id
Definition packet.hh:374
Addr getAddr() const
Definition packet.hh:807
bool isResponse() const
Definition packet.hh:598
uint32_t snoopDelay
Keep track of the extra delay incurred by snooping upwards before sending a request down the memory s...
Definition packet.hh:439
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 satisfied() const
Definition packet.hh:755
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
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
int cmdToIndex() const
Return the index of this command.
Definition packet.hh:591
bool hasData() const
Definition packet.hh:614
bool isWrite() const
Definition packet.hh:594
RequestPtr req
A pointer to the original request.
Definition packet.hh:377
bool isPrint() const
Definition packet.hh:623
unsigned getSize() const
Definition packet.hh:817
bool isClean() const
Definition packet.hh:611
bool isExpressSnoop() const
Definition packet.hh:702
void clearWriteThrough()
Definition packet.hh:741
bool cacheResponding() const
Definition packet.hh:659
MemCmd cmd
The command field of the packet.
Definition packet.hh:372
bool isBlockCached() const
Definition packet.hh:760
void setBlockCached()
Definition packet.hh:759
bool isEviction() const
Definition packet.hh:610
const std::string name() const
Return port name (for DPRINTF).
Definition port.hh:111
A queued port is a port that has an infinite queue for outgoing packets and thus decouples the module...
Definition qport.hh:62
A RequestPort is a specialisation of a Port, which implements the default protocol for the three diff...
Definition port.hh:136
A ResponsePort is a specialization of a port.
Definition port.hh:349
void finishRequest(bool will_retry, Addr addr, bool is_secure)
For an un-successful request, revert the change to the snoop filter.
void setCPUSidePorts(const SnoopList &_cpu_side_ports)
Init a new snoop filter and tell it about all the cpu_sideports of the enclosing bus.
void updateSnoopForward(const Packet *cpkt, const ResponsePort &rsp_port, const RequestPort &req_port)
Pass snoop responses that travel downward through the snoop filter and let them update the snoop filt...
void updateResponse(const Packet *cpkt, const ResponsePort &cpu_side_port)
Update the snoop filter with a response from below (outer / other cache, or memory) and update the tr...
std::pair< SnoopList, Cycles > lookupSnoop(const Packet *cpkt)
Handle an incoming snoop from below (the memory-side port).
void updateSnoopResponse(const Packet *cpkt, const ResponsePort &rsp_port, const ResponsePort &req_port)
Let the snoop filter see any snoop responses that turn into request responses and indicate cache to c...
std::pair< SnoopList, Cycles > lookupRequest(const Packet *cpkt, const ResponsePort &cpu_side_port)
Lookup a request (from a CPU-side port) in the snoop filter and return a list of other CPU-side ports...
bool bypassCaches() const
Should caches be bypassed?
Definition system.hh:279
void sample(const U &v, int n=1)
Add a value to the distribtion n times.
Distribution & init(Counter min, Counter max, Counter bkt)
Set the parameters of this distribution.
STL pair class.
Definition stl.hh:58
STL vector class.
Definition stl.hh:37
Declaration of a coherent crossbar.
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition group.hh:75
#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
virtual void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition sim_object.cc:73
#define warn(...)
Definition logging.hh:256
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 5 > l
Bitfield< 0 > p
Bitfield< 15 > system
Definition misc.hh:1032
Bitfield< 3 > addr
Definition types.hh:84
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
const PortID InvalidPortID
Definition types.hh:246
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
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
std::string csprintf(const char *format, const Args &...args)
Definition cprintf.hh:161

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