gem5  v22.1.0.0
Sequencer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-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) 1999-2008 Mark D. Hill and David A. Wood
15  * Copyright (c) 2013 Advanced Micro Devices, Inc.
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 "arch/x86/ldstflags.hh"
45 #include "base/compiler.hh"
46 #include "base/logging.hh"
47 #include "base/str.hh"
49 #include "debug/LLSC.hh"
50 #include "debug/MemoryAccess.hh"
51 #include "debug/ProtocolTrace.hh"
52 #include "debug/RubyHitMiss.hh"
53 #include "debug/RubySequencer.hh"
54 #include "debug/RubyStats.hh"
55 #include "mem/packet.hh"
57 #include "mem/ruby/protocol/PrefetchBit.hh"
58 #include "mem/ruby/protocol/RubyAccessMode.hh"
62 #include "sim/system.hh"
63 
64 namespace gem5
65 {
66 
67 namespace ruby
68 {
69 
71  : RubyPort(p), m_IncompleteTimes(MachineType_NUM),
72  deadlockCheckEvent([this]{ wakeup(); }, "Sequencer deadlock check")
73 {
74  m_outstanding_count = 0;
75 
76  m_dataCache_ptr = p.dcache;
77  m_max_outstanding_requests = p.max_outstanding_requests;
78  m_deadlock_threshold = p.deadlock_threshold;
79 
80  m_coreId = p.coreid; // for tracking the two CorePair sequencers
81  assert(m_max_outstanding_requests > 0);
82  assert(m_deadlock_threshold > 0);
83 
84  m_unaddressedTransactionCnt = 0;
85 
86  m_runningGarnetStandalone = p.garnet_standalone;
87 
88 
89  // These statistical variables are not for display.
90  // The profiler will collate these across different
91  // sequencers and display those collated statistics.
92  m_outstandReqHist.init(10);
93  m_latencyHist.init(10);
94  m_hitLatencyHist.init(10);
95  m_missLatencyHist.init(10);
96 
97  for (int i = 0; i < RubyRequestType_NUM; i++) {
98  m_typeLatencyHist.push_back(new statistics::Histogram());
99  m_typeLatencyHist[i]->init(10);
100 
101  m_hitTypeLatencyHist.push_back(new statistics::Histogram());
102  m_hitTypeLatencyHist[i]->init(10);
103 
104  m_missTypeLatencyHist.push_back(new statistics::Histogram());
105  m_missTypeLatencyHist[i]->init(10);
106  }
107 
108  for (int i = 0; i < MachineType_NUM; i++) {
109  m_hitMachLatencyHist.push_back(new statistics::Histogram());
110  m_hitMachLatencyHist[i]->init(10);
111 
112  m_missMachLatencyHist.push_back(new statistics::Histogram());
113  m_missMachLatencyHist[i]->init(10);
114 
115  m_IssueToInitialDelayHist.push_back(new statistics::Histogram());
116  m_IssueToInitialDelayHist[i]->init(10);
117 
118  m_InitialToForwardDelayHist.push_back(new statistics::Histogram());
119  m_InitialToForwardDelayHist[i]->init(10);
120 
121  m_ForwardToFirstResponseDelayHist.push_back(
122  new statistics::Histogram());
123  m_ForwardToFirstResponseDelayHist[i]->init(10);
124 
125  m_FirstResponseToCompletionDelayHist.push_back(
126  new statistics::Histogram());
127  m_FirstResponseToCompletionDelayHist[i]->init(10);
128  }
129 
130  for (int i = 0; i < RubyRequestType_NUM; i++) {
131  m_hitTypeMachLatencyHist.push_back(
133  m_missTypeMachLatencyHist.push_back(
135 
136  for (int j = 0; j < MachineType_NUM; j++) {
137  m_hitTypeMachLatencyHist[i].push_back(new statistics::Histogram());
138  m_hitTypeMachLatencyHist[i][j]->init(10);
139 
140  m_missTypeMachLatencyHist[i].push_back(
141  new statistics::Histogram());
142  m_missTypeMachLatencyHist[i][j]->init(10);
143  }
144  }
145 
146 }
147 
149 {
150 }
151 
152 void
154 {
155  fatal_if(m_dataCache_ptr == NULL,
156  "%s must have a dcache object to support LLSC requests.", name());
157  AbstractCacheEntry *line = m_dataCache_ptr->lookup(claddr);
158  if (line) {
159  line->setLocked(m_version);
160  DPRINTF(LLSC, "LLSC Monitor - inserting load linked - "
161  "addr=0x%lx - cpu=%u\n", claddr, m_version);
162  }
163 }
164 
165 void
167 {
168  // clear monitor is called for all stores and evictions
169  if (m_dataCache_ptr == NULL)
170  return;
171  AbstractCacheEntry *line = m_dataCache_ptr->lookup(claddr);
172  if (line && line->isLocked(m_version)) {
173  line->clearLocked();
174  DPRINTF(LLSC, "LLSC Monitor - clearing due to store - "
175  "addr=0x%lx - cpu=%u\n", claddr, m_version);
176  }
177 }
178 
179 bool
181 {
182  fatal_if(m_dataCache_ptr == NULL,
183  "%s must have a dcache object to support LLSC requests.", name());
184  AbstractCacheEntry *line = m_dataCache_ptr->lookup(claddr);
185  if (!line)
186  return false;
187 
188  DPRINTF(LLSC, "LLSC Monitor - clearing due to "
189  "store conditional - "
190  "addr=0x%lx - cpu=%u\n",
191  claddr, m_version);
192 
193  if (line->isLocked(m_version)) {
194  line->clearLocked();
195  return true;
196  } else {
197  line->clearLocked();
198  return false;
199  }
200 }
201 
202 bool
204 {
205  assert(m_dataCache_ptr != NULL);
206  const Addr claddr = makeLineAddress(address);
207  AbstractCacheEntry *line = m_dataCache_ptr->lookup(claddr);
208  if (!line)
209  return false;
210 
211  if (line->isLocked(m_version)) {
212  return true;
213  } else {
214  return false;
215  }
216 }
217 
218 void
220 {
222 }
223 
224 void
226 {
227  assert(drainState() != DrainState::Draining);
228 
229  // Check for deadlock of any of the requests
230  Cycles current_time = curCycle();
231 
232  // Check across all outstanding requests
233  GEM5_VAR_USED int total_outstanding = 0;
234 
235  for (const auto &table_entry : m_RequestTable) {
236  for (const auto &seq_req : table_entry.second) {
237  if (current_time - seq_req.issue_time < m_deadlock_threshold)
238  continue;
239 
240  panic("Possible Deadlock detected. Aborting!\n version: %d "
241  "request.paddr: 0x%x m_readRequestTable: %d current time: "
242  "%u issue_time: %d difference: %d\n", m_version,
243  seq_req.pkt->getAddr(), table_entry.second.size(),
244  current_time * clockPeriod(), seq_req.issue_time
245  * clockPeriod(), (current_time * clockPeriod())
246  - (seq_req.issue_time * clockPeriod()));
247  }
248  total_outstanding += table_entry.second.size();
249  }
250 
251  assert(m_outstanding_count == total_outstanding);
252 
253  if (m_outstanding_count > 0) {
254  // If there are still outstanding requests, keep checking
256  }
257 }
258 
259 int
261 {
262  int num_written = RubyPort::functionalWrite(func_pkt);
263 
264  for (const auto &table_entry : m_RequestTable) {
265  for (const auto& seq_req : table_entry.second) {
266  if (seq_req.functionalWrite(func_pkt))
267  ++num_written;
268  }
269  }
270 
271  return num_written;
272 }
273 
275 {
280  for (int i = 0; i < RubyRequestType_NUM; i++) {
281  m_typeLatencyHist[i]->reset();
282  m_hitTypeLatencyHist[i]->reset();
283  m_missTypeLatencyHist[i]->reset();
284  for (int j = 0; j < MachineType_NUM; j++) {
285  m_hitTypeMachLatencyHist[i][j]->reset();
286  m_missTypeMachLatencyHist[i][j]->reset();
287  }
288  }
289 
290  for (int i = 0; i < MachineType_NUM; i++) {
291  m_missMachLatencyHist[i]->reset();
292  m_hitMachLatencyHist[i]->reset();
293 
294  m_IssueToInitialDelayHist[i]->reset();
295  m_InitialToForwardDelayHist[i]->reset();
298 
299  m_IncompleteTimes[i] = 0;
300  }
301 }
302 
303 // Insert the request in the request table. Return RequestStatus_Aliased
304 // if the entry was already present.
305 RequestStatus
306 Sequencer::insertRequest(PacketPtr pkt, RubyRequestType primary_type,
307  RubyRequestType secondary_type)
308 {
309  // See if we should schedule a deadlock check
310  if (!deadlockCheckEvent.scheduled() &&
313  }
314 
315  if (isTlbiCmdRequest(primary_type)) {
316  assert(primary_type == secondary_type);
317 
318  switch (primary_type) {
319  case RubyRequestType_TLBI_EXT_SYNC_COMP:
320  // Don't have to store any data on this
321  break;
322  case RubyRequestType_TLBI:
323  case RubyRequestType_TLBI_SYNC:
324  {
326 
327  // returns pair<inserted element, was inserted>
328  [[maybe_unused]] auto insert_data = \
329  m_UnaddressedRequestTable.emplace(
332  pkt, primary_type, secondary_type, curCycle()));
333 
334  // if insert_data.second is false, wasn't inserted
335  assert(insert_data.second &&
336  "Another TLBI request with the same ID exists");
337 
338  DPRINTF(RubySequencer, "Inserting TLBI request %016x\n",
340 
341  break;
342  }
343 
344  default:
345  panic("Unexpected TLBI RubyRequestType");
346  }
347 
348  return RequestStatus_Ready;
349  }
350 
351  Addr line_addr = makeLineAddress(pkt->getAddr());
352  // Check if there is any outstanding request for the same cache line.
353  auto &seq_req_list = m_RequestTable[line_addr];
354  // Create a default entry
355  seq_req_list.emplace_back(pkt, primary_type,
356  secondary_type, curCycle());
358 
359  if (seq_req_list.size() > 1) {
360  return RequestStatus_Aliased;
361  }
362 
364 
365  return RequestStatus_Ready;
366 }
367 
368 void
370 {
372 }
373 
374 void
375 Sequencer::recordMissLatency(SequencerRequest* srequest, bool llscSuccess,
376  const MachineType respondingMach,
377  bool isExternalHit, Cycles initialRequestTime,
378  Cycles forwardRequestTime,
379  Cycles firstResponseTime)
380 {
381  RubyRequestType type = srequest->m_type;
382  Cycles issued_time = srequest->issue_time;
383  Cycles completion_time = curCycle();
384 
385  assert(curCycle() >= issued_time);
386  Cycles total_lat = completion_time - issued_time;
387 
388  if ((initialRequestTime != 0) && (initialRequestTime < issued_time)) {
389  // if the request was combined in the protocol with an earlier request
390  // for the same address, it is possible that it will return an
391  // initialRequestTime corresponding the earlier request. Since Cycles
392  // is unsigned, we can't let this request get profiled below.
393 
394  total_lat = Cycles(0);
395  }
396 
397  DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %d cycles\n",
398  curTick(), m_version, "Seq", llscSuccess ? "Done" : "SC_Failed",
399  "", "", printAddress(srequest->pkt->getAddr()), total_lat);
400 
401  m_latencyHist.sample(total_lat);
402  m_typeLatencyHist[type]->sample(total_lat);
403 
404  if (isExternalHit) {
405  m_missLatencyHist.sample(total_lat);
406  m_missTypeLatencyHist[type]->sample(total_lat);
407 
408  if (respondingMach != MachineType_NUM) {
409  m_missMachLatencyHist[respondingMach]->sample(total_lat);
410  m_missTypeMachLatencyHist[type][respondingMach]->sample(total_lat);
411 
412  if ((issued_time <= initialRequestTime) &&
413  (initialRequestTime <= forwardRequestTime) &&
414  (forwardRequestTime <= firstResponseTime) &&
415  (firstResponseTime <= completion_time)) {
416 
417  m_IssueToInitialDelayHist[respondingMach]->sample(
418  initialRequestTime - issued_time);
419  m_InitialToForwardDelayHist[respondingMach]->sample(
420  forwardRequestTime - initialRequestTime);
421  m_ForwardToFirstResponseDelayHist[respondingMach]->sample(
422  firstResponseTime - forwardRequestTime);
423  m_FirstResponseToCompletionDelayHist[respondingMach]->sample(
424  completion_time - firstResponseTime);
425  } else {
426  m_IncompleteTimes[respondingMach]++;
427  }
428  }
429  } else {
430  m_hitLatencyHist.sample(total_lat);
431  m_hitTypeLatencyHist[type]->sample(total_lat);
432 
433  if (respondingMach != MachineType_NUM) {
434  m_hitMachLatencyHist[respondingMach]->sample(total_lat);
435  m_hitTypeMachLatencyHist[type][respondingMach]->sample(total_lat);
436  }
437  }
438 }
439 
440 void
442 {
443  llscClearMonitor(address);
444  writeCallback(address, data);
445 }
446 
447 void
449  const bool externalHit, const MachineType mach,
450  const Cycles initialRequestTime,
451  const Cycles forwardRequestTime,
452  const Cycles firstResponseTime,
453  const bool noCoales)
454 {
455  //
456  // Free the whole list as we assume we have had the exclusive access
457  // to this cache line when response for the write comes back
458  //
459  assert(address == makeLineAddress(address));
460  assert(m_RequestTable.find(address) != m_RequestTable.end());
461  auto &seq_req_list = m_RequestTable[address];
462 
463  // Perform hitCallback on every cpu request made to this cache block while
464  // ruby request was outstanding. Since only 1 ruby request was made,
465  // profile the ruby latency once.
466  bool ruby_request = true;
467  int aliased_stores = 0;
468  int aliased_loads = 0;
469  while (!seq_req_list.empty()) {
470  SequencerRequest &seq_req = seq_req_list.front();
471 
472  if (noCoales && !ruby_request) {
473  // Do not process follow-up requests
474  // (e.g. if full line no present)
475  // Reissue to the cache hierarchy
476  issueRequest(seq_req.pkt, seq_req.m_second_type);
477  break;
478  }
479 
480  if (ruby_request) {
481  assert(seq_req.m_type != RubyRequestType_LD);
482  assert(seq_req.m_type != RubyRequestType_Load_Linked);
483  assert(seq_req.m_type != RubyRequestType_IFETCH);
484  }
485 
486  // handle write request
487  if ((seq_req.m_type != RubyRequestType_LD) &&
488  (seq_req.m_type != RubyRequestType_Load_Linked) &&
489  (seq_req.m_type != RubyRequestType_IFETCH)) {
490  // LL/SC support (tested with ARMv8)
491  bool success = true;
492 
493  if (seq_req.m_type != RubyRequestType_Store_Conditional) {
494  // Regular stores to addresses being monitored
495  // will fail (remove) the monitor entry.
496  llscClearMonitor(address);
497  } else {
498  // Store conditionals must first check the monitor
499  // if they will succeed or not
500  success = llscStoreConditional(address);
501  seq_req.pkt->req->setExtraData(success ? 1 : 0);
502  }
503 
504  // Handle SLICC block_on behavior for Locked_RMW accesses. NOTE: the
505  // address variable here is assumed to be a line address, so when
506  // blocking buffers, must check line addresses.
507  if (seq_req.m_type == RubyRequestType_Locked_RMW_Read) {
508  // blockOnQueue blocks all first-level cache controller queues
509  // waiting on memory accesses for the specified address that go
510  // to the specified queue. In this case, a Locked_RMW_Write must
511  // go to the mandatory_q before unblocking the first-level
512  // controller. This will block standard loads, stores, ifetches,
513  // etc.
515  } else if (seq_req.m_type == RubyRequestType_Locked_RMW_Write) {
516  m_controller->unblock(address);
517  }
518 
519  if (ruby_request) {
520  recordMissLatency(&seq_req, success, mach, externalHit,
521  initialRequestTime, forwardRequestTime,
522  firstResponseTime);
523  } else {
524  aliased_stores++;
525  }
526  markRemoved();
527  hitCallback(&seq_req, data, success, mach, externalHit,
528  initialRequestTime, forwardRequestTime,
529  firstResponseTime, !ruby_request);
530  ruby_request = false;
531  } else {
532  // handle read request
533  assert(!ruby_request);
534  markRemoved();
535  aliased_loads++;
536  hitCallback(&seq_req, data, true, mach, externalHit,
537  initialRequestTime, forwardRequestTime,
538  firstResponseTime, !ruby_request);
539  }
540  seq_req_list.pop_front();
541  }
542 
543  // free all outstanding requests corresponding to this address
544  if (seq_req_list.empty()) {
545  m_RequestTable.erase(address);
546  }
547 }
548 
549 void
551  bool externalHit, const MachineType mach,
552  Cycles initialRequestTime,
553  Cycles forwardRequestTime,
554  Cycles firstResponseTime)
555 {
556  //
557  // Free up read requests until we hit the first Write request
558  // or end of the corresponding list.
559  //
560  assert(address == makeLineAddress(address));
561  assert(m_RequestTable.find(address) != m_RequestTable.end());
562  auto &seq_req_list = m_RequestTable[address];
563 
564  // Perform hitCallback on every cpu request made to this cache block while
565  // ruby request was outstanding. Since only 1 ruby request was made,
566  // profile the ruby latency once.
567  bool ruby_request = true;
568  int aliased_loads = 0;
569  while (!seq_req_list.empty()) {
570  SequencerRequest &seq_req = seq_req_list.front();
571  if (ruby_request) {
572  assert((seq_req.m_type == RubyRequestType_LD) ||
573  (seq_req.m_type == RubyRequestType_Load_Linked) ||
574  (seq_req.m_type == RubyRequestType_IFETCH));
575  } else {
576  aliased_loads++;
577  }
578  if ((seq_req.m_type != RubyRequestType_LD) &&
579  (seq_req.m_type != RubyRequestType_Load_Linked) &&
580  (seq_req.m_type != RubyRequestType_IFETCH)) {
581  // Write request: reissue request to the cache hierarchy
582  issueRequest(seq_req.pkt, seq_req.m_second_type);
583  break;
584  }
585  if (ruby_request) {
586  recordMissLatency(&seq_req, true, mach, externalHit,
587  initialRequestTime, forwardRequestTime,
588  firstResponseTime);
589  }
590  markRemoved();
591  hitCallback(&seq_req, data, true, mach, externalHit,
592  initialRequestTime, forwardRequestTime,
593  firstResponseTime, !ruby_request);
594  ruby_request = false;
595  seq_req_list.pop_front();
596  }
597 
598  // free all outstanding requests corresponding to this address
599  if (seq_req_list.empty()) {
600  m_RequestTable.erase(address);
601  }
602 }
603 
604 void
606  bool llscSuccess,
607  const MachineType mach, const bool externalHit,
608  const Cycles initialRequestTime,
609  const Cycles forwardRequestTime,
610  const Cycles firstResponseTime,
611  const bool was_coalesced)
612 {
613  warn_once("Replacement policy updates recently became the responsibility "
614  "of SLICC state machines. Make sure to setMRU() near callbacks "
615  "in .sm files!");
616 
617  PacketPtr pkt = srequest->pkt;
618  Addr request_address(pkt->getAddr());
619  RubyRequestType type = srequest->m_type;
620 
621  if (was_coalesced) {
622  // Notify the controller about a coalesced request so it can properly
623  // account for it in its hit/miss stats and/or train prefetchers
624  // (this is protocol-dependent)
625  m_controller->notifyCoalesced(request_address, type, pkt->req,
626  data, externalHit);
627  }
628 
629  // Load-linked handling
630  if (type == RubyRequestType_Load_Linked) {
631  Addr line_addr = makeLineAddress(request_address);
632  llscLoadLinked(line_addr);
633  }
634 
635  DPRINTF(RubyHitMiss, "Cache %s at %#x\n",
636  externalHit ? "miss" : "hit",
637  printAddress(request_address));
638 
639  // update the data unless it is a non-data-carrying flush
641  data.setData(pkt);
642  } else if (!pkt->isFlush()) {
643  if ((type == RubyRequestType_LD) ||
644  (type == RubyRequestType_IFETCH) ||
645  (type == RubyRequestType_RMW_Read) ||
646  (type == RubyRequestType_Locked_RMW_Read) ||
647  (type == RubyRequestType_Load_Linked)) {
648  pkt->setData(
649  data.getData(getOffset(request_address), pkt->getSize()));
650  DPRINTF(RubySequencer, "read data %s\n", data);
651  } else if (pkt->req->isSwap()) {
652  assert(!pkt->isMaskedWrite());
653  std::vector<uint8_t> overwrite_val(pkt->getSize());
654  pkt->writeData(&overwrite_val[0]);
655  pkt->setData(
656  data.getData(getOffset(request_address), pkt->getSize()));
657  data.setData(&overwrite_val[0],
658  getOffset(request_address), pkt->getSize());
659  DPRINTF(RubySequencer, "swap data %s\n", data);
660  } else if (pkt->isAtomicOp()) {
661  // Set the data in the packet to the old value in the cache
662  pkt->setData(
663  data.getData(getOffset(request_address), pkt->getSize()));
664  DPRINTF(RubySequencer, "AMO original data %s\n", data);
665  // execute AMO operation
666  (*(pkt->getAtomicOp()))(
667  data.getDataMod(getOffset(request_address)));
668  DPRINTF(RubySequencer, "AMO new data %s\n", data);
669  } else if (type != RubyRequestType_Store_Conditional || llscSuccess) {
670  // Types of stores set the actual data here, apart from
671  // failed Store Conditional requests
672  data.setData(pkt);
673  DPRINTF(RubySequencer, "set data %s\n", data);
674  }
675  }
676 
677  // If using the RubyTester, update the RubyTester sender state's
678  // subBlock with the recieved data. The tester will later access
679  // this state.
680  if (m_usingRubyTester) {
681  DPRINTF(RubySequencer, "hitCallback %s 0x%x using RubyTester\n",
682  pkt->cmdString(), pkt->getAddr());
683  RubyTester::SenderState* testerSenderState =
685  assert(testerSenderState);
686  testerSenderState->subBlock.mergeFrom(data);
687  }
688 
691  assert(pkt->req);
692  delete pkt;
693  rs->m_cache_recorder->enqueueNextFetchRequest();
694  } else if (RubySystem::getCooldownEnabled()) {
695  delete pkt;
696  rs->m_cache_recorder->enqueueNextFlushRequest();
697  } else {
698  ruby_hit_callback(pkt);
700  }
701 }
702 
703 void
705  RubyRequestType reqType,
706  const MachineType mach,
707  const Cycles initialRequestTime,
708  const Cycles forwardRequestTime,
709  const Cycles firstResponseTime)
710 {
711  DPRINTF(RubySequencer, "unaddressedCallback ID:%08x type:%d\n",
712  unaddressedReqId, reqType);
713 
714  switch (reqType) {
715  case RubyRequestType_TLBI_EXT_SYNC:
716  {
717  // This should trigger the CPU to wait for stale translations
718  // and send an EXT_SYNC_COMP once complete.
719 
720  // Don't look for the ID in our requestTable.
721  // It won't be there because we didn't request this Sync
722  ruby_stale_translation_callback(unaddressedReqId);
723  break;
724  }
725  case RubyRequestType_TLBI:
726  case RubyRequestType_TLBI_SYNC:
727  {
728  // These signal that a TLBI operation that this core initiated
729  // of the respective type (TLBI or Sync) has finished.
730 
731  assert(m_UnaddressedRequestTable.find(unaddressedReqId)
732  != m_UnaddressedRequestTable.end());
733 
734  {
735  SequencerRequest &seq_req =
736  m_UnaddressedRequestTable.at(unaddressedReqId);
737  assert(seq_req.m_type == reqType);
738 
739  PacketPtr pkt = seq_req.pkt;
740 
743  }
744 
745  m_UnaddressedRequestTable.erase(unaddressedReqId);
746  break;
747  }
748  default:
749  panic("Unexpected TLBI RubyRequestType");
750  }
751 }
752 
753 bool
755 {
756  return m_RequestTable.empty() &&
758 }
759 
760 RequestStatus
762 {
763  // HTM abort signals must be allowed to reach the Sequencer
764  // the same cycle they are issued. They cannot be retried.
766  !pkt->req->isHTMAbort()) {
767  return RequestStatus_BufferFull;
768  }
769 
770  RubyRequestType primary_type = RubyRequestType_NULL;
771  RubyRequestType secondary_type = RubyRequestType_NULL;
772 
773  if (pkt->isLLSC()) {
774  // LL/SC instructions need to be handled carefully by the cache
775  // coherence protocol to ensure they follow the proper semantics. In
776  // particular, by identifying the operations as atomic, the protocol
777  // should understand that migratory sharing optimizations should not
778  // be performed (i.e. a load between the LL and SC should not steal
779  // away exclusive permission).
780  //
781  // The following logic works correctly with the semantics
782  // of armV8 LDEX/STEX instructions.
783 
784  if (pkt->isWrite()) {
785  DPRINTF(RubySequencer, "Issuing SC\n");
786  primary_type = RubyRequestType_Store_Conditional;
787 #if defined (PROTOCOL_MESI_Three_Level) || defined (PROTOCOL_MESI_Three_Level_HTM)
788  secondary_type = RubyRequestType_Store_Conditional;
789 #else
790  secondary_type = RubyRequestType_ST;
791 #endif
792  } else {
793  DPRINTF(RubySequencer, "Issuing LL\n");
794  assert(pkt->isRead());
795  primary_type = RubyRequestType_Load_Linked;
796  secondary_type = RubyRequestType_LD;
797  }
798  } else if (pkt->req->isLockedRMW()) {
799  //
800  // x86 locked instructions are translated to store cache coherence
801  // requests because these requests should always be treated as read
802  // exclusive operations and should leverage any migratory sharing
803  // optimization built into the protocol.
804  //
805  if (pkt->isWrite()) {
806  DPRINTF(RubySequencer, "Issuing Locked RMW Write\n");
807  primary_type = RubyRequestType_Locked_RMW_Write;
808  } else {
809  DPRINTF(RubySequencer, "Issuing Locked RMW Read\n");
810  assert(pkt->isRead());
811  primary_type = RubyRequestType_Locked_RMW_Read;
812  }
813  secondary_type = RubyRequestType_ST;
814  } else if (pkt->req->isTlbiCmd()) {
815  primary_type = secondary_type = tlbiCmdToRubyRequestType(pkt);
816  DPRINTF(RubySequencer, "Issuing TLBI\n");
817  } else {
818  //
819  // To support SwapReq, we need to check isWrite() first: a SwapReq
820  // should always be treated like a write, but since a SwapReq implies
821  // both isWrite() and isRead() are true, check isWrite() first here.
822  //
823  if (pkt->isWrite()) {
824  //
825  // Note: M5 packets do not differentiate ST from RMW_Write
826  //
827  primary_type = secondary_type = RubyRequestType_ST;
828  } else if (pkt->isRead()) {
829  // hardware transactional memory commands
830  if (pkt->req->isHTMCmd()) {
831  primary_type = secondary_type = htmCmdToRubyRequestType(pkt);
832  } else if (pkt->req->isInstFetch()) {
833  primary_type = secondary_type = RubyRequestType_IFETCH;
834  } else {
835  if (pkt->req->isReadModifyWrite()) {
836  primary_type = RubyRequestType_RMW_Read;
837  secondary_type = RubyRequestType_ST;
838  } else {
839  primary_type = secondary_type = RubyRequestType_LD;
840  }
841  }
842  } else if (pkt->isFlush()) {
843  primary_type = secondary_type = RubyRequestType_FLUSH;
844  } else {
845  panic("Unsupported ruby packet type\n");
846  }
847  }
848 
849  // Check if the line is blocked for a Locked_RMW
850  if (!pkt->req->isMemMgmt() &&
852  (primary_type != RubyRequestType_Locked_RMW_Write)) {
853  // Return that this request's cache line address aliases with
854  // a prior request that locked the cache line. The request cannot
855  // proceed until the cache line is unlocked by a Locked_RMW_Write
856  return RequestStatus_Aliased;
857  }
858 
859  RequestStatus status = insertRequest(pkt, primary_type, secondary_type);
860 
861  // It is OK to receive RequestStatus_Aliased, it can be considered Issued
862  if (status != RequestStatus_Ready && status != RequestStatus_Aliased)
863  return status;
864  // non-aliased with any existing request in the request table, just issue
865  // to the cache
866  if (status != RequestStatus_Aliased)
867  issueRequest(pkt, secondary_type);
868 
869  // TODO: issue hardware prefetches here
870  return RequestStatus_Issued;
871 }
872 
873 void
874 Sequencer::issueRequest(PacketPtr pkt, RubyRequestType secondary_type)
875 {
876  assert(pkt != NULL);
877  ContextID proc_id = pkt->req->hasContextId() ?
878  pkt->req->contextId() : InvalidContextID;
879 
880  ContextID core_id = coreId();
881 
882  // If valid, copy the pc to the ruby request
883  Addr pc = 0;
884  if (pkt->req->hasPC()) {
885  pc = pkt->req->getPC();
886  }
887 
888  // check if the packet has data as for example prefetch and flush
889  // requests do not
890  std::shared_ptr<RubyRequest> msg;
891  if (pkt->req->isMemMgmt()) {
892  msg = std::make_shared<RubyRequest>(clockEdge(),
893  pc, secondary_type,
894  RubyAccessMode_Supervisor, pkt,
895  proc_id, core_id);
896 
897  DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s\n",
898  curTick(), m_version, "Seq", "Begin", "", "",
899  RubyRequestType_to_string(secondary_type));
900 
901  if (pkt->req->isTlbiCmd()) {
902  msg->m_isTlbi = true;
903  switch (secondary_type) {
904  case RubyRequestType_TLBI_EXT_SYNC_COMP:
905  msg->m_tlbiTransactionUid = pkt->req->getExtraData();
906  break;
907  case RubyRequestType_TLBI:
908  case RubyRequestType_TLBI_SYNC:
909  msg->m_tlbiTransactionUid = \
910  getCurrentUnaddressedTransactionID();
911  break;
912  default:
913  panic("Unexpected TLBI RubyRequestType");
914  }
915  DPRINTF(RubySequencer, "Issuing TLBI %016x\n",
916  msg->m_tlbiTransactionUid);
917  }
918  } else {
919  msg = std::make_shared<RubyRequest>(clockEdge(), pkt->getAddr(),
920  pkt->getSize(), pc, secondary_type,
921  RubyAccessMode_Supervisor, pkt,
922  PrefetchBit_No, proc_id, core_id);
923 
924  DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\n",
925  curTick(), m_version, "Seq", "Begin", "", "",
926  printAddress(msg->getPhysicalAddress()),
927  RubyRequestType_to_string(secondary_type));
928  }
929 
930  // hardware transactional memory
931  // If the request originates in a transaction,
932  // then mark the Ruby message as such.
933  if (pkt->isHtmTransactional()) {
934  msg->m_htmFromTransaction = true;
935  msg->m_htmTransactionUid = pkt->getHtmTransactionUid();
936  }
937 
938  Tick latency = cyclesToTicks(
939  m_controller->mandatoryQueueLatency(secondary_type));
940  assert(latency > 0);
941 
942  assert(m_mandatory_q_ptr != NULL);
943  m_mandatory_q_ptr->enqueue(msg, clockEdge(), latency);
944 }
945 
946 template <class KEY, class VALUE>
947 std::ostream &
948 operator<<(std::ostream &out, const std::unordered_map<KEY, VALUE> &map)
949 {
950  for (const auto &table_entry : map) {
951  out << "[ " << table_entry.first << " =";
952  for (const auto &seq_req : table_entry.second) {
953  out << " " << RubyRequestType_to_string(seq_req.m_second_type);
954  }
955  }
956  out << " ]";
957 
958  return out;
959 }
960 
961 void
962 Sequencer::print(std::ostream& out) const
963 {
964  out << "[Sequencer: " << m_version
965  << ", outstanding requests: " << m_outstanding_count
966  << ", request table: " << m_RequestTable
967  << "]";
968 }
969 
970 void
971 Sequencer::recordRequestType(SequencerRequestType requestType) {
972  DPRINTF(RubyStats, "Recorded statistic: %s\n",
973  SequencerRequestType_to_string(requestType));
974 }
975 
976 void
978 {
979  llscClearMonitor(address);
980  ruby_eviction_callback(address);
981 }
982 
983 void
985 {
987  // Limit m_unaddressedTransactionCnt to 32 bits,
988  // top 32 bits should always be zeroed out
989  uint64_t aligned_txid = \
990  m_unaddressedTransactionCnt << RubySystem::getBlockSizeBits();
991 
992  if (aligned_txid > 0xFFFFFFFFull) {
994  }
995 }
996 
997 uint64_t
999 {
1000  return (
1001  uint64_t(m_version & 0xFFFFFFFF) << 32) |
1003  );
1004 }
1005 
1006 } // namespace ruby
1007 } // namespace gem5
#define DPRINTFR(x,...)
Definition: trace.hh:200
#define DPRINTF(x,...)
Definition: trace.hh:186
const char data[]
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
Tick cyclesToTicks(Cycles c) const
Tick clockPeriod() const
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
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
AtomicOpFunctor * getAtomicOp() const
Accessor function to atomic op.
Definition: packet.hh:843
bool isAtomicOp() const
Definition: packet.hh:844
T * findNextSenderState() const
Go through the sender state stack and return the first instance that is of type T (as determined by a...
Definition: packet.hh:574
bool isHtmTransactional() const
Returns whether or not this packet/request originates in the CPU executing in transactional mode,...
Definition: packet.cc:523
void setData(const uint8_t *p)
Copy data into the packet from the provided pointer.
Definition: packet.hh:1280
bool isWrite() const
Definition: packet.hh:593
uint64_t getHtmTransactionUid() const
If a packet/request originates in a CPU executing in transactional mode, i.e.
Definition: packet.cc:529
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
bool isLLSC() const
Definition: packet.hh:619
bool isMaskedWrite() const
Definition: packet.hh:1428
bool isFlush() const
Definition: packet.hh:623
void writeData(uint8_t *p) const
Copy data from the packet to the memory at the provided pointer.
Definition: packet.hh:1309
bool isLocked(int context) const
virtual void notifyCoalesced(const Addr &addr, const RubyRequestType &type, const RequestPtr &req, const DataBlock &data_blk, const bool &was_miss)
Notifies controller of a request coalesced at the sequencer.
virtual Cycles mandatoryQueueLatency(const RubyRequestType &param_type)
void blockOnQueue(Addr, MessageBuffer *)
void clearLockedAll(int context)
Definition: CacheMemory.cc:497
AbstractCacheEntry * lookup(Addr address)
Definition: CacheMemory.cc:342
void enqueue(MsgPtr message, Tick curTime, Tick delta)
void ruby_hit_callback(PacketPtr pkt)
Definition: RubyPort.cc:454
void ruby_unaddressed_callback(PacketPtr pkt)
Definition: RubyPort.cc:477
void testDrainComplete()
Definition: RubyPort.cc:551
void ruby_stale_translation_callback(Addr txnId)
Definition: RubyPort.cc:496
RubySystem * m_ruby_system
Definition: RubyPort.hh:197
virtual int functionalWrite(Packet *func_pkt)
Definition: RubyPort.cc:735
RubyPortParams Params
Definition: RubyPort.hh:153
AbstractController * m_controller
Definition: RubyPort.hh:199
void ruby_eviction_callback(Addr address)
Definition: RubyPort.cc:701
MessageBuffer * m_mandatory_q_ptr
Definition: RubyPort.hh:200
static bool getWarmupEnabled()
Definition: RubySystem.hh:75
static uint32_t getBlockSizeBits()
Definition: RubySystem.hh:73
static bool getCooldownEnabled()
Definition: RubySystem.hh:76
statistics::Histogram m_outstandReqHist
Histogram for number of outstanding requests per cycle.
Definition: Sequencer.hh:258
void resetStats() override
Callback to reset stats.
Definition: Sequencer.cc:274
std::unordered_map< Addr, std::list< SequencerRequest > > m_RequestTable
Definition: Sequencer.hh:224
virtual bool empty() const
Definition: Sequencer.cc:754
void writeCallback(Addr address, DataBlock &data, const bool externalHit=false, const MachineType mach=MachineType_NUM, const Cycles initialRequestTime=Cycles(0), const Cycles forwardRequestTime=Cycles(0), const Cycles firstResponseTime=Cycles(0), const bool noCoales=false)
Definition: Sequencer.cc:448
std::vector< statistics::Counter > m_IncompleteTimes
Definition: Sequencer.hh:290
bool llscCheckMonitor(const Addr)
Searches for cache line address in the global monitor tagged with this Sequencer object's version id.
Definition: Sequencer.cc:203
virtual int functionalWrite(Packet *func_pkt) override
Definition: Sequencer.cc:260
std::vector< statistics::Histogram * > m_InitialToForwardDelayHist
Definition: Sequencer.hh:287
std::vector< statistics::Histogram * > m_hitMachLatencyHist
Histograms for profiling the latencies for requests that did not required external messages.
Definition: Sequencer.hh:271
void recordMissLatency(SequencerRequest *srequest, bool llscSuccess, const MachineType respondingMach, bool isExternalHit, Cycles initialRequestTime, Cycles forwardRequestTime, Cycles firstResponseTime)
Definition: Sequencer.cc:375
std::vector< statistics::Histogram * > m_typeLatencyHist
Definition: Sequencer.hh:262
void writeCallbackScFail(Addr address, DataBlock &data)
Proxy function to writeCallback that first invalidates the line address in the local monitor.
Definition: Sequencer.cc:441
CacheMemory * m_dataCache_ptr
Definition: Sequencer.hh:238
std::vector< statistics::Histogram * > m_FirstResponseToCompletionDelayHist
Definition: Sequencer.hh:289
void incrementUnaddressedTransactionCnt()
Increment the unaddressed transaction counter.
Definition: Sequencer.cc:984
void hitCallback(SequencerRequest *srequest, DataBlock &data, bool llscSuccess, const MachineType mach, const bool externalHit, const Cycles initialRequestTime, const Cycles forwardRequestTime, const Cycles firstResponseTime, const bool was_coalesced)
Definition: Sequencer.cc:605
void llscLoadLinked(const Addr)
Places the cache line address into the global monitor tagged with this Sequencer object's version id.
Definition: Sequencer.cc:153
uint64_t getCurrentUnaddressedTransactionID() const
Generate the current unaddressed transaction ID based on the counter and the Sequencer object's versi...
Definition: Sequencer.cc:998
Sequencer(const Params &)
Definition: Sequencer.cc:70
statistics::Histogram m_latencyHist
Histogram for holding latency profile of all requests.
Definition: Sequencer.hh:261
void issueRequest(PacketPtr pkt, RubyRequestType type)
Definition: Sequencer.cc:874
bool llscStoreConditional(const Addr)
Searches for cache line address in the global monitor tagged with this Sequencer object's version id.
Definition: Sequencer.cc:180
void unaddressedCallback(Addr unaddressedReqId, RubyRequestType requestType, const MachineType mach=MachineType_NUM, const Cycles initialRequestTime=Cycles(0), const Cycles forwardRequestTime=Cycles(0), const Cycles firstResponseTime=Cycles(0))
Definition: Sequencer.cc:704
virtual RequestStatus insertRequest(PacketPtr pkt, RubyRequestType primary_type, RubyRequestType secondary_type)
Definition: Sequencer.cc:306
EventFunctionWrapper deadlockCheckEvent
Definition: Sequencer.hh:292
std::unordered_map< uint64_t, SequencerRequest > m_UnaddressedRequestTable
Definition: Sequencer.hh:227
uint64_t m_unaddressedTransactionCnt
Definition: Sequencer.hh:253
std::vector< statistics::Histogram * > m_hitTypeLatencyHist
Definition: Sequencer.hh:267
statistics::Histogram m_hitLatencyHist
Histogram for holding latency profile of all requests that hit in the controller connected to this se...
Definition: Sequencer.hh:266
RequestStatus makeRequest(PacketPtr pkt) override
Definition: Sequencer.cc:761
void llscClearLocalMonitor()
Removes all addresses from the local monitor.
Definition: Sequencer.cc:219
void recordRequestType(SequencerRequestType requestType)
Definition: Sequencer.cc:971
std::vector< statistics::Histogram * > m_IssueToInitialDelayHist
Histograms for recording the breakdown of miss latency.
Definition: Sequencer.hh:286
virtual void print(std::ostream &out) const
Definition: Sequencer.cc:962
std::vector< std::vector< statistics::Histogram * > > m_hitTypeMachLatencyHist
Definition: Sequencer.hh:272
void llscClearMonitor(const Addr)
Removes the cache line address from the global monitor.
Definition: Sequencer.cc:166
virtual void wakeup()
Definition: Sequencer.cc:225
void evictionCallback(Addr address)
Definition: Sequencer.cc:977
std::vector< statistics::Histogram * > m_ForwardToFirstResponseDelayHist
Definition: Sequencer.hh:288
void readCallback(Addr address, DataBlock &data, const bool externalHit=false, const MachineType mach=MachineType_NUM, const Cycles initialRequestTime=Cycles(0), const Cycles forwardRequestTime=Cycles(0), const Cycles firstResponseTime=Cycles(0))
Definition: Sequencer.cc:550
int coreId() const
Definition: Sequencer.hh:150
std::vector< statistics::Histogram * > m_missMachLatencyHist
Histograms for profiling the latencies for requests that required external messages.
Definition: Sequencer.hh:281
std::vector< statistics::Histogram * > m_missTypeLatencyHist
Definition: Sequencer.hh:277
statistics::Histogram m_missLatencyHist
Histogram for holding latency profile of all requests that miss in the controller connected to this s...
Definition: Sequencer.hh:276
std::vector< std::vector< statistics::Histogram * > > m_missTypeMachLatencyHist
Definition: Sequencer.hh:283
void mergeFrom(const DataBlock &data)
Definition: SubBlock.hh:66
void sample(const U &v, int n=1)
Add a value to the distribtion n times.
Definition: statistics.hh:1328
void reset()
Reset stat value to default.
Definition: statistics.hh:1352
A simple histogram stat.
Definition: statistics.hh:2127
STL vector class.
Definition: stl.hh:37
#define GEM5_VAR_USED
Definition: compiler.hh:174
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:324
@ Draining
Draining buffers pending serialization/handover.
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:465
void schedule(Event &event, Tick when)
Definition: eventq.hh:1019
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:226
#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< 5, 0 > status
Definition: misc_types.hh:429
Bitfield< 24 > j
Definition: misc_types.hh:57
Bitfield< 4 > pc
Bitfield< 54 > p
Definition: pagetable.hh:70
RubyRequestType tlbiCmdToRubyRequestType(const Packet *pkt)
bool isTlbiCmdRequest(RubyRequestType type)
Addr makeLineAddress(Addr addr)
Definition: Address.cc:60
Addr getOffset(Addr addr)
Definition: Address.cc:54
RubyRequestType htmCmdToRubyRequestType(const Packet *pkt)
std::ostream & operator<<(std::ostream &os, const BoolVec &myvector)
Definition: BoolVec.cc:49
std::string printAddress(Addr addr)
Definition: Address.cc:80
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
uint64_t Tick
Tick count type.
Definition: types.hh:58
int ContextID
Globally unique thread context ID.
Definition: types.hh:239
const ContextID InvalidContextID
Definition: types.hh:240
Declaration of the Packet class.
RubyRequestType m_second_type
Definition: Sequencer.hh:66
RubyRequestType m_type
Definition: Sequencer.hh:65

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