gem5  v22.1.0.0
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 
55 namespace gem5
56 {
57 
58 CoherentXBar::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) {
87  defaultPortID = memSidePorts.size();
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",
93  defaultPortID)));
94  snoopLayers.push_back(new SnoopRespLayer(*bp, *this,
95  csprintf("snoopLayer%d",
96  defaultPortID)));
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);
102  QueuedResponsePort* bp = new CoherentXBarResponsePort(portName,
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 
123 void
125 {
126  BaseXBar::init();
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 
148 bool
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->getAddrRange());
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 
446 bool
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 
509 void
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->getAddrRange()) == mem_side_port_id);
567 }
568 
569 bool
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 
699 void
700 CoherentXBar::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 
727 void
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 
736 Tick
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->getAddrRange());
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 
888 Tick
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 
930 CoherentXBar::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 
1000 void
1002 {
1003  if (!pkt->isPrint()) {
1004  // don't do DPRINTFs on PrintReq as it clutters up the output
1005  DPRINTF(CoherentXBar, "%s: src %s packet %s\n", __func__,
1006  cpuSidePorts[cpu_side_port_id]->name(), pkt->print());
1007  }
1008 
1009  if (!system->bypassCaches()) {
1010  // forward to all snoopers but the source
1011  forwardFunctional(pkt, cpu_side_port_id);
1012  }
1013 
1014  // there is no need to continue if the snooping has found what we
1015  // were looking for and the packet is already a response
1016  if (!pkt->isResponse()) {
1017  // since our CPU-side ports are queued ports we need to check
1018  // them as well
1019  for (const auto& p : cpuSidePorts) {
1020  // if we find a response that has the data, then the
1021  // downstream caches/memories may be out of date, so simply stop
1022  // here
1023  if (p->trySatisfyFunctional(pkt)) {
1024  if (pkt->needsResponse())
1025  pkt->makeResponse();
1026  return;
1027  }
1028  }
1029 
1030  PortID dest_id = findPort(pkt->getAddrRange());
1031 
1032  memSidePorts[dest_id]->sendFunctional(pkt);
1033  }
1034 }
1035 
1036 void
1038 {
1039  if (!pkt->isPrint()) {
1040  // don't do DPRINTFs on PrintReq as it clutters up the output
1041  DPRINTF(CoherentXBar, "%s: src %s packet %s\n", __func__,
1042  memSidePorts[mem_side_port_id]->name(), pkt->print());
1043  }
1044 
1045  for (const auto& p : cpuSidePorts) {
1046  if (p->trySatisfyFunctional(pkt)) {
1047  if (pkt->needsResponse())
1048  pkt->makeResponse();
1049  return;
1050  }
1051  }
1052 
1053  // forward to all snoopers
1055 }
1056 
1057 void
1058 CoherentXBar::forwardFunctional(PacketPtr pkt, PortID exclude_cpu_side_port_id)
1059 {
1060  // snoops should only happen if the system isn't bypassing caches
1061  assert(!system->bypassCaches());
1062 
1063  for (const auto& p: snoopPorts) {
1064  // we could have gotten this request from a snooping requestor
1065  // (corresponding to our own CPU-side port that is also in
1066  // snoopPorts) and should not send it back to where it came
1067  // from
1068  if (exclude_cpu_side_port_id == InvalidPortID ||
1069  p->getId() != exclude_cpu_side_port_id)
1070  p->sendFunctionalSnoop(pkt);
1071 
1072  // if we get a response we are done
1073  if (pkt->isResponse()) {
1074  break;
1075  }
1076  }
1077 }
1078 
1079 bool
1081 {
1082  // we can sink the packet if:
1083  // 1) the crossbar is the point of coherency, and a cache is
1084  // responding after being snooped
1085  // 2) the crossbar is the point of coherency, and the packet is a
1086  // coherency packet (not a read or a write) that does not
1087  // require a response
1088  // 3) this is a clean evict or clean writeback, but the packet is
1089  // found in a cache above this crossbar
1090  // 4) a cache is responding after being snooped, and the packet
1091  // either does not need the block to be writable, or the cache
1092  // that has promised to respond (setting the cache responding
1093  // flag) is providing writable and thus had a Modified block,
1094  // and no further action is needed
1095  return (pointOfCoherency && pkt->cacheResponding()) ||
1096  (pointOfCoherency && !(pkt->isRead() || pkt->isWrite()) &&
1097  !pkt->needsResponse()) ||
1098  (pkt->isCleanEviction() && pkt->isBlockCached()) ||
1099  (pkt->cacheResponding() &&
1100  (!pkt->needsWritable() || pkt->responderHadWritable()));
1101 }
1102 
1103 bool
1105 {
1106  // we are forwarding the packet if:
1107  // 1) this is a cache clean request to the PoU/PoC and this
1108  // crossbar is above the PoU/PoC
1109  // 2) this is a read or a write
1110  // 3) this crossbar is above the point of coherency
1111  if (pkt->isClean()) {
1112  return !isDestination(pkt);
1113  }
1114  return pkt->isRead() || pkt->isWrite() || !pointOfCoherency;
1115 }
1116 
1117 
1118 void
1120 {
1122 
1123  snoopFanout.init(0, snoopPorts.size(), 1);
1124 }
1125 
1126 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
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:383
std::vector< RequestPort * > memSidePorts
Definition: xbar.hh:380
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
statistics::Vector transDist
Stats for transaction distribution and data passing through the crossbar.
Definition: xbar.hh:402
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:403
std::vector< QueuedResponsePort * > cpuSidePorts
The memory-side ports and CPU-side ports of the crossbar.
Definition: xbar.hh:379
PortID findPort(AddrRange addr_range)
Find which port connected to this crossbar (if any) should be given a packet with this address range.
Definition: xbar.cc:331
void regStats() override
Callback to set stat parameters.
Definition: xbar.cc:544
const Cycles forwardLatency
Definition: xbar.hh:312
statistics::Vector2d pktSize
Definition: xbar.hh:404
void calcPacketTiming(PacketPtr pkt, Tick header_delay)
Calculate the timing parameters for the packet.
Definition: xbar.cc:105
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::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...
std::vector< SnoopRespLayer * > snoopLayers
bool recvTimingSnoopResp(PacketPtr pkt, PortID cpu_side_port_id)
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...
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
@ WriteClean
Definition: packet.hh:94
@ InvalidCmd
Definition: packet.hh:85
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:294
void setExpressSnoop()
The express snoop flag is used for two purposes.
Definition: packet.hh:699
bool responderHadWritable() const
Definition: packet.hh:717
bool isRead() const
Definition: packet.hh:592
bool isSecure() const
Definition: packet.hh:834
const PacketId id
Definition: packet.hh:373
Addr getAddr() const
Definition: packet.hh:805
bool isResponse() const
Definition: packet.hh:597
uint32_t snoopDelay
Keep track of the extra delay incurred by snooping upwards before sending a request down the memory s...
Definition: packet.hh:438
bool needsWritable() const
Definition: packet.hh:598
AddrRange getAddrRange() const
Get address range to which this packet belongs.
Definition: packet.cc:243
void print(std::ostream &o, int verbosity=0, const std::string &prefix="") const
Definition: packet.cc:368
bool satisfied() const
Definition: packet.hh:753
bool isCleanEviction() const
Is this packet a clean eviction, including both actual clean evict packets, but also clean writebacks...
Definition: packet.hh:1422
bool needsResponse() const
Definition: packet.hh:607
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition: packet.hh:448
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:1059
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition: packet.hh:430
int cmdToIndex() const
Return the index of this command.
Definition: packet.hh:590
bool hasData() const
Definition: packet.hh:613
bool isWrite() const
Definition: packet.hh:593
RequestPtr req
A pointer to the original request.
Definition: packet.hh:376
bool isPrint() const
Definition: packet.hh:622
unsigned getSize() const
Definition: packet.hh:815
bool isClean() const
Definition: packet.hh:610
bool isExpressSnoop() const
Definition: packet.hh:700
void clearWriteThrough()
Definition: packet.hh:739
bool cacheResponding() const
Definition: packet.hh:657
MemCmd cmd
The command field of the packet.
Definition: packet.hh:371
bool isBlockCached() const
Definition: packet.hh:758
void setBlockCached()
Definition: packet.hh:757
bool isEviction() const
Definition: packet.hh:609
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:79
A ResponsePort is a specialization of a port.
Definition: port.hh:270
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...
Definition: snoop_filter.cc:67
bool bypassCaches() const
Should caches be bypassed?
Definition: system.hh:282
void sample(const U &v, int n=1)
Add a value to the distribtion n times.
Definition: statistics.hh:1328
Distribution & init(Counter min, Counter max, Counter bkt)
Set the parameters of this distribution.
Definition: statistics.hh:2113
STL pair class.
Definition: stl.hh:58
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:204
virtual void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: sim_object.cc:76
#define warn(...)
Definition: logging.hh:246
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 55 > l
Definition: pagetable.hh:54
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 15 > system
Definition: misc.hh:1004
Bitfield< 3 > addr
Definition: types.hh:84
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
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 Wed Dec 21 2022 10:22:37 for gem5 by doxygen 1.9.1