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

Generated on Mon Jun 8 2020 15:45:11 for gem5 by doxygen 1.8.13