gem5  v22.0.0.1
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
mem_ctrl.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-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) 2013 Amin Farmahini-Farahani
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 
41 #include "mem/mem_ctrl.hh"
42 
43 #include "base/trace.hh"
44 #include "debug/DRAM.hh"
45 #include "debug/Drain.hh"
46 #include "debug/MemCtrl.hh"
47 #include "debug/NVM.hh"
48 #include "debug/QOS.hh"
49 #include "mem/dram_interface.hh"
50 #include "mem/mem_interface.hh"
51 #include "mem/nvm_interface.hh"
52 #include "sim/system.hh"
53 
54 namespace gem5
55 {
56 
57 namespace memory
58 {
59 
60 MemCtrl::MemCtrl(const MemCtrlParams &p) :
61  qos::MemCtrl(p),
62  port(name() + ".port", *this), isTimingMode(false),
63  retryRdReq(false), retryWrReq(false),
64  nextReqEvent([this] {processNextReqEvent(dram, respQueue,
66  respondEvent([this] {processRespondEvent(dram, respQueue,
67  respondEvent, retryRdReq); }, name()),
68  dram(p.dram),
69  readBufferSize(dram->readBufferSize),
70  writeBufferSize(dram->writeBufferSize),
71  writeHighThreshold(writeBufferSize * p.write_high_thresh_perc / 100.0),
72  writeLowThreshold(writeBufferSize * p.write_low_thresh_perc / 100.0),
73  minWritesPerSwitch(p.min_writes_per_switch),
74  minReadsPerSwitch(p.min_reads_per_switch),
75  writesThisTime(0), readsThisTime(0),
76  memSchedPolicy(p.mem_sched_policy),
77  frontendLatency(p.static_frontend_latency),
78  backendLatency(p.static_backend_latency),
79  commandWindow(p.command_window),
80  prevArrival(0),
81  stats(*this)
82 {
83  DPRINTF(MemCtrl, "Setting up controller\n");
84 
85  readQueue.resize(p.qos_priorities);
86  writeQueue.resize(p.qos_priorities);
87 
88  dram->setCtrl(this, commandWindow);
89 
90  // perform a basic check of the write thresholds
91  if (p.write_low_thresh_perc >= p.write_high_thresh_perc)
92  fatal("Write buffer low threshold %d must be smaller than the "
93  "high threshold %d\n", p.write_low_thresh_perc,
94  p.write_high_thresh_perc);
95 }
96 
97 void
99 {
100  if (!port.isConnected()) {
101  fatal("MemCtrl %s is unconnected!\n", name());
102  } else {
104  }
105 }
106 
107 void
109 {
110  // remember the memory system mode of operation
112 
113  if (isTimingMode) {
114  // shift the bus busy time sufficiently far ahead that we never
115  // have to worry about negative values when computing the time for
116  // the next request, this will add an insignificant bubble at the
117  // start of simulation
119  }
120 }
121 
122 Tick
124 {
125  if (!dram->getAddrRange().contains(pkt->getAddr())) {
126  panic("Can't handle address range for packet %s\n", pkt->print());
127  }
128 
129  return recvAtomicLogic(pkt, dram);
130 }
131 
132 
133 Tick
135 {
136  DPRINTF(MemCtrl, "recvAtomic: %s 0x%x\n",
137  pkt->cmdString(), pkt->getAddr());
138 
139  panic_if(pkt->cacheResponding(), "Should not see packets where cache "
140  "is responding");
141 
142  // do the actual memory access and turn the packet into a response
143  mem_intr->access(pkt);
144 
145  if (pkt->hasData()) {
146  // this value is not supposed to be accurate, just enough to
147  // keep things going, mimic a closed page
148  // also this latency can't be 0
149  return mem_intr->accessLatency();
150  }
151 
152  return 0;
153 }
154 
155 Tick
157 {
158  Tick latency = recvAtomic(pkt);
159  dram->getBackdoor(backdoor);
160  return latency;
161 }
162 
163 bool
164 MemCtrl::readQueueFull(unsigned int neededEntries) const
165 {
167  "Read queue limit %d, current size %d, entries needed %d\n",
169  neededEntries);
170 
171  auto rdsize_new = totalReadQueueSize + respQueue.size() + neededEntries;
172  return rdsize_new > readBufferSize;
173 }
174 
175 bool
176 MemCtrl::writeQueueFull(unsigned int neededEntries) const
177 {
179  "Write queue limit %d, current size %d, entries needed %d\n",
180  writeBufferSize, totalWriteQueueSize, neededEntries);
181 
182  auto wrsize_new = (totalWriteQueueSize + neededEntries);
183  return wrsize_new > writeBufferSize;
184 }
185 
186 bool
188  unsigned int pkt_count, MemInterface* mem_intr)
189 {
190  // only add to the read queue here. whenever the request is
191  // eventually done, set the readyTime, and call schedule()
192  assert(!pkt->isWrite());
193 
194  assert(pkt_count != 0);
195 
196  // if the request size is larger than burst size, the pkt is split into
197  // multiple packets
198  // Note if the pkt starting address is not aligened to burst size, the
199  // address of first packet is kept unaliged. Subsequent packets
200  // are aligned to burst size boundaries. This is to ensure we accurately
201  // check read packets against packets in write queue.
202  const Addr base_addr = pkt->getAddr();
203  Addr addr = base_addr;
204  unsigned pktsServicedByWrQ = 0;
205  BurstHelper* burst_helper = NULL;
206 
207  uint32_t burst_size = mem_intr->bytesPerBurst();
208 
209  for (int cnt = 0; cnt < pkt_count; ++cnt) {
210  unsigned size = std::min((addr | (burst_size - 1)) + 1,
211  base_addr + pkt->getSize()) - addr;
212  stats.readPktSize[ceilLog2(size)]++;
213  stats.readBursts++;
215 
216  // First check write buffer to see if the data is already at
217  // the controller
218  bool foundInWrQ = false;
219  Addr burst_addr = burstAlign(addr, mem_intr);
220  // if the burst address is not present then there is no need
221  // looking any further
222  if (isInWriteQueue.find(burst_addr) != isInWriteQueue.end()) {
223  for (const auto& vec : writeQueue) {
224  for (const auto& p : vec) {
225  // check if the read is subsumed in the write queue
226  // packet we are looking at
227  if (p->addr <= addr &&
228  ((addr + size) <= (p->addr + p->size))) {
229 
230  foundInWrQ = true;
232  pktsServicedByWrQ++;
234  "Read to addr %#x with size %d serviced by "
235  "write queue\n",
236  addr, size);
237  stats.bytesReadWrQ += burst_size;
238  break;
239  }
240  }
241  }
242  }
243 
244  // If not found in the write q, make a memory packet and
245  // push it onto the read queue
246  if (!foundInWrQ) {
247 
248  // Make the burst helper for split packets
249  if (pkt_count > 1 && burst_helper == NULL) {
250  DPRINTF(MemCtrl, "Read to addr %#x translates to %d "
251  "memory requests\n", pkt->getAddr(), pkt_count);
252  burst_helper = new BurstHelper(pkt_count);
253  }
254 
255  MemPacket* mem_pkt;
256  mem_pkt = mem_intr->decodePacket(pkt, addr, size, true,
257  mem_intr->pseudoChannel);
258 
259  // Increment read entries of the rank (dram)
260  // Increment count to trigger issue of non-deterministic read (nvm)
261  mem_intr->setupRank(mem_pkt->rank, true);
262  // Default readyTime to Max; will be reset once read is issued
263  mem_pkt->readyTime = MaxTick;
264  mem_pkt->burstHelper = burst_helper;
265 
266  assert(!readQueueFull(1));
268 
269  DPRINTF(MemCtrl, "Adding to read queue\n");
270 
271  readQueue[mem_pkt->qosValue()].push_back(mem_pkt);
272 
273  // log packet
275  pkt->qosValue(), mem_pkt->addr, 1);
276 
277  // Update stats
279  }
280 
281  // Starting address of next memory pkt (aligned to burst boundary)
282  addr = (addr | (burst_size - 1)) + 1;
283  }
284 
285  // If all packets are serviced by write queue, we send the repsonse back
286  if (pktsServicedByWrQ == pkt_count) {
287  accessAndRespond(pkt, frontendLatency, mem_intr);
288  return true;
289  }
290 
291  // Update how many split packets are serviced by write queue
292  if (burst_helper != NULL)
293  burst_helper->burstsServiced = pktsServicedByWrQ;
294 
295  // not all/any packets serviced by the write queue
296  return false;
297 }
298 
299 void
300 MemCtrl::addToWriteQueue(PacketPtr pkt, unsigned int pkt_count,
301  MemInterface* mem_intr)
302 {
303  // only add to the write queue here. whenever the request is
304  // eventually done, set the readyTime, and call schedule()
305  assert(pkt->isWrite());
306 
307  // if the request size is larger than burst size, the pkt is split into
308  // multiple packets
309  const Addr base_addr = pkt->getAddr();
310  Addr addr = base_addr;
311  uint32_t burst_size = mem_intr->bytesPerBurst();
312 
313  for (int cnt = 0; cnt < pkt_count; ++cnt) {
314  unsigned size = std::min((addr | (burst_size - 1)) + 1,
315  base_addr + pkt->getSize()) - addr;
316  stats.writePktSize[ceilLog2(size)]++;
317  stats.writeBursts++;
319 
320  // see if we can merge with an existing item in the write
321  // queue and keep track of whether we have merged or not
322  bool merged = isInWriteQueue.find(burstAlign(addr, mem_intr)) !=
323  isInWriteQueue.end();
324 
325  // if the item was not merged we need to create a new write
326  // and enqueue it
327  if (!merged) {
328  MemPacket* mem_pkt;
329  mem_pkt = mem_intr->decodePacket(pkt, addr, size, false,
330  mem_intr->pseudoChannel);
331  // Default readyTime to Max if nvm interface;
332  //will be reset once read is issued
333  mem_pkt->readyTime = MaxTick;
334 
335  mem_intr->setupRank(mem_pkt->rank, false);
336 
339 
340  DPRINTF(MemCtrl, "Adding to write queue\n");
341 
342  writeQueue[mem_pkt->qosValue()].push_back(mem_pkt);
343  isInWriteQueue.insert(burstAlign(addr, mem_intr));
344 
345  // log packet
347  pkt->qosValue(), mem_pkt->addr, 1);
348 
349  assert(totalWriteQueueSize == isInWriteQueue.size());
350 
351  // Update stats
353 
354  } else {
356  "Merging write burst with existing queue entry\n");
357 
358  // keep track of the fact that this burst effectively
359  // disappeared as it was merged with an existing one
361  }
362 
363  // Starting address of next memory pkt (aligned to burst_size boundary)
364  addr = (addr | (burst_size - 1)) + 1;
365  }
366 
367  // we do not wait for the writes to be send to the actual memory,
368  // but instead take responsibility for the consistency here and
369  // snoop the write queue for any upcoming reads
370  // @todo, if a pkt size is larger than burst size, we might need a
371  // different front end latency
372  accessAndRespond(pkt, frontendLatency, mem_intr);
373 }
374 
375 void
377 {
378 #if TRACING_ON
379  DPRINTF(MemCtrl, "===READ QUEUE===\n\n");
380  for (const auto& queue : readQueue) {
381  for (const auto& packet : queue) {
382  DPRINTF(MemCtrl, "Read %#x\n", packet->addr);
383  }
384  }
385 
386  DPRINTF(MemCtrl, "\n===RESP QUEUE===\n\n");
387  for (const auto& packet : respQueue) {
388  DPRINTF(MemCtrl, "Response %#x\n", packet->addr);
389  }
390 
391  DPRINTF(MemCtrl, "\n===WRITE QUEUE===\n\n");
392  for (const auto& queue : writeQueue) {
393  for (const auto& packet : queue) {
394  DPRINTF(MemCtrl, "Write %#x\n", packet->addr);
395  }
396  }
397 #endif // TRACING_ON
398 }
399 
400 bool
402 {
403  // This is where we enter from the outside world
404  DPRINTF(MemCtrl, "recvTimingReq: request %s addr %#x size %d\n",
405  pkt->cmdString(), pkt->getAddr(), pkt->getSize());
406 
407  panic_if(pkt->cacheResponding(), "Should not see packets where cache "
408  "is responding");
409 
410  panic_if(!(pkt->isRead() || pkt->isWrite()),
411  "Should only see read and writes at memory controller\n");
412 
413  // Calc avg gap between requests
414  if (prevArrival != 0) {
416  }
417  prevArrival = curTick();
418 
419  panic_if(!(dram->getAddrRange().contains(pkt->getAddr())),
420  "Can't handle address range for packet %s\n", pkt->print());
421 
422  // Find out how many memory packets a pkt translates to
423  // If the burst size is equal or larger than the pkt size, then a pkt
424  // translates to only one memory packet. Otherwise, a pkt translates to
425  // multiple memory packets
426  unsigned size = pkt->getSize();
427  uint32_t burst_size = dram->bytesPerBurst();
428 
429  unsigned offset = pkt->getAddr() & (burst_size - 1);
430  unsigned int pkt_count = divCeil(offset + size, burst_size);
431 
432  // run the QoS scheduler and assign a QoS priority value to the packet
433  qosSchedule( { &readQueue, &writeQueue }, burst_size, pkt);
434 
435  // check local buffers and do not accept if full
436  if (pkt->isWrite()) {
437  assert(size != 0);
438  if (writeQueueFull(pkt_count)) {
439  DPRINTF(MemCtrl, "Write queue full, not accepting\n");
440  // remember that we have to retry this port
441  retryWrReq = true;
442  stats.numWrRetry++;
443  return false;
444  } else {
445  addToWriteQueue(pkt, pkt_count, dram);
446  // If we are not already scheduled to get a request out of the
447  // queue, do so now
448  if (!nextReqEvent.scheduled()) {
449  DPRINTF(MemCtrl, "Request scheduled immediately\n");
451  }
452  stats.writeReqs++;
453  stats.bytesWrittenSys += size;
454  }
455  } else {
456  assert(pkt->isRead());
457  assert(size != 0);
458  if (readQueueFull(pkt_count)) {
459  DPRINTF(MemCtrl, "Read queue full, not accepting\n");
460  // remember that we have to retry this port
461  retryRdReq = true;
462  stats.numRdRetry++;
463  return false;
464  } else {
465  if (!addToReadQueue(pkt, pkt_count, dram)) {
466  // If we are not already scheduled to get a request out of the
467  // queue, do so now
468  if (!nextReqEvent.scheduled()) {
469  DPRINTF(MemCtrl, "Request scheduled immediately\n");
471  }
472  }
473  stats.readReqs++;
474  stats.bytesReadSys += size;
475  }
476  }
477 
478  return true;
479 }
480 
481 void
483  MemPacketQueue& queue,
484  EventFunctionWrapper& resp_event,
485  bool& retry_rd_req)
486 {
487 
489  "processRespondEvent(): Some req has reached its readyTime\n");
490 
491  MemPacket* mem_pkt = queue.front();
492 
493  // media specific checks and functions when read response is complete
494  // DRAM only
495  mem_intr->respondEvent(mem_pkt->rank);
496 
497  if (mem_pkt->burstHelper) {
498  // it is a split packet
499  mem_pkt->burstHelper->burstsServiced++;
500  if (mem_pkt->burstHelper->burstsServiced ==
501  mem_pkt->burstHelper->burstCount) {
502  // we have now serviced all children packets of a system packet
503  // so we can now respond to the requestor
504  // @todo we probably want to have a different front end and back
505  // end latency for split packets
507  mem_intr);
508  delete mem_pkt->burstHelper;
509  mem_pkt->burstHelper = NULL;
510  }
511  } else {
512  // it is not a split packet
514  mem_intr);
515  }
516 
517  queue.pop_front();
518 
519  if (!queue.empty()) {
520  assert(queue.front()->readyTime >= curTick());
521  assert(!resp_event.scheduled());
522  schedule(resp_event, queue.front()->readyTime);
523  } else {
524  // if there is nothing left in any queue, signal a drain
525  if (drainState() == DrainState::Draining &&
527  allIntfDrained()) {
528 
529  DPRINTF(Drain, "Controller done draining\n");
530  signalDrainDone();
531  } else {
532  // check the refresh state and kick the refresh event loop
533  // into action again if banks already closed and just waiting
534  // for read to complete
535  // DRAM only
536  mem_intr->checkRefreshState(mem_pkt->rank);
537  }
538  }
539 
540  delete mem_pkt;
541 
542  // We have made a location in the queue available at this point,
543  // so if there is a read that was forced to wait, retry now
544  if (retry_rd_req) {
545  retry_rd_req = false;
546  port.sendRetryReq();
547  }
548 }
549 
550 MemPacketQueue::iterator
551 MemCtrl::chooseNext(MemPacketQueue& queue, Tick extra_col_delay,
552  MemInterface* mem_intr)
553 {
554  // This method does the arbitration between requests.
555 
556  MemPacketQueue::iterator ret = queue.end();
557 
558  if (!queue.empty()) {
559  if (queue.size() == 1) {
560  // available rank corresponds to state refresh idle
561  MemPacket* mem_pkt = *(queue.begin());
562  if (mem_pkt->pseudoChannel != mem_intr->pseudoChannel) {
563  return ret;
564  }
565  if (packetReady(mem_pkt, mem_intr)) {
566  ret = queue.begin();
567  DPRINTF(MemCtrl, "Single request, going to a free rank\n");
568  } else {
569  DPRINTF(MemCtrl, "Single request, going to a busy rank\n");
570  }
571  } else if (memSchedPolicy == enums::fcfs) {
572  // check if there is a packet going to a free rank
573  for (auto i = queue.begin(); i != queue.end(); ++i) {
574  MemPacket* mem_pkt = *i;
575  if (packetReady(mem_pkt, mem_intr)) {
576  ret = i;
577  break;
578  }
579  }
580  } else if (memSchedPolicy == enums::frfcfs) {
581  Tick col_allowed_at;
582  std::tie(ret, col_allowed_at)
583  = chooseNextFRFCFS(queue, extra_col_delay, mem_intr);
584  } else {
585  panic("No scheduling policy chosen\n");
586  }
587  }
588  return ret;
589 }
590 
593  MemInterface* mem_intr)
594 {
595  auto selected_pkt_it = queue.end();
596  Tick col_allowed_at = MaxTick;
597 
598  // time we need to issue a column command to be seamless
599  const Tick min_col_at = std::max(mem_intr->nextBurstAt + extra_col_delay,
600  curTick());
601 
602  std::tie(selected_pkt_it, col_allowed_at) =
603  mem_intr->chooseNextFRFCFS(queue, min_col_at);
604 
605  if (selected_pkt_it == queue.end()) {
606  DPRINTF(MemCtrl, "%s no available packets found\n", __func__);
607  }
608 
609  return std::make_pair(selected_pkt_it, col_allowed_at);
610 }
611 
612 void
614  MemInterface* mem_intr)
615 {
616  DPRINTF(MemCtrl, "Responding to Address %#x.. \n", pkt->getAddr());
617 
618  bool needsResponse = pkt->needsResponse();
619  // do the actual memory access which also turns the packet into a
620  // response
621  panic_if(!mem_intr->getAddrRange().contains(pkt->getAddr()),
622  "Can't handle address range for packet %s\n", pkt->print());
623  mem_intr->access(pkt);
624 
625  // turn packet around to go back to requestor if response expected
626  if (needsResponse) {
627  // access already turned the packet into a response
628  assert(pkt->isResponse());
629  // response_time consumes the static latency and is charged also
630  // with headerDelay that takes into account the delay provided by
631  // the xbar and also the payloadDelay that takes into account the
632  // number of data beats.
633  Tick response_time = curTick() + static_latency + pkt->headerDelay +
634  pkt->payloadDelay;
635  // Here we reset the timing of the packet before sending it out.
636  pkt->headerDelay = pkt->payloadDelay = 0;
637 
638  // queue the packet in the response queue to be sent out after
639  // the static latency has passed
640  port.schedTimingResp(pkt, response_time);
641  } else {
642  // @todo the packet is going to be deleted, and the MemPacket
643  // is still having a pointer to it
644  pendingDelete.reset(pkt);
645  }
646 
647  DPRINTF(MemCtrl, "Done\n");
648 
649  return;
650 }
651 
652 void
654 {
655  auto it = burstTicks.begin();
656  while (it != burstTicks.end()) {
657  auto current_it = it++;
658  if (curTick() > *current_it) {
659  DPRINTF(MemCtrl, "Removing burstTick for %d\n", *current_it);
660  burstTicks.erase(current_it);
661  }
662  }
663 }
664 
665 Tick
667 {
668  // get tick aligned to burst window
669  Tick burst_offset = cmd_tick % commandWindow;
670  return (cmd_tick - burst_offset);
671 }
672 
673 Tick
674 MemCtrl::verifySingleCmd(Tick cmd_tick, Tick max_cmds_per_burst, bool row_cmd)
675 {
676  // start with assumption that there is no contention on command bus
677  Tick cmd_at = cmd_tick;
678 
679  // get tick aligned to burst window
680  Tick burst_tick = getBurstWindow(cmd_tick);
681 
682  // verify that we have command bandwidth to issue the command
683  // if not, iterate over next window(s) until slot found
684  while (burstTicks.count(burst_tick) >= max_cmds_per_burst) {
685  DPRINTF(MemCtrl, "Contention found on command bus at %d\n",
686  burst_tick);
687  burst_tick += commandWindow;
688  cmd_at = burst_tick;
689  }
690 
691  // add command into burst window and return corresponding Tick
692  burstTicks.insert(burst_tick);
693  return cmd_at;
694 }
695 
696 Tick
697 MemCtrl::verifyMultiCmd(Tick cmd_tick, Tick max_cmds_per_burst,
698  Tick max_multi_cmd_split)
699 {
700  // start with assumption that there is no contention on command bus
701  Tick cmd_at = cmd_tick;
702 
703  // get tick aligned to burst window
704  Tick burst_tick = getBurstWindow(cmd_tick);
705 
706  // Command timing requirements are from 2nd command
707  // Start with assumption that 2nd command will issue at cmd_at and
708  // find prior slot for 1st command to issue
709  // Given a maximum latency of max_multi_cmd_split between the commands,
710  // find the burst at the maximum latency prior to cmd_at
711  Tick burst_offset = 0;
712  Tick first_cmd_offset = cmd_tick % commandWindow;
713  while (max_multi_cmd_split > (first_cmd_offset + burst_offset)) {
714  burst_offset += commandWindow;
715  }
716  // get the earliest burst aligned address for first command
717  // ensure that the time does not go negative
718  Tick first_cmd_tick = burst_tick - std::min(burst_offset, burst_tick);
719 
720  // Can required commands issue?
721  bool first_can_issue = false;
722  bool second_can_issue = false;
723  // verify that we have command bandwidth to issue the command(s)
724  while (!first_can_issue || !second_can_issue) {
725  bool same_burst = (burst_tick == first_cmd_tick);
726  auto first_cmd_count = burstTicks.count(first_cmd_tick);
727  auto second_cmd_count = same_burst ? first_cmd_count + 1 :
728  burstTicks.count(burst_tick);
729 
730  first_can_issue = first_cmd_count < max_cmds_per_burst;
731  second_can_issue = second_cmd_count < max_cmds_per_burst;
732 
733  if (!second_can_issue) {
734  DPRINTF(MemCtrl, "Contention (cmd2) found on command bus at %d\n",
735  burst_tick);
736  burst_tick += commandWindow;
737  cmd_at = burst_tick;
738  }
739 
740  // Verify max_multi_cmd_split isn't violated when command 2 is shifted
741  // If commands initially were issued in same burst, they are
742  // now in consecutive bursts and can still issue B2B
743  bool gap_violated = !same_burst &&
744  ((burst_tick - first_cmd_tick) > max_multi_cmd_split);
745 
746  if (!first_can_issue || (!second_can_issue && gap_violated)) {
747  DPRINTF(MemCtrl, "Contention (cmd1) found on command bus at %d\n",
748  first_cmd_tick);
749  first_cmd_tick += commandWindow;
750  }
751  }
752 
753  // Add command to burstTicks
754  burstTicks.insert(burst_tick);
755  burstTicks.insert(first_cmd_tick);
756 
757  return cmd_at;
758 }
759 
760 bool
761 MemCtrl::inReadBusState(bool next_state) const
762 {
763  // check the bus state
764  if (next_state) {
765  // use busStateNext to get the state that will be used
766  // for the next burst
767  return (busStateNext == MemCtrl::READ);
768  } else {
769  return (busState == MemCtrl::READ);
770  }
771 }
772 
773 bool
774 MemCtrl::inWriteBusState(bool next_state) const
775 {
776  // check the bus state
777  if (next_state) {
778  // use busStateNext to get the state that will be used
779  // for the next burst
780  return (busStateNext == MemCtrl::WRITE);
781  } else {
782  return (busState == MemCtrl::WRITE);
783  }
784 }
785 
786 Tick
788 {
789  // first clean up the burstTick set, removing old entries
790  // before adding new entries for next burst
791  pruneBurstTick();
792 
793  // When was command issued?
794  Tick cmd_at;
795 
796  // Issue the next burst and update bus state to reflect
797  // when previous command was issued
798  std::vector<MemPacketQueue>& queue = selQueue(mem_pkt->isRead());
799  std::tie(cmd_at, mem_intr->nextBurstAt) =
800  mem_intr->doBurstAccess(mem_pkt, mem_intr->nextBurstAt, queue);
801 
802  DPRINTF(MemCtrl, "Access to %#x, ready at %lld next burst at %lld.\n",
803  mem_pkt->addr, mem_pkt->readyTime, mem_intr->nextBurstAt);
804 
805  // Update the minimum timing between the requests, this is a
806  // conservative estimate of when we have to schedule the next
807  // request to not introduce any unecessary bubbles. In most cases
808  // we will wake up sooner than we have to.
809  mem_intr->nextReqTime = mem_intr->nextBurstAt - mem_intr->commandOffset();
810 
811  // Update the common bus stats
812  if (mem_pkt->isRead()) {
813  ++readsThisTime;
814  // Update latency stats
816  mem_pkt->readyTime - mem_pkt->entryTime;
817  stats.requestorReadBytes[mem_pkt->requestorId()] += mem_pkt->size;
818  } else {
819  ++writesThisTime;
820  stats.requestorWriteBytes[mem_pkt->requestorId()] += mem_pkt->size;
822  mem_pkt->readyTime - mem_pkt->entryTime;
823  }
824 
825  return cmd_at;
826 }
827 
828 bool
830 
831  // check ranks for refresh/wakeup - uses busStateNext, so done after
832  // turnaround decisions
833  // Default to busy status and update based on interface specifics
834  // Default state of unused interface is 'true'
835  bool mem_busy = true;
836  bool all_writes_nvm = mem_intr->numWritesQueued == totalWriteQueueSize;
837  bool read_queue_empty = totalReadQueueSize == 0;
838  mem_busy = mem_intr->isBusy(read_queue_empty, all_writes_nvm);
839  if (mem_busy) {
840  // if all ranks are refreshing wait for them to finish
841  // and stall this state machine without taking any further
842  // action, and do not schedule a new nextReqEvent
843  return true;
844  } else {
845  return false;
846  }
847 }
848 
849 bool
851 
852  bool all_writes_nvm = mem_intr->numWritesQueued == totalWriteQueueSize;
853  return (mem_intr->writeRespQueueFull() && all_writes_nvm);
854 }
855 
856 void
858 
859  for (auto queue = readQueue.rbegin();
860  queue != readQueue.rend(); ++queue) {
861  // select non-deterministic NVM read to issue
862  // assume that we have the command bandwidth to issue this along
863  // with additional RD/WR burst with needed bank operations
864  if (mem_intr->readsWaitingToIssue()) {
865  // select non-deterministic NVM read to issue
866  mem_intr->chooseRead(*queue);
867  }
868  }
869 }
870 
871 void
873  MemPacketQueue& resp_queue,
874  EventFunctionWrapper& resp_event,
875  EventFunctionWrapper& next_req_event,
876  bool& retry_wr_req) {
877  // transition is handled by QoS algorithm if enabled
878  if (turnPolicy) {
879  // select bus state - only done if QoS algorithms are in use
881  }
882 
883  // detect bus state change
884  bool switched_cmd_type = (busState != busStateNext);
885  // record stats
887 
888  DPRINTF(MemCtrl, "QoS Turnarounds selected state %s %s\n",
889  (busState==MemCtrl::READ)?"READ":"WRITE",
890  switched_cmd_type?"[turnaround triggered]":"");
891 
892  if (switched_cmd_type) {
893  if (busState == MemCtrl::READ) {
895  "Switching to writes after %d reads with %d reads "
896  "waiting\n", readsThisTime, totalReadQueueSize);
898  readsThisTime = 0;
899  } else {
901  "Switching to reads after %d writes with %d writes "
902  "waiting\n", writesThisTime, totalWriteQueueSize);
904  writesThisTime = 0;
905  }
906  }
907 
908  // updates current state
910 
911  nonDetermReads(mem_intr);
912 
913  if (memBusy(mem_intr)) {
914  return;
915  }
916 
917  // when we get here it is either a read or a write
918  if (busState == READ) {
919 
920  // track if we should switch or not
921  bool switch_to_writes = false;
922 
923  if (totalReadQueueSize == 0) {
924  // In the case there is no read request to go next,
925  // trigger writes if we have passed the low threshold (or
926  // if we are draining)
927  if (!(totalWriteQueueSize == 0) &&
930 
932  "Switching to writes due to read queue empty\n");
933  switch_to_writes = true;
934  } else {
935  // check if we are drained
936  // not done draining until in PWR_IDLE state
937  // ensuring all banks are closed and
938  // have exited low power states
939  if (drainState() == DrainState::Draining &&
940  respQEmpty() && allIntfDrained()) {
941 
942  DPRINTF(Drain, "MemCtrl controller done draining\n");
943  signalDrainDone();
944  }
945 
946  // nothing to do, not even any point in scheduling an
947  // event for the next request
948  return;
949  }
950  } else {
951 
952  bool read_found = false;
953  MemPacketQueue::iterator to_read;
954  uint8_t prio = numPriorities();
955 
956  for (auto queue = readQueue.rbegin();
957  queue != readQueue.rend(); ++queue) {
958 
959  prio--;
960 
961  DPRINTF(QOS,
962  "Checking READ queue [%d] priority [%d elements]\n",
963  prio, queue->size());
964 
965  // Figure out which read request goes next
966  // If we are changing command type, incorporate the minimum
967  // bus turnaround delay which will be rank to rank delay
968  to_read = chooseNext((*queue), switched_cmd_type ?
969  minWriteToReadDataGap() : 0, mem_intr);
970 
971  if (to_read != queue->end()) {
972  // candidate read found
973  read_found = true;
974  break;
975  }
976  }
977 
978  // if no read to an available rank is found then return
979  // at this point. There could be writes to the available ranks
980  // which are above the required threshold. However, to
981  // avoid adding more complexity to the code, return and wait
982  // for a refresh event to kick things into action again.
983  if (!read_found) {
984  DPRINTF(MemCtrl, "No Reads Found - exiting\n");
985  return;
986  }
987 
988  auto mem_pkt = *to_read;
989 
990  Tick cmd_at = doBurstAccess(mem_pkt, mem_intr);
991 
993  "Command for %#x, issued at %lld.\n", mem_pkt->addr, cmd_at);
994 
995  // sanity check
996  assert(pktSizeCheck(mem_pkt, mem_intr));
997  assert(mem_pkt->readyTime >= curTick());
998 
999  // log the response
1000  logResponse(MemCtrl::READ, (*to_read)->requestorId(),
1001  mem_pkt->qosValue(), mem_pkt->getAddr(), 1,
1002  mem_pkt->readyTime - mem_pkt->entryTime);
1003 
1004 
1005  // Insert into response queue. It will be sent back to the
1006  // requestor at its readyTime
1007  if (resp_queue.empty()) {
1008  assert(!resp_event.scheduled());
1009  schedule(resp_event, mem_pkt->readyTime);
1010  } else {
1011  assert(resp_queue.back()->readyTime <= mem_pkt->readyTime);
1012  assert(resp_event.scheduled());
1013  }
1014 
1015  resp_queue.push_back(mem_pkt);
1016 
1017  // we have so many writes that we have to transition
1018  // don't transition if the writeRespQueue is full and
1019  // there are no other writes that can issue
1020  // Also ensure that we've issued a minimum defined number
1021  // of reads before switching, or have emptied the readQ
1024  && !(nvmWriteBlock(mem_intr))) {
1025  switch_to_writes = true;
1026  }
1027 
1028  // remove the request from the queue
1029  // the iterator is no longer valid .
1030  readQueue[mem_pkt->qosValue()].erase(to_read);
1031  }
1032 
1033  // switching to writes, either because the read queue is empty
1034  // and the writes have passed the low threshold (or we are
1035  // draining), or because the writes hit the hight threshold
1036  if (switch_to_writes) {
1037  // transition to writing
1038  busStateNext = WRITE;
1039  }
1040  } else {
1041 
1042  bool write_found = false;
1043  MemPacketQueue::iterator to_write;
1044  uint8_t prio = numPriorities();
1045 
1046  for (auto queue = writeQueue.rbegin();
1047  queue != writeQueue.rend(); ++queue) {
1048 
1049  prio--;
1050 
1051  DPRINTF(QOS,
1052  "Checking WRITE queue [%d] priority [%d elements]\n",
1053  prio, queue->size());
1054 
1055  // If we are changing command type, incorporate the minimum
1056  // bus turnaround delay
1057  to_write = chooseNext((*queue),
1058  switched_cmd_type ? minReadToWriteDataGap() : 0, mem_intr);
1059 
1060  if (to_write != queue->end()) {
1061  write_found = true;
1062  break;
1063  }
1064  }
1065 
1066  // if there are no writes to a rank that is available to service
1067  // requests (i.e. rank is in refresh idle state) are found then
1068  // return. There could be reads to the available ranks. However, to
1069  // avoid adding more complexity to the code, return at this point and
1070  // wait for a refresh event to kick things into action again.
1071  if (!write_found) {
1072  DPRINTF(MemCtrl, "No Writes Found - exiting\n");
1073  return;
1074  }
1075 
1076  auto mem_pkt = *to_write;
1077 
1078  // sanity check
1079  assert(pktSizeCheck(mem_pkt, mem_intr));
1080 
1081  Tick cmd_at = doBurstAccess(mem_pkt, mem_intr);
1082  DPRINTF(MemCtrl,
1083  "Command for %#x, issued at %lld.\n", mem_pkt->addr, cmd_at);
1084 
1085  isInWriteQueue.erase(burstAlign(mem_pkt->addr, mem_intr));
1086 
1087  // log the response
1088  logResponse(MemCtrl::WRITE, mem_pkt->requestorId(),
1089  mem_pkt->qosValue(), mem_pkt->getAddr(), 1,
1090  mem_pkt->readyTime - mem_pkt->entryTime);
1091 
1092 
1093  // remove the request from the queue - the iterator is no longer valid
1094  writeQueue[mem_pkt->qosValue()].erase(to_write);
1095 
1096  delete mem_pkt;
1097 
1098  // If we emptied the write queue, or got sufficiently below the
1099  // threshold (using the minWritesPerSwitch as the hysteresis) and
1100  // are not draining, or we have reads waiting and have done enough
1101  // writes, then switch to reads.
1102  // If we are interfacing to NVM and have filled the writeRespQueue,
1103  // with only NVM writes in Q, then switch to reads
1104  bool below_threshold =
1106 
1107  if (totalWriteQueueSize == 0 ||
1108  (below_threshold && drainState() != DrainState::Draining) ||
1110  (totalReadQueueSize && (nvmWriteBlock(mem_intr)))) {
1111 
1112  // turn the bus back around for reads again
1114 
1115  // note that the we switch back to reads also in the idle
1116  // case, which eventually will check for any draining and
1117  // also pause any further scheduling if there is really
1118  // nothing to do
1119  }
1120  }
1121  // It is possible that a refresh to another rank kicks things back into
1122  // action before reaching this point.
1123  if (!next_req_event.scheduled())
1124  schedule(next_req_event, std::max(mem_intr->nextReqTime, curTick()));
1125 
1126  if (retry_wr_req && totalWriteQueueSize < writeBufferSize) {
1127  retry_wr_req = false;
1128  port.sendRetryReq();
1129  }
1130 }
1131 
1132 bool
1134 {
1135  return mem_intr->burstReady(pkt);
1136 }
1137 
1138 Tick
1140 {
1141  return dram->minReadToWriteDataGap();
1142 }
1143 
1144 Tick
1146 {
1147  return dram->minWriteToReadDataGap();
1148 }
1149 
1150 Addr
1152 {
1153  return (addr & ~(Addr(mem_intr->bytesPerBurst() - 1)));
1154 }
1155 
1156 bool
1158 {
1159  return (mem_pkt->size <= mem_intr->bytesPerBurst());
1160 }
1161 
1163  : statistics::Group(&_ctrl),
1164  ctrl(_ctrl),
1165 
1166  ADD_STAT(readReqs, statistics::units::Count::get(),
1167  "Number of read requests accepted"),
1168  ADD_STAT(writeReqs, statistics::units::Count::get(),
1169  "Number of write requests accepted"),
1170 
1171  ADD_STAT(readBursts, statistics::units::Count::get(),
1172  "Number of controller read bursts, including those serviced by "
1173  "the write queue"),
1174  ADD_STAT(writeBursts, statistics::units::Count::get(),
1175  "Number of controller write bursts, including those merged in "
1176  "the write queue"),
1177  ADD_STAT(servicedByWrQ, statistics::units::Count::get(),
1178  "Number of controller read bursts serviced by the write queue"),
1179  ADD_STAT(mergedWrBursts, statistics::units::Count::get(),
1180  "Number of controller write bursts merged with an existing one"),
1181 
1182  ADD_STAT(neitherReadNorWriteReqs, statistics::units::Count::get(),
1183  "Number of requests that are neither read nor write"),
1184 
1185  ADD_STAT(avgRdQLen, statistics::units::Rate<
1186  statistics::units::Count, statistics::units::Tick>::get(),
1187  "Average read queue length when enqueuing"),
1188  ADD_STAT(avgWrQLen, statistics::units::Rate<
1189  statistics::units::Count, statistics::units::Tick>::get(),
1190  "Average write queue length when enqueuing"),
1191 
1192  ADD_STAT(numRdRetry, statistics::units::Count::get(),
1193  "Number of times read queue was full causing retry"),
1194  ADD_STAT(numWrRetry, statistics::units::Count::get(),
1195  "Number of times write queue was full causing retry"),
1196 
1197  ADD_STAT(readPktSize, statistics::units::Count::get(),
1198  "Read request sizes (log2)"),
1199  ADD_STAT(writePktSize, statistics::units::Count::get(),
1200  "Write request sizes (log2)"),
1201 
1202  ADD_STAT(rdQLenPdf, statistics::units::Count::get(),
1203  "What read queue length does an incoming req see"),
1204  ADD_STAT(wrQLenPdf, statistics::units::Count::get(),
1205  "What write queue length does an incoming req see"),
1206 
1207  ADD_STAT(rdPerTurnAround, statistics::units::Count::get(),
1208  "Reads before turning the bus around for writes"),
1209  ADD_STAT(wrPerTurnAround, statistics::units::Count::get(),
1210  "Writes before turning the bus around for reads"),
1211 
1212  ADD_STAT(bytesReadWrQ, statistics::units::Byte::get(),
1213  "Total number of bytes read from write queue"),
1214  ADD_STAT(bytesReadSys, statistics::units::Byte::get(),
1215  "Total read bytes from the system interface side"),
1216  ADD_STAT(bytesWrittenSys, statistics::units::Byte::get(),
1217  "Total written bytes from the system interface side"),
1218 
1219  ADD_STAT(avgRdBWSys, statistics::units::Rate<
1220  statistics::units::Byte, statistics::units::Second>::get(),
1221  "Average system read bandwidth in Byte/s"),
1222  ADD_STAT(avgWrBWSys, statistics::units::Rate<
1223  statistics::units::Byte, statistics::units::Second>::get(),
1224  "Average system write bandwidth in Byte/s"),
1225 
1226  ADD_STAT(totGap, statistics::units::Tick::get(),
1227  "Total gap between requests"),
1228  ADD_STAT(avgGap, statistics::units::Rate<
1229  statistics::units::Tick, statistics::units::Count>::get(),
1230  "Average gap between requests"),
1231 
1232  ADD_STAT(requestorReadBytes, statistics::units::Byte::get(),
1233  "Per-requestor bytes read from memory"),
1234  ADD_STAT(requestorWriteBytes, statistics::units::Byte::get(),
1235  "Per-requestor bytes write to memory"),
1236  ADD_STAT(requestorReadRate, statistics::units::Rate<
1237  statistics::units::Byte, statistics::units::Second>::get(),
1238  "Per-requestor bytes read from memory rate"),
1239  ADD_STAT(requestorWriteRate, statistics::units::Rate<
1240  statistics::units::Byte, statistics::units::Second>::get(),
1241  "Per-requestor bytes write to memory rate"),
1242  ADD_STAT(requestorReadAccesses, statistics::units::Count::get(),
1243  "Per-requestor read serviced memory accesses"),
1244  ADD_STAT(requestorWriteAccesses, statistics::units::Count::get(),
1245  "Per-requestor write serviced memory accesses"),
1246  ADD_STAT(requestorReadTotalLat, statistics::units::Tick::get(),
1247  "Per-requestor read total memory access latency"),
1248  ADD_STAT(requestorWriteTotalLat, statistics::units::Tick::get(),
1249  "Per-requestor write total memory access latency"),
1250  ADD_STAT(requestorReadAvgLat, statistics::units::Rate<
1251  statistics::units::Tick, statistics::units::Count>::get(),
1252  "Per-requestor read average memory access latency"),
1253  ADD_STAT(requestorWriteAvgLat, statistics::units::Rate<
1254  statistics::units::Tick, statistics::units::Count>::get(),
1255  "Per-requestor write average memory access latency")
1256 {
1257 }
1258 
1259 void
1261 {
1262  using namespace statistics;
1263 
1264  assert(ctrl.system());
1265  const auto max_requestors = ctrl.system()->maxRequestors();
1266 
1267  avgRdQLen.precision(2);
1268  avgWrQLen.precision(2);
1269 
1270  readPktSize.init(ceilLog2(ctrl.system()->cacheLineSize()) + 1);
1271  writePktSize.init(ceilLog2(ctrl.system()->cacheLineSize()) + 1);
1272 
1273  rdQLenPdf.init(ctrl.readBufferSize);
1274  wrQLenPdf.init(ctrl.writeBufferSize);
1275 
1276  rdPerTurnAround
1277  .init(ctrl.readBufferSize)
1278  .flags(nozero);
1279  wrPerTurnAround
1280  .init(ctrl.writeBufferSize)
1281  .flags(nozero);
1282 
1283  avgRdBWSys.precision(8);
1284  avgWrBWSys.precision(8);
1285  avgGap.precision(2);
1286 
1287  // per-requestor bytes read and written to memory
1288  requestorReadBytes
1289  .init(max_requestors)
1290  .flags(nozero | nonan);
1291 
1292  requestorWriteBytes
1293  .init(max_requestors)
1294  .flags(nozero | nonan);
1295 
1296  // per-requestor bytes read and written to memory rate
1297  requestorReadRate
1298  .flags(nozero | nonan)
1299  .precision(12);
1300 
1301  requestorReadAccesses
1302  .init(max_requestors)
1303  .flags(nozero);
1304 
1305  requestorWriteAccesses
1306  .init(max_requestors)
1307  .flags(nozero);
1308 
1309  requestorReadTotalLat
1310  .init(max_requestors)
1311  .flags(nozero | nonan);
1312 
1313  requestorReadAvgLat
1314  .flags(nonan)
1315  .precision(2);
1316 
1317  requestorWriteRate
1318  .flags(nozero | nonan)
1319  .precision(12);
1320 
1321  requestorWriteTotalLat
1322  .init(max_requestors)
1323  .flags(nozero | nonan);
1324 
1325  requestorWriteAvgLat
1326  .flags(nonan)
1327  .precision(2);
1328 
1329  for (int i = 0; i < max_requestors; i++) {
1330  const std::string requestor = ctrl.system()->getRequestorName(i);
1331  requestorReadBytes.subname(i, requestor);
1332  requestorReadRate.subname(i, requestor);
1333  requestorWriteBytes.subname(i, requestor);
1334  requestorWriteRate.subname(i, requestor);
1335  requestorReadAccesses.subname(i, requestor);
1336  requestorWriteAccesses.subname(i, requestor);
1337  requestorReadTotalLat.subname(i, requestor);
1338  requestorReadAvgLat.subname(i, requestor);
1339  requestorWriteTotalLat.subname(i, requestor);
1340  requestorWriteAvgLat.subname(i, requestor);
1341  }
1342 
1343  // Formula stats
1344  avgRdBWSys = (bytesReadSys) / simSeconds;
1345  avgWrBWSys = (bytesWrittenSys) / simSeconds;
1346 
1347  avgGap = totGap / (readReqs + writeReqs);
1348 
1349  requestorReadRate = requestorReadBytes / simSeconds;
1350  requestorWriteRate = requestorWriteBytes / simSeconds;
1351  requestorReadAvgLat = requestorReadTotalLat / requestorReadAccesses;
1352  requestorWriteAvgLat = requestorWriteTotalLat / requestorWriteAccesses;
1353 }
1354 
1355 void
1357 {
1358  bool found = recvFunctionalLogic(pkt, dram);
1359 
1360  panic_if(!found, "Can't handle address range for packet %s\n",
1361  pkt->print());
1362 }
1363 
1364 bool
1366 {
1367  if (mem_intr->getAddrRange().contains(pkt->getAddr())) {
1368  // rely on the abstract memory
1369  mem_intr->functionalAccess(pkt);
1370  return true;
1371  } else {
1372  return false;
1373  }
1374 }
1375 
1376 Port &
1377 MemCtrl::getPort(const std::string &if_name, PortID idx)
1378 {
1379  if (if_name != "port") {
1380  return qos::MemCtrl::getPort(if_name, idx);
1381  } else {
1382  return port;
1383  }
1384 }
1385 
1386 bool
1388 {
1389  // DRAM: ensure dram is in power down and refresh IDLE states
1390  // NVM: No outstanding NVM writes
1391  // NVM: All other queues verified as needed with calling logic
1392  return dram->allRanksDrained();
1393 }
1394 
1395 DrainState
1397 {
1398  // if there is anything in any of our internal queues, keep track
1399  // of that as well
1400  if (!(!totalWriteQueueSize && !totalReadQueueSize && respQueue.empty() &&
1401  allIntfDrained())) {
1402 
1403  DPRINTF(Drain, "Memory controller not drained, write: %d, read: %d,"
1404  " resp: %d\n", totalWriteQueueSize, totalReadQueueSize,
1405  respQueue.size());
1406 
1407  // the only queue that is not drained automatically over time
1408  // is the write queue, thus kick things into action if needed
1411  }
1412 
1413  dram->drainRanks();
1414 
1415  return DrainState::Draining;
1416  } else {
1417  return DrainState::Drained;
1418  }
1419 }
1420 
1421 void
1423 {
1424  if (!isTimingMode && system()->isTimingMode()) {
1425  // if we switched to timing mode, kick things into action,
1426  // and behave as if we restored from a checkpoint
1427  startup();
1428  dram->startup();
1429  } else if (isTimingMode && !system()->isTimingMode()) {
1430  // if we switch from timing mode, stop the refresh events to
1431  // not cause issues with KVM
1432  dram->suspend();
1433  }
1434 
1435  // update the mode
1437 }
1438 
1441 {
1442  AddrRangeList range;
1443  range.push_back(dram->getAddrRange());
1444  return range;
1445 }
1446 
1448 MemoryPort(const std::string& name, MemCtrl& _ctrl)
1449  : QueuedResponsePort(name, &_ctrl, queue), queue(_ctrl, *this, true),
1450  ctrl(_ctrl)
1451 { }
1452 
1455 {
1456  return ctrl.getAddrRanges();
1457 }
1458 
1459 void
1461 {
1462  pkt->pushLabel(ctrl.name());
1463 
1464  if (!queue.trySatisfyFunctional(pkt)) {
1465  // Default implementation of SimpleTimingPort::recvFunctional()
1466  // calls recvAtomic() and throws away the latency; we can save a
1467  // little here by just not calculating the latency.
1468  ctrl.recvFunctional(pkt);
1469  }
1470 
1471  pkt->popLabel();
1472 }
1473 
1474 Tick
1476 {
1477  return ctrl.recvAtomic(pkt);
1478 }
1479 
1480 Tick
1482  PacketPtr pkt, MemBackdoorPtr &backdoor)
1483 {
1484  return ctrl.recvAtomicBackdoor(pkt, backdoor);
1485 }
1486 
1487 bool
1489 {
1490  // pass it to the memory controller
1491  return ctrl.recvTimingReq(pkt);
1492 }
1493 
1494 } // namespace memory
1495 } // namespace gem5
gem5::curTick
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
fatal
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
gem5::PortID
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:245
gem5::Packet::cmdString
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
Definition: packet.hh:585
gem5::memory::qos::MemCtrl::totalReadQueueSize
uint64_t totalReadQueueSize
Total read request packets queue length in #packets.
Definition: mem_ctrl.hh:131
gem5::SimObject::getPort
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
gem5::memory::MemInterface::respondEvent
virtual void respondEvent(uint8_t rank)
This function is DRAM specific.
Definition: mem_interface.hh:334
gem5::memory::MemCtrl::addToReadQueue
bool addToReadQueue(PacketPtr pkt, unsigned int pkt_count, MemInterface *mem_intr)
When a new read comes in, first check if the write q has a pending request to the same address....
Definition: mem_ctrl.cc:187
gem5::memory::MemCtrl::backendLatency
const Tick backendLatency
Pipeline latency of the backend and PHY.
Definition: mem_ctrl.hh:538
gem5::memory::MemCtrl::writeLowThreshold
uint32_t writeLowThreshold
Definition: mem_ctrl.hh:514
gem5::memory::MemCtrl::CtrlStats::bytesReadWrQ
statistics::Scalar bytesReadWrQ
Definition: mem_ctrl.hh:590
gem5::memory::MemCtrl::nextReqEvent
EventFunctionWrapper nextReqEvent
Definition: mem_ctrl.hh:304
gem5::memory::MemCtrl::verifySingleCmd
virtual Tick verifySingleCmd(Tick cmd_tick, Tick max_cmds_per_burst, bool row_cmd)
Check for command bus contention for single cycle command.
Definition: mem_ctrl.cc:674
gem5::memory::qos::MemCtrl::logResponse
void logResponse(BusState dir, RequestorID id, uint8_t _qos, Addr addr, uint64_t entries, double delay)
Called upon receiving a response, updates statistics and updates queues status.
Definition: mem_ctrl.cc:149
system.hh
gem5::memory::MemCtrl::MemoryPort::recvTimingReq
bool recvTimingReq(PacketPtr) override
Receive a timing request from the peer.
Definition: mem_ctrl.cc:1488
gem5::memory::MemPacket::burstHelper
BurstHelper * burstHelper
A pointer to the BurstHelper if this MemPacket is a split packet If not a split packet (common case),...
Definition: mem_ctrl.hh:152
gem5::memory::MemInterface::readsWaitingToIssue
virtual bool readsWaitingToIssue() const
This function is NVM specific.
Definition: mem_interface.hh:369
gem5::ResponsePort::sendRetryReq
void sendRetryReq()
Send a retry to the request port that previously attempted a sendTimingReq to this response port and ...
Definition: port.hh:401
gem5::memory::MemPacket::readyTime
Tick readyTime
When will request leave the controller.
Definition: mem_ctrl.hh:106
gem5::memory::MemPacket::size
unsigned int size
The size of this dram packet in bytes It is always equal or smaller than the burst size.
Definition: mem_ctrl.hh:146
gem5::memory::MemInterface::numWritesQueued
uint32_t numWritesQueued
NVM specific variable, but declaring it here allows treating different interfaces in a more genral wa...
Definition: mem_interface.hh:184
gem5::memory::MemCtrl::readsThisTime
uint32_t readsThisTime
Definition: mem_ctrl.hh:518
gem5::memory::MemInterface::suspend
virtual void suspend()
This function is DRAM specific.
Definition: mem_interface.hh:360
nvm_interface.hh
gem5::memory::MemCtrl::isInWriteQueue
std::unordered_set< Addr > isInWriteQueue
To avoid iterating over the write queue to check for overlapping transactions, maintain a set of burs...
Definition: mem_ctrl.hh:479
gem5::Drainable::drainState
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:324
memory
Definition: mem.h:38
gem5::memory::MemCtrl::recvAtomicBackdoor
virtual Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor)
Definition: mem_ctrl.cc:156
gem5::memory::MemCtrl::CtrlStats::requestorWriteAccesses
statistics::Vector requestorWriteAccesses
Definition: mem_ctrl.hh:610
gem5::memory::MemCtrl::MemoryPort::MemoryPort
MemoryPort(const std::string &name, MemCtrl &_ctrl)
Definition: mem_ctrl.cc:1448
gem5::memory::AbstractMemory::getAddrRange
AddrRange getAddrRange() const
Get the address range.
Definition: abstract_mem.cc:249
gem5::memory::qos::MemCtrl::READ
@ READ
Definition: mem_ctrl.hh:84
gem5::AddrRange::contains
bool contains(const Addr &a) const
Determine if the range contains an address.
Definition: addr_range.hh:471
gem5::statistics::nozero
const FlagsType nozero
Don't print if this is zero.
Definition: info.hh:68
gem5::memory::MemCtrl::CtrlStats::requestorReadTotalLat
statistics::Vector requestorReadTotalLat
Definition: mem_ctrl.hh:613
gem5::memory::MemPacket::pkt
const PacketPtr pkt
This comes from the outside world.
Definition: mem_ctrl.hh:109
gem5::Packet::qosValue
uint8_t qosValue() const
QoS Value getter Returns 0 if QoS value was never set (constructor default).
Definition: packet.hh:765
gem5::memory::MemInterface::allRanksDrained
virtual bool allRanksDrained() const =0
Check drain state of interface.
gem5::memory::MemCtrl::burstAlign
virtual Addr burstAlign(Addr addr, MemInterface *mem_intr) const
Burst-align an address.
Definition: mem_ctrl.cc:1151
gem5::memory::MemCtrl
The memory controller is a single-channel memory controller capturing the most important timing const...
Definition: mem_ctrl.hh:246
gem5::Packet::cacheResponding
bool cacheResponding() const
Definition: packet.hh:655
gem5::MaxTick
const Tick MaxTick
Definition: types.hh:60
gem5::Packet::isWrite
bool isWrite() const
Definition: packet.hh:591
gem5::memory::MemCtrl::writeHighThreshold
uint32_t writeHighThreshold
Definition: mem_ctrl.hh:513
std::vector
STL vector class.
Definition: stl.hh:37
gem5::memory::MemCtrl::respondEvent
EventFunctionWrapper respondEvent
Definition: mem_ctrl.hh:310
gem5::statistics::nonan
const FlagsType nonan
Don't print if this is NAN.
Definition: info.hh:70
gem5::memory::MemCtrl::startup
virtual void startup() override
startup() is the final initialization call before simulation.
Definition: mem_ctrl.cc:108
gem5::memory::MemCtrl::CtrlStats::requestorWriteTotalLat
statistics::Vector requestorWriteTotalLat
Definition: mem_ctrl.hh:614
gem5::memory::MemCtrl::prevArrival
Tick prevArrival
Definition: mem_ctrl.hh:551
gem5::memory::MemCtrl::selQueue
std::vector< MemPacketQueue > & selQueue(bool is_read)
Select either the read or write queue.
Definition: mem_ctrl.hh:635
gem5::memory::MemCtrl::doBurstAccess
virtual Tick doBurstAccess(MemPacket *mem_pkt, MemInterface *mem_intr)
Actually do the burst based on media specific access function.
Definition: mem_ctrl.cc:787
gem5::memory::MemCtrl::memSchedPolicy
enums::MemSched memSchedPolicy
Memory controller configuration initialized based on parameter values.
Definition: mem_ctrl.hh:524
gem5::ArmISA::i
Bitfield< 7 > i
Definition: misc_types.hh:67
gem5::memory::MemCtrl::CtrlStats::readPktSize
statistics::Vector readPktSize
Definition: mem_ctrl.hh:583
gem5::Packet::headerDelay
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition: packet.hh:428
gem5::memory::MemCtrl::MemCtrl
MemCtrl(const MemCtrlParams &p)
Definition: mem_ctrl.cc:60
gem5::memory::qos::MemCtrl::busStateNext
BusState busStateNext
bus state for next request event triggered
Definition: mem_ctrl.hh:143
gem5::memory::MemCtrl::minReadsPerSwitch
const uint32_t minReadsPerSwitch
Definition: mem_ctrl.hh:516
gem5::memory::qos::MemCtrl::busState
BusState busState
Bus state used to control the read/write switching and drive the scheduling of the next request.
Definition: mem_ctrl.hh:140
gem5::memory::qos::MemCtrl::qosSchedule
uint8_t qosSchedule(std::initializer_list< Queues * > queues_ptr, uint64_t queue_entry_size, const PacketPtr pkt)
Assign priority to a packet by executing the configured QoS policy.
Definition: mem_ctrl.hh:496
gem5::statistics::DistBase::sample
void sample(const U &v, int n=1)
Add a value to the distribtion n times.
Definition: statistics.hh:1328
gem5::memory::MemInterface::chooseRead
virtual void chooseRead(MemPacketQueue &queue)
This function is NVM specific.
Definition: mem_interface.hh:378
gem5::memory::MemCtrl::readBufferSize
uint32_t readBufferSize
The following are basic design parameters of the memory controller, and are initialized based on para...
Definition: mem_ctrl.hh:511
gem5::memory::MemCtrl::CtrlStats::bytesReadSys
statistics::Scalar bytesReadSys
Definition: mem_ctrl.hh:591
gem5::memory::MemCtrl::inReadBusState
bool inReadBusState(bool next_state) const
Check the current direction of the memory channel.
Definition: mem_ctrl.cc:761
gem5::memory::MemCtrl::retryRdReq
bool retryRdReq
Remember if we have to retry a request when available.
Definition: mem_ctrl.hh:290
gem5::memory::MemCtrl::CtrlStats::requestorReadAccesses
statistics::Vector requestorReadAccesses
Definition: mem_ctrl.hh:609
gem5::memory::MemPacket::entryTime
const Tick entryTime
When did request enter the controller.
Definition: mem_ctrl.hh:103
gem5::Packet::hasData
bool hasData() const
Definition: packet.hh:611
gem5::memory::MemInterface::minWriteToReadDataGap
Tick minWriteToReadDataGap() const
Definition: mem_interface.hh:287
gem5::memory::qos::MemCtrl::turnPolicy
const std::unique_ptr< TurnaroundPolicy > turnPolicy
QoS Bus Turnaround Policy: selects the bus direction (READ/WRITE)
Definition: mem_ctrl.hh:91
gem5::memory::MemCtrl::CtrlStats::avgWrQLen
statistics::Average avgWrQLen
Definition: mem_ctrl.hh:579
gem5::Packet::payloadDelay
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition: packet.hh:446
gem5::memory::MemCtrl::recvAtomic
virtual Tick recvAtomic(PacketPtr pkt)
Definition: mem_ctrl.cc:123
gem5::memory::MemCtrl::CtrlStats::writePktSize
statistics::Vector writePktSize
Definition: mem_ctrl.hh:584
gem5::memory::MemCtrl::writeQueue
std::vector< MemPacketQueue > writeQueue
Definition: mem_ctrl.hh:470
gem5::memory::MemInterface::drainRanks
virtual void drainRanks()
This function is DRAM specific.
Definition: mem_interface.hh:351
gem5::DrainState
DrainState
Object drain/handover states.
Definition: drain.hh:74
gem5::memory::MemCtrl::inWriteBusState
bool inWriteBusState(bool next_state) const
Check the current direction of the memory channel.
Definition: mem_ctrl.cc:774
gem5::memory::qos::MemCtrl::schedule
uint8_t schedule(RequestorID id, uint64_t data)
Definition: mem_ctrl.cc:218
gem5::memory::MemInterface::doBurstAccess
virtual std::pair< Tick, Tick > doBurstAccess(MemPacket *mem_pkt, Tick next_burst_at, const std::vector< MemPacketQueue > &queue)=0
This function performs the burst and update stats.
mem_interface.hh
gem5::Packet::isRead
bool isRead() const
Definition: packet.hh:590
gem5::memory::MemPacket::addr
Addr addr
The starting address of the packet.
Definition: mem_ctrl.hh:140
gem5::memory::MemCtrl::processRespondEvent
virtual void processRespondEvent(MemInterface *mem_intr, MemPacketQueue &queue, EventFunctionWrapper &resp_event, bool &retry_rd_req)
Definition: mem_ctrl.cc:482
gem5::memory::MemCtrl::minWriteToReadDataGap
virtual Tick minWriteToReadDataGap()
Calculate the minimum delay used when scheduling a write-to-read transision.
Definition: mem_ctrl.cc:1145
gem5::memory::MemCtrl::port
MemoryPort port
Our incoming port, for a multi-ported controller add a crossbar in front of it.
Definition: mem_ctrl.hh:280
gem5::memory::MemCtrl::CtrlStats::CtrlStats
CtrlStats(MemCtrl &ctrl)
Definition: mem_ctrl.cc:1162
gem5::memory::MemInterface
General interface to memory device Includes functions and parameters shared across media types.
Definition: mem_interface.hh:74
gem5::memory::MemInterface::isBusy
virtual bool isBusy(bool read_queue_empty, bool all_writes_nvm)=0
This function checks if ranks are busy.
gem5::memory::MemInterface::setupRank
virtual void setupRank(const uint8_t rank, const bool is_read)=0
Setup the rank based on packet received.
gem5::memory::MemCtrl::CtrlStats::requestorReadBytes
statistics::Vector requestorReadBytes
Definition: mem_ctrl.hh:601
gem5::memory::AbstractMemory::functionalAccess
void functionalAccess(PacketPtr pkt)
Perform an untimed memory read or write without changing anything but the memory itself.
Definition: abstract_mem.cc:481
gem5::memory::MemCtrl::CtrlStats::numWrRetry
statistics::Scalar numWrRetry
Definition: mem_ctrl.hh:582
gem5::Named::name
virtual std::string name() const
Definition: named.hh:47
gem5::Packet::requestorId
RequestorID requestorId() const
Definition: packet.hh:776
gem5::VegaISA::p
Bitfield< 54 > p
Definition: pagetable.hh:70
gem5::Packet::print
void print(std::ostream &o, int verbosity=0, const std::string &prefix="") const
Definition: packet.cc:364
gem5::memory::qos::MemCtrl::selectNextBusState
BusState selectNextBusState()
Returns next bus direction (READ or WRITE) based on configured policy.
Definition: mem_ctrl.cc:247
gem5::QueuedResponsePort
A queued port is a port that has an infinite queue for outgoing packets and thus decouples the module...
Definition: qport.hh:61
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:186
ADD_STAT
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
gem5::Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:291
gem5::memory::MemCtrl::readQueueFull
bool readQueueFull(unsigned int pkt_count) const
Check if the read queue has room for more entries.
Definition: mem_ctrl.cc:164
gem5::Tick
uint64_t Tick
Tick count type.
Definition: types.hh:58
gem5::memory::MemCtrl::recvFunctional
virtual void recvFunctional(PacketPtr pkt)
Definition: mem_ctrl.cc:1356
gem5::memory::MemCtrl::packetReady
virtual bool packetReady(MemPacket *pkt, MemInterface *mem_intr)
Determine if there is a packet that can issue.
Definition: mem_ctrl.cc:1133
gem5::memory::MemCtrl::recvTimingReq
virtual bool recvTimingReq(PacketPtr pkt)
Definition: mem_ctrl.cc:401
gem5::memory::MemPacket
A memory packet stores packets along with the timestamp of when the packet entered the queue,...
Definition: mem_ctrl.hh:98
gem5::memory::MemInterface::commandOffset
virtual Tick commandOffset() const =0
gem5::memory::MemCtrl::stats
CtrlStats stats
Definition: mem_ctrl.hh:621
gem5::memory::MemCtrl::drain
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
Definition: mem_ctrl.cc:1396
gem5::memory::MemCtrl::getAddrRanges
virtual AddrRangeList getAddrRanges()
Definition: mem_ctrl.cc:1440
gem5::memory::MemCtrl::writeBufferSize
uint32_t writeBufferSize
Definition: mem_ctrl.hh:512
gem5::memory::qos::MemCtrl::system
System * system() const
read the system pointer
Definition: mem_ctrl.hh:371
gem5::memory::MemCtrl::init
virtual void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: mem_ctrl.cc:98
gem5::memory::MemPacket::pseudoChannel
const uint8_t pseudoChannel
pseudo channel num
Definition: mem_ctrl.hh:120
gem5::memory::MemInterface::burstReady
virtual bool burstReady(MemPacket *pkt) const =0
Check if a burst operation can be issued to the interface.
gem5::memory::MemCtrl::recvFunctionalLogic
bool recvFunctionalLogic(PacketPtr pkt, MemInterface *mem_intr)
Definition: mem_ctrl.cc:1365
gem5::memory::MemPacket::qosValue
void qosValue(const uint8_t qv)
Set the packet QoS value (interface compatibility with Packet)
Definition: mem_ctrl.hh:163
gem5::memory::MemCtrl::pruneBurstTick
virtual void pruneBurstTick()
Remove commands that have already issued from burstTicks.
Definition: mem_ctrl.cc:653
gem5::memory::MemCtrl::pendingDelete
std::unique_ptr< Packet > pendingDelete
Upstream caches need this packet until true is returned, so hold it for deletion until a subsequent c...
Definition: mem_ctrl.hh:627
gem5::memory::MemCtrl::retryWrReq
bool retryWrReq
Definition: mem_ctrl.hh:291
gem5::memory::qos::MemCtrl::totalWriteQueueSize
uint64_t totalWriteQueueSize
Total write request packets queue length in #packets.
Definition: mem_ctrl.hh:134
gem5::memory::MemInterface::checkRefreshState
virtual void checkRefreshState(uint8_t rank)
This function is DRAM specific.
Definition: mem_interface.hh:342
gem5::ArmISA::offset
Bitfield< 23, 0 > offset
Definition: types.hh:144
gem5::memory::MemCtrl::allIntfDrained
virtual bool allIntfDrained() const
Ensure that all interfaced have drained commands.
Definition: mem_ctrl.cc:1387
gem5::memory::MemCtrl::CtrlStats::rdQLenPdf
statistics::Vector rdQLenPdf
Definition: mem_ctrl.hh:585
gem5::Port::isConnected
bool isConnected() const
Is this port currently connected to a peer?
Definition: port.hh:133
gem5::memory::MemCtrl::CtrlStats::bytesWrittenSys
statistics::Scalar bytesWrittenSys
Definition: mem_ctrl.hh:592
mem_ctrl.hh
gem5::memory::MemCtrl::MemoryPort::recvFunctional
void recvFunctional(PacketPtr pkt) override
Receive a functional request packet from the peer.
Definition: mem_ctrl.cc:1460
gem5::memory::MemCtrl::CtrlStats::writeReqs
statistics::Scalar writeReqs
Definition: mem_ctrl.hh:571
gem5::memory::BurstHelper::burstsServiced
unsigned int burstsServiced
Number of bursts serviced so far for a system packet.
Definition: mem_ctrl.hh:87
gem5::memory::MemCtrl::CtrlStats::regStats
void regStats() override
Callback to set stat parameters.
Definition: mem_ctrl.cc:1260
gem5::memory::MemPacket::requestorId
RequestorID requestorId() const
Get the packet RequestorID (interface compatibility with Packet)
Definition: mem_ctrl.hh:175
gem5::DrainState::Drained
@ Drained
Buffers drained, ready for serialization/handover.
gem5::System::isTimingMode
bool isTimingMode() const
Is the system in timing mode?
Definition: system.hh:274
gem5::memory::MemInterface::minReadToWriteDataGap
Tick minReadToWriteDataGap() const
Definition: mem_interface.hh:281
gem5::memory::MemCtrl::dram
MemInterface * dram
Definition: mem_ctrl.hh:501
gem5::memory::MemCtrl::isTimingMode
bool isTimingMode
Remember if the memory system is in timing mode.
Definition: mem_ctrl.hh:285
gem5::Packet::pushLabel
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1433
std::pair
STL pair class.
Definition: stl.hh:58
gem5::Packet::popLabel
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1443
gem5::Packet::needsResponse
bool needsResponse() const
Definition: packet.hh:605
gem5::memory::MemCtrl::CtrlStats::numRdRetry
statistics::Scalar numRdRetry
Definition: mem_ctrl.hh:581
gem5::Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
gem5::memory::MemCtrl::respQueue
std::deque< MemPacket * > respQueue
Response queue where read packets wait after we're done working with them, but it's not time to send ...
Definition: mem_ctrl.hh:489
gem5::memory::MemCtrl::frontendLatency
const Tick frontendLatency
Pipeline latency of the controller frontend.
Definition: mem_ctrl.hh:531
gem5::memory::MemCtrl::CtrlStats::wrQLenPdf
statistics::Vector wrQLenPdf
Definition: mem_ctrl.hh:586
gem5::memory::MemCtrl::MemoryPort::recvAtomicBackdoor
Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor) override
Receive an atomic request packet from the peer, and optionally provide a backdoor to the data being a...
Definition: mem_ctrl.cc:1481
gem5::memory::MemCtrl::pktSizeCheck
virtual bool pktSizeCheck(MemPacket *mem_pkt, MemInterface *mem_intr) const
Check if mem pkt's size is sane.
Definition: mem_ctrl.cc:1157
name
const std::string & name()
Definition: trace.cc:49
gem5::MemBackdoor
Definition: backdoor.hh:41
gem5::memory::MemCtrl::CtrlStats::servicedByWrQ
statistics::Scalar servicedByWrQ
Definition: mem_ctrl.hh:574
gem5::memory::MemCtrl::CtrlStats::totGap
statistics::Scalar totGap
Definition: mem_ctrl.hh:597
gem5::ResponsePort::sendRangeChange
void sendRangeChange() const
Called by the owner to send a range change.
Definition: port.hh:296
gem5::memory::MemInterface::nextBurstAt
Tick nextBurstAt
Till when the controller must wait before issuing next RD/WR burst?
Definition: mem_interface.hh:189
gem5::memory::AbstractMemory::getBackdoor
void getBackdoor(MemBackdoorPtr &bd_ptr)
Definition: abstract_mem.hh:238
gem5::memory::MemCtrl::chooseNextFRFCFS
virtual std::pair< MemPacketQueue::iterator, Tick > chooseNextFRFCFS(MemPacketQueue &queue, Tick extra_col_delay, MemInterface *mem_intr)
For FR-FCFS policy reorder the read/write queue depending on row buffer hits and earliest bursts avai...
Definition: mem_ctrl.cc:592
gem5::memory::MemCtrl::readQueue
std::vector< MemPacketQueue > readQueue
The controller's main read and write queues, with support for QoS reordering.
Definition: mem_ctrl.hh:469
gem5::memory::MemCtrl::CtrlStats::readBursts
statistics::Scalar readBursts
Definition: mem_ctrl.hh:572
gem5::divCeil
static constexpr T divCeil(const T &a, const U &b)
Definition: intmath.hh:110
gem5::memory::MemCtrl::burstTicks
std::unordered_multiset< Tick > burstTicks
Holds count of commands issued in burst window starting at defined Tick.
Definition: mem_ctrl.hh:496
gem5::memory::MemCtrl::respQEmpty
virtual bool respQEmpty()
Definition: mem_ctrl.hh:640
gem5::EventFunctionWrapper
Definition: eventq.hh:1115
gem5::Drainable::signalDrainDone
void signalDrainDone() const
Signal that an object is drained.
Definition: drain.hh:305
panic_if
#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
gem5::memory::MemCtrl::CtrlStats::readReqs
statistics::Scalar readReqs
Definition: mem_ctrl.hh:570
gem5::memory::MemCtrl::minReadToWriteDataGap
virtual Tick minReadToWriteDataGap()
Calculate the minimum delay used when scheduling a read-to-write transision.
Definition: mem_ctrl.cc:1139
gem5::ceilLog2
static constexpr int ceilLog2(const T &n)
Definition: intmath.hh:84
gem5::memory::MemCtrl::accessAndRespond
virtual void accessAndRespond(PacketPtr pkt, Tick static_latency, MemInterface *mem_intr)
When a packet reaches its "readyTime" in the response Q, use the "access()" method in AbstractMemory ...
Definition: mem_ctrl.cc:613
gem5::memory::MemCtrl::MemoryPort::getAddrRanges
AddrRangeList getAddrRanges() const override
Get a list of the non-overlapping address ranges the owner is responsible for.
Definition: mem_ctrl.cc:1454
gem5::memory::MemCtrl::verifyMultiCmd
virtual Tick verifyMultiCmd(Tick cmd_tick, Tick max_cmds_per_burst, Tick max_multi_cmd_split=0)
Check for command bus contention for multi-cycle (2 currently) command.
Definition: mem_ctrl.cc:697
gem5::memory::MemCtrl::getPort
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: mem_ctrl.cc:1377
gem5::memory::MemCtrl::memBusy
virtual bool memBusy(MemInterface *mem_intr)
Checks if the memory interface is already busy.
Definition: mem_ctrl.cc:829
gem5::memory::MemCtrl::MemoryPort::recvAtomic
Tick recvAtomic(PacketPtr pkt) override
Receive an atomic request packet from the peer.
Definition: mem_ctrl.cc:1475
gem5::Port
Ports are used to interface objects to each other.
Definition: port.hh:61
gem5::memory::MemPacket::rank
const uint8_t rank
Will be populated by address decoder.
Definition: mem_ctrl.hh:123
gem5::memory::MemCtrl::recvAtomicLogic
Tick recvAtomicLogic(PacketPtr pkt, MemInterface *mem_intr)
Definition: mem_ctrl.cc:134
gem5::SimObject::startup
virtual void startup()
startup() is the final initialization call before simulation.
Definition: sim_object.cc:99
dram_interface.hh
gem5::PowerISA::vec
Bitfield< 25 > vec
Definition: misc.hh:108
std::deque
STL deque class.
Definition: stl.hh:44
gem5::memory::MemInterface::nextReqTime
Tick nextReqTime
Definition: mem_interface.hh:190
gem5::memory::MemCtrl::writeQueueFull
bool writeQueueFull(unsigned int pkt_count) const
Check if the write queue has room for more entries.
Definition: mem_ctrl.cc:176
gem5::memory::MemInterface::chooseNextFRFCFS
virtual std::pair< MemPacketQueue::iterator, Tick > chooseNextFRFCFS(MemPacketQueue &queue, Tick min_col_at) const =0
For FR-FCFS policy, find first command that can issue Function will be overriden by interface to sele...
gem5::memory::qos::MemCtrl::numPriorities
uint8_t numPriorities() const
Gets the total number of priority levels in the QoS memory controller.
Definition: mem_ctrl.hh:367
gem5::simSeconds
statistics::Formula & simSeconds
Definition: stats.cc:45
gem5::memory::MemCtrl::CtrlStats::writeBursts
statistics::Scalar writeBursts
Definition: mem_ctrl.hh:573
gem5::memory::MemCtrl::CtrlStats::rdPerTurnAround
statistics::Histogram rdPerTurnAround
Definition: mem_ctrl.hh:587
gem5::memory::BurstHelper
A burst helper helps organize and manage a packet that is larger than the memory burst size.
Definition: mem_ctrl.hh:79
gem5::statistics::Group
Statistics container.
Definition: group.hh:93
gem5::memory::MemCtrl::processNextReqEvent
virtual void processNextReqEvent(MemInterface *mem_intr, MemPacketQueue &resp_queue, EventFunctionWrapper &resp_event, EventFunctionWrapper &next_req_event, bool &retry_wr_req)
Bunch of things requires to setup "events" in gem5 When event "respondEvent" occurs for example,...
Definition: mem_ctrl.cc:872
gem5::memory::qos::MemCtrl::recordTurnaroundStats
void recordTurnaroundStats()
Record statistics on turnarounds based on busStateNext and busState values.
Definition: mem_ctrl.cc:359
gem5::memory::qos::MemCtrl::WRITE
@ WRITE
Definition: mem_ctrl.hh:84
gem5::memory::MemCtrl::getBurstWindow
Tick getBurstWindow(Tick cmd_tick)
Calculate burst window aligned tick.
Definition: mem_ctrl.cc:666
gem5::memory::MemCtrl::addToWriteQueue
void addToWriteQueue(PacketPtr pkt, unsigned int pkt_count, MemInterface *mem_intr)
Decode the incoming pkt, create a mem_pkt and push to the back of the write queue.
Definition: mem_ctrl.cc:300
gem5::memory::MemInterface::pseudoChannel
uint8_t pseudoChannel
pseudo channel number used for HBM modeling
Definition: mem_interface.hh:195
trace.hh
gem5::memory::MemCtrl::minWritesPerSwitch
const uint32_t minWritesPerSwitch
Definition: mem_ctrl.hh:515
gem5::memory::MemInterface::bytesPerBurst
uint32_t bytesPerBurst() const
Definition: mem_interface.hh:256
gem5::memory::MemCtrl::drainResume
virtual void drainResume() override
Resume execution after a successful drain.
Definition: mem_ctrl.cc:1422
std::list< AddrRange >
gem5::Packet::getAddr
Addr getAddr() const
Definition: packet.hh:790
gem5::memory::MemCtrl::commandWindow
const Tick commandWindow
Length of a command window, used to check command bandwidth.
Definition: mem_ctrl.hh:544
gem5::memory::MemCtrl::CtrlStats::mergedWrBursts
statistics::Scalar mergedWrBursts
Definition: mem_ctrl.hh:575
gem5::QueuedResponsePort::schedTimingResp
void schedTimingResp(PacketPtr pkt, Tick when)
Schedule the sending of a timing response.
Definition: qport.hh:93
gem5::memory::MemCtrl::printQs
void printQs() const
Used for debugging to observe the contents of the queues.
Definition: mem_ctrl.cc:376
gem5::memory::AbstractMemory::access
void access(PacketPtr pkt)
Perform an untimed memory access and update all the state (e.g.
Definition: abstract_mem.cc:379
gem5::memory::BurstHelper::burstCount
const unsigned int burstCount
Number of bursts requred for a system packet.
Definition: mem_ctrl.hh:84
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: gpu_translation_state.hh:37
gem5::memory::MemInterface::writeRespQueueFull
virtual bool writeRespQueueFull() const
This function is NVM specific.
Definition: mem_interface.hh:387
gem5::memory::MemPacket::isRead
bool isRead() const
Return true if its a read packet (interface compatibility with Packet)
Definition: mem_ctrl.hh:193
gem5::memory::MemCtrl::chooseNext
virtual MemPacketQueue::iterator chooseNext(MemPacketQueue &queue, Tick extra_col_delay, MemInterface *mem_intr)
The memory schduler/arbiter - picks which request needs to go next, based on the specified policy suc...
Definition: mem_ctrl.cc:551
gem5::memory::MemInterface::accessLatency
virtual Tick accessLatency() const =0
gem5::memory::MemCtrl::CtrlStats::avgRdQLen
statistics::Average avgRdQLen
Definition: mem_ctrl.hh:578
gem5::memory::qos::MemCtrl::logRequest
void logRequest(BusState dir, RequestorID id, uint8_t _qos, Addr addr, uint64_t entries)
Called upon receiving a request or updates statistics and updates queues status.
Definition: mem_ctrl.cc:92
gem5::memory::MemCtrl::CtrlStats::wrPerTurnAround
statistics::Histogram wrPerTurnAround
Definition: mem_ctrl.hh:588
gem5::memory::MemCtrl::writesThisTime
uint32_t writesThisTime
Definition: mem_ctrl.hh:517
gem5::memory::MemCtrl::nonDetermReads
virtual void nonDetermReads(MemInterface *mem_intr)
Will access memory interface and select non-deterministic reads to issue.
Definition: mem_ctrl.cc:857
gem5::Packet::isResponse
bool isResponse() const
Definition: packet.hh:595
gem5::Packet::getSize
unsigned getSize() const
Definition: packet.hh:800
gem5::memory::MemCtrl::CtrlStats::requestorWriteBytes
statistics::Vector requestorWriteBytes
Definition: mem_ctrl.hh:602
gem5::DrainState::Draining
@ Draining
Draining buffers pending serialization/handover.
gem5::memory::MemInterface::decodePacket
virtual MemPacket * decodePacket(const PacketPtr pkt, Addr pkt_addr, unsigned int size, bool is_read, uint8_t pseudo_channel=0)
Address decoder to figure out physical mapping onto ranks, banks, and rows.
Definition: mem_interface.hh:302
gem5::Event::scheduled
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:465
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
gem5::X86ISA::addr
Bitfield< 3 > addr
Definition: types.hh:84
gem5::memory::MemCtrl::nvmWriteBlock
virtual bool nvmWriteBlock(MemInterface *mem_intr)
Will check if all writes are for nvm interface and nvm's write resp queue is full.
Definition: mem_ctrl.cc:850

Generated on Wed Jul 13 2022 10:39:24 for gem5 by doxygen 1.8.17