gem5  v22.1.0.0
RubyPort.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012-2013,2020-2021 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) 2009-2013 Advanced Micro Devices, Inc.
15  * Copyright (c) 2011 Mark D. Hill and David A. Wood
16  * All rights reserved.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions are
20  * met: redistributions of source code must retain the above copyright
21  * notice, this list of conditions and the following disclaimer;
22  * redistributions in binary form must reproduce the above copyright
23  * notice, this list of conditions and the following disclaimer in the
24  * documentation and/or other materials provided with the distribution;
25  * neither the name of the copyright holders nor the names of its
26  * contributors may be used to endorse or promote products derived from
27  * this software without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  */
41 
43 
44 #include "base/compiler.hh"
46 #include "debug/Config.hh"
47 #include "debug/Drain.hh"
48 #include "debug/Ruby.hh"
49 #include "mem/ruby/protocol/AccessPermission.hh"
51 #include "mem/simple_mem.hh"
52 #include "sim/full_system.hh"
53 #include "sim/system.hh"
54 
55 namespace gem5
56 {
57 
58 namespace ruby
59 {
60 
62  : ClockedObject(p), m_ruby_system(p.ruby_system), m_version(p.version),
63  m_controller(NULL), m_mandatory_q_ptr(NULL),
64  m_usingRubyTester(p.using_ruby_tester), system(p.system),
65  pioRequestPort(csprintf("%s.pio-request-port", name()), this),
66  pioResponsePort(csprintf("%s.pio-response-port", name()), this),
67  memRequestPort(csprintf("%s.mem-request-port", name()), this),
68  memResponsePort(csprintf("%s-mem-response-port", name()), this,
69  p.ruby_system->getAccessBackingStore(), -1,
70  p.no_retry_on_stall),
71  gotAddrRanges(p.port_interrupt_out_port_connection_count),
72  m_isCPUSequencer(p.is_cpu_sequencer)
73 {
74  assert(m_version != -1);
75 
76  // create the response ports based on the number of connected ports
77  for (size_t i = 0; i < p.port_in_ports_connection_count; ++i) {
79  ("%s.response_ports%d", name(), i), this,
80  p.ruby_system->getAccessBackingStore(),
81  i, p.no_retry_on_stall));
82  }
83 
84  // create the request ports based on the number of connected ports
85  for (size_t i = 0; i < p.port_interrupt_out_port_connection_count; ++i) {
87  "%s.request_ports%d", name(), i), this));
88  }
89 }
90 
91 void
93 {
94  assert(m_controller != NULL);
96  for (const auto &response_port : response_ports)
97  response_port->sendRangeChange();
98  if (gotAddrRanges == 0 && FullSystem) {
100  }
101 }
102 
103 Port &
104 RubyPort::getPort(const std::string &if_name, PortID idx)
105 {
106  if (if_name == "mem_request_port") {
107  return memRequestPort;
108  } else if (if_name == "pio_request_port") {
109  return pioRequestPort;
110  } else if (if_name == "mem_response_port") {
111  return memResponsePort;
112  } else if (if_name == "pio_response_port") {
113  return pioResponsePort;
114  } else if (if_name == "interrupt_out_port") {
115  // used by the x86 CPUs to connect the interrupt PIO and interrupt
116  // response port
117  if (idx >= static_cast<PortID>(request_ports.size())) {
118  panic("%s: unknown %s index (%d)\n", __func__, if_name, idx);
119  }
120 
121  return *request_ports[idx];
122  } else if (if_name == "in_ports") {
123  // used by the CPUs to connect the caches to the interconnect, and
124  // for the x86 case also the interrupt request port
125  if (idx >= static_cast<PortID>(response_ports.size())) {
126  panic("%s: unknown %s index (%d)\n", __func__, if_name, idx);
127  }
128 
129  return *response_ports[idx];
130  }
131 
132  // pass it along to our super class
133  return ClockedObject::getPort(if_name, idx);
134 }
135 
137  RubyPort *_port)
138  : QueuedRequestPort(_name, _port, reqQueue, snoopRespQueue),
139  reqQueue(*_port, *this), snoopRespQueue(*_port, *this)
140 {
141  DPRINTF(RubyPort, "Created request pioport on sequencer %s\n", _name);
142 }
143 
145  RubyPort *_port)
146  : QueuedResponsePort(_name, _port, queue), queue(*_port, *this)
147 {
148  DPRINTF(RubyPort, "Created response pioport on sequencer %s\n", _name);
149 }
150 
152  RubyPort *_port)
153  : QueuedRequestPort(_name, _port, reqQueue, snoopRespQueue),
154  reqQueue(*_port, *this), snoopRespQueue(*_port, *this)
155 {
156  DPRINTF(RubyPort, "Created request memport on ruby sequencer %s\n", _name);
157 }
158 
160 MemResponsePort::MemResponsePort(const std::string &_name, RubyPort *_port,
161  bool _access_backing_store, PortID id,
162  bool _no_retry_on_stall)
163  : QueuedResponsePort(_name, _port, queue, id), queue(*_port, *this),
164  access_backing_store(_access_backing_store),
165  no_retry_on_stall(_no_retry_on_stall)
166 {
167  DPRINTF(RubyPort, "Created response memport on ruby sequencer %s\n",
168  _name);
169 }
170 
171 bool
173 {
174  RubyPort *rp = static_cast<RubyPort *>(&owner);
175  DPRINTF(RubyPort, "Response for address: 0x%#x\n", pkt->getAddr());
176 
177  // send next cycle
179  pkt, curTick() + rp->m_ruby_system->clockPeriod());
180  return true;
181 }
182 
184 {
185  // got a response from a device
186  assert(pkt->isResponse());
187  assert(!pkt->htmTransactionFailedInCache());
188 
189  // First we must retrieve the request port from the sender State
190  RubyPort::SenderState *senderState =
191  safe_cast<RubyPort::SenderState *>(pkt->popSenderState());
192  MemResponsePort *port = senderState->port;
193  assert(port != NULL);
194  delete senderState;
195 
196  // In FS mode, ruby memory will receive pio responses from devices
197  // and it must forward these responses back to the particular CPU.
198  DPRINTF(RubyPort, "Pio response for address %#x, going to %s\n",
199  pkt->getAddr(), port->name());
200 
201  // attempt to send the response in the next cycle
202  RubyPort *rp = static_cast<RubyPort *>(&owner);
203  port->schedTimingResp(pkt, curTick() + rp->m_ruby_system->clockPeriod());
204 
205  return true;
206 }
207 
208 bool
210 {
211  RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
212 
213  for (size_t i = 0; i < ruby_port->request_ports.size(); ++i) {
214  AddrRangeList l = ruby_port->request_ports[i]->getAddrRanges();
215  for (auto it = l.begin(); it != l.end(); ++it) {
216  if (it->contains(pkt->getAddr())) {
217  // generally it is not safe to assume success here as
218  // the port could be blocked
219  [[maybe_unused]] bool success =
220  ruby_port->request_ports[i]->sendTimingReq(pkt);
221  assert(success);
222  return true;
223  }
224  }
225  }
226  panic("Should never reach here!\n");
227 }
228 
229 Tick
231 {
232  RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
233  // Only atomic_noncaching mode supported!
234  if (!ruby_port->system->bypassCaches()) {
235  panic("Ruby supports atomic accesses only in noncaching mode\n");
236  }
237 
238  for (size_t i = 0; i < ruby_port->request_ports.size(); ++i) {
239  AddrRangeList l = ruby_port->request_ports[i]->getAddrRanges();
240  for (auto it = l.begin(); it != l.end(); ++it) {
241  if (it->contains(pkt->getAddr())) {
242  return ruby_port->request_ports[i]->sendAtomic(pkt);
243  }
244  }
245  }
246  panic("Could not find address in Ruby PIO address ranges!\n");
247 }
248 
249 bool
251 {
252  DPRINTF(RubyPort, "Timing request for address %#x on port %d\n",
253  pkt->getAddr(), id);
254  RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
255 
256  if (pkt->cacheResponding())
257  panic("RubyPort should never see request with the "
258  "cacheResponding flag set\n");
259 
260  // ruby doesn't support cache maintenance operations at the
261  // moment, as a workaround, we respond right away
262  if (pkt->req->isCacheMaintenance()) {
263  warn_once("Cache maintenance operations are not supported in Ruby.\n");
264  pkt->makeResponse();
265  schedTimingResp(pkt, curTick());
266  return true;
267  }
268  // Check for pio requests and directly send them to the dedicated
269  // pio port.
270  if (pkt->cmd != MemCmd::MemSyncReq) {
271  if (!pkt->req->isMemMgmt() && !isPhysMemAddress(pkt)) {
272  assert(ruby_port->memRequestPort.isConnected());
273  DPRINTF(RubyPort, "Request address %#x assumed to be a "
274  "pio address\n", pkt->getAddr());
275 
276  // Save the port in the sender state object to be used later to
277  // route the response
278  pkt->pushSenderState(new SenderState(this));
279 
280  // send next cycle
281  RubySystem *rs = ruby_port->m_ruby_system;
282  ruby_port->memRequestPort.schedTimingReq(pkt,
283  curTick() + rs->clockPeriod());
284  return true;
285  }
286  }
287 
288  // Save the port in the sender state object to be used later to
289  // route the response
290  pkt->pushSenderState(new SenderState(this));
291 
292  // Submit the ruby request
293  RequestStatus requestStatus = ruby_port->makeRequest(pkt);
294 
295  // If the request successfully issued then we should return true.
296  // Otherwise, we need to tell the port to retry at a later point
297  // and return false.
298  if (requestStatus == RequestStatus_Issued) {
299  DPRINTF(RubyPort, "Request %s 0x%x issued\n", pkt->cmdString(),
300  pkt->getAddr());
301  return true;
302  }
303 
304  // pop off sender state as this request failed to issue
305  SenderState *ss = safe_cast<SenderState *>(pkt->popSenderState());
306  delete ss;
307 
308  if (pkt->cmd != MemCmd::MemSyncReq) {
310  "Request %s for address %#x did not issue because %s\n",
311  pkt->cmdString(), pkt->getAddr(),
312  RequestStatus_to_string(requestStatus));
313  }
314 
315  addToRetryList();
316 
317  return false;
318 }
319 
320 Tick
322 {
323  RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
324  // Only atomic_noncaching mode supported!
325  if (!ruby_port->system->bypassCaches()) {
326  panic("Ruby supports atomic accesses only in noncaching mode\n");
327  }
328 
329  // Check for pio requests and directly send them to the dedicated
330  // pio port.
331  if (pkt->cmd != MemCmd::MemSyncReq) {
332  if (!isPhysMemAddress(pkt)) {
333  assert(ruby_port->memRequestPort.isConnected());
334  DPRINTF(RubyPort, "Request address %#x assumed to be a "
335  "pio address\n", pkt->getAddr());
336 
337  // Save the port in the sender state object to be used later to
338  // route the response
339  pkt->pushSenderState(new SenderState(this));
340 
341  // send next cycle
342  Tick req_ticks = ruby_port->memRequestPort.sendAtomic(pkt);
343  return ruby_port->ticksToCycles(req_ticks);
344  }
345 
346  assert(getOffset(pkt->getAddr()) + pkt->getSize() <=
348  }
349 
350  // Find the machine type of memory controller interface
351  RubySystem *rs = ruby_port->m_ruby_system;
352  static int mem_interface_type = -1;
353  if (mem_interface_type == -1) {
354  if (rs->m_abstract_controls[MachineType_Directory].size() != 0) {
355  mem_interface_type = MachineType_Directory;
356  }
357  else if (rs->m_abstract_controls[MachineType_Memory].size() != 0) {
358  mem_interface_type = MachineType_Memory;
359  }
360  else {
361  panic("Can't find the memory controller interface\n");
362  }
363  }
364 
365  // Find the controller for the target address
366  MachineID id = ruby_port->m_controller->mapAddressToMachine(
367  pkt->getAddr(), (MachineType)mem_interface_type);
368  AbstractController *mem_interface =
369  rs->m_abstract_controls[mem_interface_type][id.getNum()];
370  Tick latency = mem_interface->recvAtomic(pkt);
371  if (access_backing_store)
372  rs->getPhysMem()->access(pkt);
373  return latency;
374 }
375 
376 void
378 {
379  RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
380 
381  //
382  // Unless the request port do not want retries (e.g., the Ruby tester),
383  // record the stalled M5 port for later retry when the sequencer
384  // becomes free.
385  //
386  if (!no_retry_on_stall && !ruby_port->onRetryList(this)) {
387  ruby_port->addToRetryList(this);
388  }
389 }
390 
391 void
393 {
394  DPRINTF(RubyPort, "Functional access for address: %#x\n", pkt->getAddr());
395 
396  [[maybe_unused]] RubyPort *rp = static_cast<RubyPort *>(&owner);
397  RubySystem *rs = rp->m_ruby_system;
398 
399  // Check for pio requests and directly send them to the dedicated
400  // pio port.
401  if (!isPhysMemAddress(pkt)) {
402  DPRINTF(RubyPort, "Pio Request for address: 0x%#x\n", pkt->getAddr());
403  assert(rp->pioRequestPort.isConnected());
405  return;
406  }
407 
408  assert(pkt->getAddr() + pkt->getSize() <=
410 
411  if (access_backing_store) {
412  // The attached physmem contains the official version of data.
413  // The following command performs the real functional access.
414  // This line should be removed once Ruby supplies the official version
415  // of data.
416  rs->getPhysMem()->functionalAccess(pkt);
417  } else {
418  bool accessSucceeded = false;
419  bool needsResponse = pkt->needsResponse();
420 
421  // Do the functional access on ruby memory
422  if (pkt->isRead()) {
423  accessSucceeded = rs->functionalRead(pkt);
424  } else if (pkt->isWrite()) {
425  accessSucceeded = rs->functionalWrite(pkt);
426  } else {
427  panic("Unsupported functional command %s\n", pkt->cmdString());
428  }
429 
430  // Unless the request port explicitly said otherwise, generate an error
431  // if the functional request failed
432  if (!accessSucceeded && !pkt->suppressFuncError()) {
433  fatal("Ruby functional %s failed for address %#x\n",
434  pkt->isWrite() ? "write" : "read", pkt->getAddr());
435  }
436 
437  // turn packet around to go back to request port if response expected
438  if (needsResponse) {
439  // The pkt is already turned into a reponse if the directory
440  // forwarded the request to the memory controller (see
441  // AbstractController::functionalMemoryWrite and
442  // AbstractMemory::functionalAccess)
443  if (!pkt->isResponse())
444  pkt->makeResponse();
445  pkt->setFunctionalResponseStatus(accessSucceeded);
446  }
447 
448  DPRINTF(RubyPort, "Functional access %s!\n",
449  accessSucceeded ? "successful":"failed");
450  }
451 }
452 
453 void
455 {
456  DPRINTF(RubyPort, "Hit callback for %s 0x%x\n", pkt->cmdString(),
457  pkt->getAddr());
458 
459  // The packet was destined for memory and has not yet been turned
460  // into a response
461  assert(system->isMemAddr(pkt->getAddr()) || system->isDeviceMemAddr(pkt));
462  assert(pkt->isRequest());
463 
464  // First we must retrieve the request port from the sender State
465  RubyPort::SenderState *senderState =
466  safe_cast<RubyPort::SenderState *>(pkt->popSenderState());
467  MemResponsePort *port = senderState->port;
468  assert(port != NULL);
469  delete senderState;
470 
471  port->hitCallback(pkt);
472 
473  trySendRetries();
474 }
475 
476 void
478 {
479  DPRINTF(RubyPort, "Unaddressed callback for %s\n", pkt->cmdString());
480 
481  assert(pkt->isRequest());
482 
483  // First we must retrieve the request port from the sender State
484  RubyPort::SenderState *senderState =
485  safe_cast<RubyPort::SenderState *>(pkt->popSenderState());
486  MemResponsePort *port = senderState->port;
487  assert(port != NULL);
488  delete senderState;
489 
490  port->hitCallback(pkt);
491 
492  trySendRetries();
493 }
494 
495 void
497 {
498  DPRINTF(RubyPort, "Stale Translation Callback\n");
499 
500  // Allocate the invalidate request and packet on the stack, as it is
501  // assumed they will not be modified or deleted by receivers.
502  // TODO: should this really be using funcRequestorId?
503  auto request = std::make_shared<Request>(
506  // Store the txnId in extraData instead of the address
507  request->setExtraData(txnId);
508 
509  // Use a single packet to signal all snooping ports of the external sync.
510  // This assumes that snooping ports do NOT modify the packet/request
511  // TODO rename TlbiExtSync to StaleTranslation
512  Packet pkt(request, MemCmd::TlbiExtSync);
513  // TODO - see where response_ports is filled, might be we only want to send
514  // to specific places
515  for (auto &port : response_ports) {
516  // check if the connected request port is snooping
517  if (port->isSnooping()) {
518  // send as a snoop request
519  port->sendTimingSnoopReq(&pkt);
520  }
521  }
522 }
523 
524 void
526 {
527  //
528  // If we had to stall the MemResponsePorts, wake them up because the
529  // sequencer likely has free resources now.
530  //
531  if (!retryList.empty()) {
532  // Record the current list of ports to retry on a temporary list
533  // before calling sendRetryReq on those ports. sendRetryReq will cause
534  // an immediate retry, which may result in the ports being put back on
535  // the list. Therefore we want to clear the retryList before calling
536  // sendRetryReq.
538 
539  retryList.clear();
540 
541  for (auto i = curRetryList.begin(); i != curRetryList.end(); ++i) {
543  "Sequencer may now be free. SendRetry to port %s\n",
544  (*i)->name());
545  (*i)->sendRetryReq();
546  }
547  }
548 }
549 
550 void
552 {
553  //If we weren't able to drain before, we might be able to now.
554  if (drainState() == DrainState::Draining) {
555  unsigned int drainCount = outstandingCount();
556  DPRINTF(Drain, "Drain count: %u\n", drainCount);
557  if (drainCount == 0) {
558  DPRINTF(Drain, "RubyPort done draining, signaling drain done\n");
559  signalDrainDone();
560  }
561  }
562 }
563 
566 {
567  if (isDeadlockEventScheduled()) {
569  }
570 
571  //
572  // If the RubyPort is not empty, then it needs to clear all outstanding
573  // requests before it should call signalDrainDone()
574  //
575  DPRINTF(Config, "outstanding count %d\n", outstandingCount());
576  if (outstandingCount() > 0) {
577  DPRINTF(Drain, "RubyPort not drained\n");
578  return DrainState::Draining;
579  } else {
580  return DrainState::Drained;
581  }
582 }
583 
584 void
586 {
587  bool needsResponse = pkt->needsResponse();
588 
589  // Unless specified at configuration, all responses except failed SC
590  // and Flush operations access M5 physical memory.
591  bool accessPhysMem = access_backing_store;
592 
593  if (pkt->isLLSC()) {
594  if (pkt->isWrite()) {
595  if (pkt->req->getExtraData() != 0) {
596  //
597  // Successful SC packets convert to normal writes
598  //
599  pkt->convertScToWrite();
600  } else {
601  //
602  // Failed SC packets don't access physical memory and thus
603  // the RubyPort itself must convert it to a response.
604  //
605  accessPhysMem = false;
606  }
607  } else {
608  //
609  // All LL packets convert to normal loads so that M5 PhysMem does
610  // not lock the blocks.
611  //
612  pkt->convertLlToRead();
613  }
614  }
615 
616  // Flush, acquire, release requests don't access physical memory
617  if (pkt->isFlush() || pkt->cmd == MemCmd::MemSyncReq
618  || pkt->cmd == MemCmd::WriteCompleteResp) {
619  accessPhysMem = false;
620  }
621 
622  if (pkt->req->isKernel()) {
623  accessPhysMem = false;
624  needsResponse = true;
625  }
626 
627  DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse);
628 
629  RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
630  RubySystem *rs = ruby_port->m_ruby_system;
631  if (accessPhysMem) {
632  // We must check device memory first in case it overlaps with the
633  // system memory range.
634  if (ruby_port->system->isDeviceMemAddr(pkt)) {
635  auto dmem = ruby_port->system->getDeviceMemory(pkt);
636  dmem->access(pkt);
637  } else if (ruby_port->system->isMemAddr(pkt->getAddr())) {
638  rs->getPhysMem()->access(pkt);
639  } else {
640  panic("Packet is in neither device nor system memory!");
641  }
642  } else if (needsResponse) {
643  pkt->makeResponse();
644  }
645 
646  // turn packet around to go back to request port if response expected
647  if (needsResponse || pkt->isResponse()) {
648  DPRINTF(RubyPort, "Sending packet back over port\n");
649  // Send a response in the same cycle. There is no need to delay the
650  // response because the response latency is already incurred in the
651  // Ruby protocol.
652  schedTimingResp(pkt, curTick());
653  } else {
654  delete pkt;
655  }
656 
657  DPRINTF(RubyPort, "Hit callback done!\n");
658 }
659 
662 {
663  // at the moment the assumption is that the request port does not care
664  AddrRangeList ranges;
665  RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
666 
667  for (size_t i = 0; i < ruby_port->request_ports.size(); ++i) {
668  ranges.splice(ranges.begin(),
669  ruby_port->request_ports[i]->getAddrRanges());
670  }
671  for ([[maybe_unused]] const auto &r : ranges)
672  DPRINTF(RubyPort, "%s\n", r.to_string());
673  return ranges;
674 }
675 
676 bool
678 {
679  RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
680  AddrRangeList ranges = ruby_port->system->getShadowRomRanges();
681 
682  for (auto it = ranges.begin(); it != ranges.end(); ++it) {
683  if (it->contains(addr)) {
684  return true;
685  }
686  }
687 
688  return false;
689 }
690 
691 bool
693 {
694  RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
695  Addr addr = pkt->getAddr();
696  return (ruby_port->system->isMemAddr(addr) && !isShadowRomAddress(addr))
697  || ruby_port->system->isDeviceMemAddr(pkt);
698 }
699 
700 void
702 {
703  DPRINTF(RubyPort, "Sending invalidations.\n");
704  // Allocate the invalidate request and packet on the stack, as it is
705  // assumed they will not be modified or deleted by receivers.
706  // TODO: should this really be using funcRequestorId?
707  auto request = std::make_shared<Request>(
708  address, RubySystem::getBlockSizeBytes(), 0,
710 
711  // Use a single packet to signal all snooping ports of the invalidation.
712  // This assumes that snooping ports do NOT modify the packet/request
713  Packet pkt(request, MemCmd::InvalidateReq);
714  for (CpuPortIter p = response_ports.begin(); p != response_ports.end();
715  ++p) {
716  // check if the connected request port is snooping
717  if ((*p)->isSnooping()) {
718  // send as a snoop request
719  (*p)->sendTimingSnoopReq(&pkt);
720  }
721  }
722 }
723 
724 void
726 {
727  RubyPort &r = static_cast<RubyPort &>(owner);
728  r.gotAddrRanges--;
729  if (r.gotAddrRanges == 0 && FullSystem) {
730  r.pioResponsePort.sendRangeChange();
731  }
732 }
733 
734 int
736 {
737  int num_written = 0;
738  for (auto port : response_ports) {
739  if (port->trySatisfyFunctional(func_pkt)) {
740  num_written += 1;
741  }
742  }
743  return num_written;
744 }
745 
746 } // namespace ruby
747 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Tick clockPeriod() const
Cycles ticksToCycles(Tick t) const
@ InvalidateReq
Definition: packet.hh:143
@ WriteCompleteResp
Definition: packet.hh:91
const std::string _name
Definition: named.hh:41
virtual std::string name() const
Definition: named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
bool isRead() const
Definition: packet.hh:592
Addr getAddr() const
Definition: packet.hh:805
bool isResponse() const
Definition: packet.hh:597
bool needsResponse() const
Definition: packet.hh:607
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
void pushSenderState(SenderState *sender_state)
Push a new sender state to the packet and make the current sender state the predecessor of the new on...
Definition: packet.cc:334
SenderState * popSenderState()
Pop the top of the state stack and return a pointer to it.
Definition: packet.cc:342
void convertScToWrite()
It has been determined that the SC packet should successfully update memory.
Definition: packet.hh:851
bool isWrite() const
Definition: packet.hh:593
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
Definition: packet.hh:587
RequestPtr req
A pointer to the original request.
Definition: packet.hh:376
unsigned getSize() const
Definition: packet.hh:815
void setFunctionalResponseStatus(bool success)
Definition: packet.hh:1083
void convertLlToRead()
When ruby is in use, Ruby will monitor the cache line and the phys memory should treat LL ops as norm...
Definition: packet.hh:863
bool isLLSC() const
Definition: packet.hh:619
bool cacheResponding() const
Definition: packet.hh:657
MemCmd cmd
The command field of the packet.
Definition: packet.hh:371
bool suppressFuncError() const
Definition: packet.hh:756
bool htmTransactionFailedInCache() const
Returns whether or not this packet/request has returned from the cache hierarchy in a failed transact...
Definition: packet.cc:503
bool isFlush() const
Definition: packet.hh:623
bool isRequest() const
Definition: packet.hh:596
Ports are used to interface objects to each other.
Definition: port.hh:62
bool isConnected() const
Is this port currently connected to a peer?
Definition: port.hh:133
const std::string name() const
Return port name (for DPRINTF).
Definition: port.hh:111
The QueuedRequestPort combines two queues, a request queue and a snoop response queue,...
Definition: qport.hh:110
void schedTimingReq(PacketPtr pkt, Tick when)
Schedule the sending of a timing request.
Definition: qport.hh:149
A queued port is a port that has an infinite queue for outgoing packets and thus decouples the module...
Definition: qport.hh:62
void schedTimingResp(PacketPtr pkt, Tick when)
Schedule the sending of a timing response.
Definition: qport.hh:93
Tick sendAtomic(PacketPtr pkt)
Send an atomic request packet, where the data is moved and the state is updated in zero time,...
Definition: port.hh:464
void sendFunctional(PacketPtr pkt) const
Send a functional request packet, where the data is instantly updated everywhere in the memory system...
Definition: port.hh:485
@ TLBI_EXT_SYNC
The Request tells the CPU model that a remote TLB Sync has been requested.
Definition: request.hh:248
@ funcRequestorId
This requestor id is used for functional requests that don't come from a particular device.
Definition: request.hh:279
void sendRangeChange() const
Called by the owner to send a range change.
Definition: port.hh:296
AddrRangeList getShadowRomRanges() const
Definition: system.hh:385
bool isMemAddr(Addr addr) const
Check if a physical address is within a range of a memory that is part of the global address map.
Definition: system.cc:288
bool isDeviceMemAddr(const PacketPtr &pkt) const
Similar to isMemAddr but for devices.
Definition: system.cc:301
bool bypassCaches() const
Should caches be bypassed?
Definition: system.hh:282
memory::AbstractMemory * getDeviceMemory(const PacketPtr &pkt) const
Return a pointer to the device memory.
Definition: system.cc:311
void access(PacketPtr pkt)
Perform an untimed memory access and update all the state (e.g.
virtual MessageBuffer * getMandatoryQueue() const =0
MachineID mapAddressToMachine(Addr addr, MachineType mtype) const
Map an address to the correct MachineID.
bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
Definition: RubyPort.cc:183
MemRequestPort(const std::string &_name, RubyPort *_port)
Definition: RubyPort.cc:151
bool isShadowRomAddress(Addr addr) const
Definition: RubyPort.cc:677
Tick recvAtomic(PacketPtr pkt)
Receive an atomic request packet from the peer.
Definition: RubyPort.cc:321
void recvFunctional(PacketPtr pkt)
Receive a functional request packet from the peer.
Definition: RubyPort.cc:392
bool recvTimingReq(PacketPtr pkt)
Receive a timing request from the peer.
Definition: RubyPort.cc:250
MemResponsePort(const std::string &_name, RubyPort *_port, bool _access_backing_store, PortID id, bool _no_retry_on_stall)
Definition: RubyPort.cc:160
bool isPhysMemAddress(PacketPtr pkt) const
Definition: RubyPort.cc:692
void recvRangeChange()
Called to receive an address range change from the peer response port.
Definition: RubyPort.cc:725
bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
Definition: RubyPort.cc:172
PioRequestPort(const std::string &_name, RubyPort *_port)
Definition: RubyPort.cc:136
PioResponsePort(const std::string &_name, RubyPort *_port)
Definition: RubyPort.cc:144
Tick recvAtomic(PacketPtr pkt)
Receive an atomic request packet from the peer.
Definition: RubyPort.cc:230
bool recvTimingReq(PacketPtr pkt)
Receive a timing request from the peer.
Definition: RubyPort.cc:209
AddrRangeList getAddrRanges() const
Get a list of the non-overlapping address ranges the owner is responsible for.
Definition: RubyPort.cc:661
void ruby_hit_callback(PacketPtr pkt)
Definition: RubyPort.cc:454
std::vector< MemResponsePort * > response_ports
Definition: RubyPort.hh:204
virtual RequestStatus makeRequest(PacketPtr pkt)=0
void ruby_unaddressed_callback(PacketPtr pkt)
Definition: RubyPort.cc:477
void testDrainComplete()
Definition: RubyPort.cc:551
virtual int outstandingCount() const =0
std::vector< MemResponsePort * >::iterator CpuPortIter
Vector of M5 Ports attached to this Ruby port.
Definition: RubyPort.hh:225
void ruby_stale_translation_callback(Addr txnId)
Definition: RubyPort.cc:496
virtual void descheduleDeadlockEvent()=0
std::vector< MemResponsePort * > retryList
Definition: RubyPort.hh:232
RubySystem * m_ruby_system
Definition: RubyPort.hh:197
MemResponsePort memResponsePort
Definition: RubyPort.hh:221
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: RubyPort.cc:92
PioResponsePort pioResponsePort
Definition: RubyPort.hh:219
bool onRetryList(MemResponsePort *port)
Definition: RubyPort.hh:207
PioRequestPort pioRequestPort
Definition: RubyPort.hh:218
RubyPort(const Params &p)
Definition: RubyPort.cc:61
virtual bool isDeadlockEventScheduled() const =0
virtual int functionalWrite(Packet *func_pkt)
Definition: RubyPort.cc:735
unsigned int gotAddrRanges
Definition: RubyPort.hh:222
void addToRetryList(MemResponsePort *port)
Definition: RubyPort.hh:212
MemRequestPort memRequestPort
Definition: RubyPort.hh:220
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: RubyPort.cc:104
RubyPortParams Params
Definition: RubyPort.hh:153
AbstractController * m_controller
Definition: RubyPort.hh:199
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
Definition: RubyPort.cc:565
void ruby_eviction_callback(Addr address)
Definition: RubyPort.cc:701
MessageBuffer * m_mandatory_q_ptr
Definition: RubyPort.hh:200
std::vector< PioRequestPort * > request_ports
Definition: RubyPort.hh:226
static uint32_t getBlockSizeBytes()
Definition: RubySystem.hh:72
STL vector class.
Definition: stl.hh:37
void signalDrainDone() const
Signal that an object is drained.
Definition: drain.hh:305
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:324
DrainState
Object drain/handover states.
Definition: drain.hh:75
@ Draining
Draining buffers pending serialization/handover.
@ Drained
Buffers drained, ready for serialization/handover.
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Definition: sim_object.cc:126
#define warn_once(...)
Definition: logging.hh:250
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 9, 8 > rs
Definition: misc_types.hh:383
Bitfield< 33 > id
Definition: misc_types.hh:257
Bitfield< 5 > r
Definition: pagetable.hh:60
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
Addr makeLineAddress(Addr addr)
Definition: Address.cc:60
Addr getOffset(Addr addr)
Definition: Address.cc:54
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
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
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
Definition: root.cc:220
uint64_t Tick
Tick count type.
Definition: types.hh:58
RubyTester::SenderState SenderState
Definition: Check.cc:40
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
SimpleMemory declaration.
const std::string & name()
Definition: trace.cc:49
std::stringstream ss
Definition: trace.test.cc:45

Generated on Wed Dec 21 2022 10:22:38 for gem5 by doxygen 1.9.1