gem5  v22.1.0.0
commit.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2014 Google, Inc.
3  * Copyright (c) 2010-2014, 2017, 2020 ARM Limited
4  * All rights reserved
5  *
6  * The license below extends only to copyright in the software and shall
7  * not be construed as granting a license to any other intellectual
8  * property including but not limited to intellectual property relating
9  * to a hardware implementation of the functionality of the software
10  * licensed hereunder. You may use the software subject to the license
11  * terms below provided that you ensure that this notice is replicated
12  * unmodified and in its entirety in all distributions of the software,
13  * modified or unmodified, in source code or in binary form.
14  *
15  * Copyright (c) 2004-2005 The Regents of The University of Michigan
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 
42 #include "cpu/o3/commit.hh"
43 
44 #include <algorithm>
45 #include <set>
46 #include <string>
47 
48 #include "base/compiler.hh"
49 #include "base/loader/symtab.hh"
50 #include "base/logging.hh"
51 #include "cpu/base.hh"
52 #include "cpu/checker/cpu.hh"
53 #include "cpu/exetrace.hh"
54 #include "cpu/o3/cpu.hh"
55 #include "cpu/o3/dyn_inst.hh"
56 #include "cpu/o3/limits.hh"
57 #include "cpu/o3/thread_state.hh"
58 #include "cpu/timebuf.hh"
59 #include "debug/Activity.hh"
60 #include "debug/Commit.hh"
61 #include "debug/CommitRate.hh"
62 #include "debug/Drain.hh"
63 #include "debug/ExecFaulting.hh"
64 #include "debug/HtmCpu.hh"
65 #include "debug/O3PipeView.hh"
66 #include "params/BaseO3CPU.hh"
67 #include "sim/faults.hh"
68 #include "sim/full_system.hh"
69 
70 namespace gem5
71 {
72 
73 namespace o3
74 {
75 
76 void
78 {
79  // This will get reset by commit if it was switched out at the
80  // time of this event processing.
81  trapSquash[tid] = true;
82 }
83 
84 Commit::Commit(CPU *_cpu, const BaseO3CPUParams &params)
85  : commitPolicy(params.smtCommitPolicy),
86  cpu(_cpu),
87  iewToCommitDelay(params.iewToCommitDelay),
88  commitToIEWDelay(params.commitToIEWDelay),
89  renameToROBDelay(params.renameToROBDelay),
90  fetchToCommitDelay(params.commitToFetchDelay),
91  renameWidth(params.renameWidth),
92  commitWidth(params.commitWidth),
93  numThreads(params.numThreads),
94  drainPending(false),
95  drainImminent(false),
96  trapLatency(params.trapLatency),
97  canHandleInterrupts(true),
98  avoidQuiesceLiveLock(false),
99  stats(_cpu, this)
100 {
101  if (commitWidth > MaxWidth)
102  fatal("commitWidth (%d) is larger than compiled limit (%d),\n"
103  "\tincrease MaxWidth in src/cpu/o3/limits.hh\n",
104  commitWidth, static_cast<int>(MaxWidth));
105 
106  _status = Active;
108 
109  if (commitPolicy == CommitPolicy::RoundRobin) {
110  //Set-Up Priority List
111  for (ThreadID tid = 0; tid < numThreads; tid++) {
112  priority_list.push_back(tid);
113  }
114  }
115 
116  for (ThreadID tid = 0; tid < MaxThreads; tid++) {
117  commitStatus[tid] = Idle;
118  changedROBNumEntries[tid] = false;
119  trapSquash[tid] = false;
120  tcSquash[tid] = false;
121  squashAfterInst[tid] = nullptr;
122  pc[tid].reset(params.isa[0]->newPCState());
123  youngestSeqNum[tid] = 0;
124  lastCommitedSeqNum[tid] = 0;
125  trapInFlight[tid] = false;
126  committedStores[tid] = false;
127  checkEmptyROB[tid] = false;
128  renameMap[tid] = nullptr;
129  htmStarts[tid] = 0;
130  htmStops[tid] = 0;
131  }
132  interrupt = NoFault;
133 }
134 
135 std::string Commit::name() const { return cpu->name() + ".commit"; }
136 
137 void
139 {
141  cpu->getProbeManager(), "Commit");
143  cpu->getProbeManager(), "CommitStall");
145  cpu->getProbeManager(), "Squash");
146 }
147 
149  : statistics::Group(cpu, "commit"),
150  ADD_STAT(commitSquashedInsts, statistics::units::Count::get(),
151  "The number of squashed insts skipped by commit"),
152  ADD_STAT(commitNonSpecStalls, statistics::units::Count::get(),
153  "The number of times commit has been forced to stall to "
154  "communicate backwards"),
155  ADD_STAT(branchMispredicts, statistics::units::Count::get(),
156  "The number of times a branch was mispredicted"),
157  ADD_STAT(numCommittedDist, statistics::units::Count::get(),
158  "Number of insts commited each cycle"),
159  ADD_STAT(instsCommitted, statistics::units::Count::get(),
160  "Number of instructions committed"),
161  ADD_STAT(opsCommitted, statistics::units::Count::get(),
162  "Number of ops (including micro ops) committed"),
163  ADD_STAT(memRefs, statistics::units::Count::get(),
164  "Number of memory references committed"),
165  ADD_STAT(loads, statistics::units::Count::get(), "Number of loads committed"),
166  ADD_STAT(amos, statistics::units::Count::get(),
167  "Number of atomic instructions committed"),
168  ADD_STAT(membars, statistics::units::Count::get(),
169  "Number of memory barriers committed"),
170  ADD_STAT(branches, statistics::units::Count::get(),
171  "Number of branches committed"),
172  ADD_STAT(vectorInstructions, statistics::units::Count::get(),
173  "Number of committed Vector instructions."),
174  ADD_STAT(floating, statistics::units::Count::get(),
175  "Number of committed floating point instructions."),
176  ADD_STAT(integer, statistics::units::Count::get(),
177  "Number of committed integer instructions."),
178  ADD_STAT(functionCalls, statistics::units::Count::get(),
179  "Number of function calls committed."),
180  ADD_STAT(committedInstType, statistics::units::Count::get(),
181  "Class of committed instruction"),
182  ADD_STAT(commitEligibleSamples, statistics::units::Cycle::get(),
183  "number cycles where commit BW limit reached")
184 {
185  using namespace statistics;
186 
190 
192  .init(0,commit->commitWidth,1)
194 
196  .init(cpu->numThreads)
197  .flags(total);
198 
200  .init(cpu->numThreads)
201  .flags(total);
202 
203  memRefs
204  .init(cpu->numThreads)
205  .flags(total);
206 
207  loads
208  .init(cpu->numThreads)
209  .flags(total);
210 
211  amos
212  .init(cpu->numThreads)
213  .flags(total);
214 
215  membars
216  .init(cpu->numThreads)
217  .flags(total);
218 
219  branches
220  .init(cpu->numThreads)
221  .flags(total);
222 
224  .init(cpu->numThreads)
225  .flags(total);
226 
227  floating
228  .init(cpu->numThreads)
229  .flags(total);
230 
231  integer
232  .init(cpu->numThreads)
233  .flags(total);
234 
236  .init(commit->numThreads)
237  .flags(total);
238 
240  .init(commit->numThreads,enums::Num_OpClass)
241  .flags(total | pdf | dist);
242 
243  committedInstType.ysubnames(enums::OpClassStrings);
244 }
245 
246 void
248 {
249  thread = threads;
250 }
251 
252 void
254 {
255  timeBuffer = tb_ptr;
256 
257  // Setup wire to send information back to IEW.
258  toIEW = timeBuffer->getWire(0);
259 
260  // Setup wire to read data from IEW (for the ROB).
262 }
263 
264 void
266 {
267  fetchQueue = fq_ptr;
268 
269  // Setup wire to get instructions from rename (for the ROB).
271 }
272 
273 void
275 {
276  renameQueue = rq_ptr;
277 
278  // Setup wire to get instructions from rename (for the ROB).
280 }
281 
282 void
284 {
285  iewQueue = iq_ptr;
286 
287  // Setup wire to get instructions from IEW.
288  fromIEW = iewQueue->getWire(-iewToCommitDelay);
289 }
290 
291 void
293 {
294  iewStage = iew_stage;
295 }
296 
297 void
299 {
300  activeThreads = at_ptr;
301 }
302 
303 void
305 {
306  for (ThreadID tid = 0; tid < numThreads; tid++)
307  renameMap[tid] = &rm_ptr[tid];
308 }
309 
310 void Commit::setROB(ROB *rob_ptr) { rob = rob_ptr; }
311 
312 void
314 {
316  rob->resetEntries();
317 
318  // Broadcast the number of free entries.
319  for (ThreadID tid = 0; tid < numThreads; tid++) {
320  toIEW->commitInfo[tid].usedROB = true;
321  toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
322  toIEW->commitInfo[tid].emptyROB = true;
323  }
324 
325  // Commit must broadcast the number of free entries it has at the
326  // start of the simulation, so it starts as active.
328 
330 }
331 
332 void
334 {
335  commitStatus[tid] = Idle;
336  changedROBNumEntries[tid] = false;
337  checkEmptyROB[tid] = false;
338  trapInFlight[tid] = false;
339  committedStores[tid] = false;
340  trapSquash[tid] = false;
341  tcSquash[tid] = false;
342  pc[tid].reset(cpu->tcBase(tid)->getIsaPtr()->newPCState());
343  lastCommitedSeqNum[tid] = 0;
344  squashAfterInst[tid] = NULL;
345 }
346 
347 void Commit::drain() { drainPending = true; }
348 
349 void
351 {
352  drainPending = false;
353  drainImminent = false;
354 }
355 
356 void
358 {
359  assert(isDrained());
361 
362  // hardware transactional memory
363  // cannot drain partially through a transaction
364  for (ThreadID tid = 0; tid < numThreads; tid++) {
365  if (executingHtmTransaction(tid)) {
366  panic("cannot drain partially through a HTM transaction");
367  }
368  }
369 }
370 
371 bool
373 {
374  /* Make sure no one is executing microcode. There are two reasons
375  * for this:
376  * - Hardware virtualized CPUs can't switch into the middle of a
377  * microcode sequence.
378  * - The current fetch implementation will most likely get very
379  * confused if it tries to start fetching an instruction that
380  * is executing in the middle of a ucode sequence that changes
381  * address mappings. This can happen on for example x86.
382  */
383  for (ThreadID tid = 0; tid < numThreads; tid++) {
384  if (pc[tid]->microPC() != 0)
385  return false;
386  }
387 
388  /* Make sure that all instructions have finished committing before
389  * declaring the system as drained. We want the pipeline to be
390  * completely empty when we declare the CPU to be drained. This
391  * makes debugging easier since CPU handover and restoring from a
392  * checkpoint with a different CPU should have the same timing.
393  */
394  return rob->isEmpty() &&
395  interrupt == NoFault;
396 }
397 
398 void
400 {
401  _status = Active;
403  for (ThreadID tid = 0; tid < numThreads; tid++) {
404  commitStatus[tid] = Idle;
405  changedROBNumEntries[tid] = false;
406  trapSquash[tid] = false;
407  tcSquash[tid] = false;
408  squashAfterInst[tid] = NULL;
409  }
410  rob->takeOverFrom();
411 }
412 
413 void
415 {
416  std::list<ThreadID>::iterator thread_it = std::find(priority_list.begin(),
417  priority_list.end(), tid);
418 
419  if (thread_it != priority_list.end()) {
420  priority_list.erase(thread_it);
421  }
422 }
423 
424 bool
426 {
427  if (tid == InvalidThreadID)
428  return false;
429  else
430  return (htmStarts[tid] > htmStops[tid]);
431 }
432 
433 void
435 {
436  if (tid != InvalidThreadID)
437  {
438  htmStarts[tid] = 0;
439  htmStops[tid] = 0;
440  }
441 }
442 
443 
444 void
446 {
447  // reset ROB changed variable
448  std::list<ThreadID>::iterator threads = activeThreads->begin();
450 
451  while (threads != end) {
452  ThreadID tid = *threads++;
453 
454  changedROBNumEntries[tid] = false;
455 
456  // Also check if any of the threads has a trap pending
457  if (commitStatus[tid] == TrapPending ||
458  commitStatus[tid] == FetchTrapPending) {
460  }
461  }
462 
463  if (_nextStatus == Inactive && _status == Active) {
464  DPRINTF(Activity, "Deactivating stage.\n");
466  } else if (_nextStatus == Active && _status == Inactive) {
467  DPRINTF(Activity, "Activating stage.\n");
469  }
470 
472 }
473 
474 bool
476 {
477  std::list<ThreadID>::iterator threads = activeThreads->begin();
479 
480  while (threads != end) {
481  ThreadID tid = *threads++;
482 
483  if (changedROBNumEntries[tid]) {
484  return true;
485  }
486  }
487 
488  return false;
489 }
490 
491 size_t
493 {
494  return rob->numFreeEntries(tid);
495 }
496 
497 void
499 {
500  DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid);
501 
503  [this, tid]{ processTrapEvent(tid); },
504  "Trap", true, Event::CPU_Tick_Pri);
505 
506  Cycles latency = std::dynamic_pointer_cast<SyscallRetryFault>(inst_fault) ?
508 
509  // hardware transactional memory
510  if (inst_fault != nullptr &&
511  std::dynamic_pointer_cast<GenericHtmFailureFault>(inst_fault)) {
512  // TODO
513  // latency = default abort/restore latency
514  // could also do some kind of exponential back off if desired
515  }
516 
517  cpu->schedule(trap, cpu->clockEdge(latency));
518  trapInFlight[tid] = true;
519  thread[tid]->trapPending = true;
520 }
521 
522 void
524 {
525  assert(!trapInFlight[tid]);
526  DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid);
527 
528  tcSquash[tid] = true;
529 }
530 
531 void
533 {
534  // If we want to include the squashing instruction in the squash,
535  // then use one older sequence number.
536  // Hopefully this doesn't mess things up. Basically I want to squash
537  // all instructions of this thread.
538  InstSeqNum squashed_inst = rob->isEmpty(tid) ?
539  lastCommitedSeqNum[tid] : rob->readHeadInst(tid)->seqNum - 1;
540 
541  // All younger instructions will be squashed. Set the sequence
542  // number as the youngest instruction in the ROB (0 in this case.
543  // Hopefully nothing breaks.)
545 
546  rob->squash(squashed_inst, tid);
547  changedROBNumEntries[tid] = true;
548 
549  // Send back the sequence number of the squashed instruction.
550  toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
551 
552  // Send back the squash signal to tell stages that they should
553  // squash.
554  toIEW->commitInfo[tid].squash = true;
555 
556  // Send back the rob squashing signal so other stages know that
557  // the ROB is in the process of squashing.
558  toIEW->commitInfo[tid].robSquashing = true;
559 
560  toIEW->commitInfo[tid].mispredictInst = NULL;
561  toIEW->commitInfo[tid].squashInst = NULL;
562 
563  set(toIEW->commitInfo[tid].pc, pc[tid]);
564 }
565 
566 void
568 {
569  squashAll(tid);
570 
571  DPRINTF(Commit, "Squashing from trap, restarting at PC %s\n", *pc[tid]);
572 
573  thread[tid]->trapPending = false;
574  thread[tid]->noSquashFromTC = false;
575  trapInFlight[tid] = false;
576 
577  trapSquash[tid] = false;
578 
579  commitStatus[tid] = ROBSquashing;
581 }
582 
583 void
585 {
586  squashAll(tid);
587 
588  DPRINTF(Commit, "Squashing from TC, restarting at PC %s\n", *pc[tid]);
589 
590  thread[tid]->noSquashFromTC = false;
591  assert(!thread[tid]->trapPending);
592 
593  commitStatus[tid] = ROBSquashing;
595 
596  tcSquash[tid] = false;
597 }
598 
599 void
601 {
602  DPRINTF(Commit, "Squashing after squash after request, "
603  "restarting at PC %s\n", *pc[tid]);
604 
605  squashAll(tid);
606  // Make sure to inform the fetch stage of which instruction caused
607  // the squash. It'll try to re-fetch an instruction executing in
608  // microcode unless this is set.
609  toIEW->commitInfo[tid].squashInst = squashAfterInst[tid];
610  squashAfterInst[tid] = NULL;
611 
612  commitStatus[tid] = ROBSquashing;
614 }
615 
616 void
618 {
619  DPRINTF(Commit, "Executing squash after for [tid:%i] inst [sn:%llu]\n",
620  tid, head_inst->seqNum);
621 
622  assert(!squashAfterInst[tid] || squashAfterInst[tid] == head_inst);
624  squashAfterInst[tid] = head_inst;
625 }
626 
627 void
629 {
630  wroteToTimeBuffer = false;
632 
633  if (activeThreads->empty())
634  return;
635 
636  std::list<ThreadID>::iterator threads = activeThreads->begin();
638 
639  // Check if any of the threads are done squashing. Change the
640  // status if they are done.
641  while (threads != end) {
642  ThreadID tid = *threads++;
643 
644  // Clear the bit saying if the thread has committed stores
645  // this cycle.
646  committedStores[tid] = false;
647 
648  if (commitStatus[tid] == ROBSquashing) {
649 
650  if (rob->isDoneSquashing(tid)) {
651  commitStatus[tid] = Running;
652  } else {
653  DPRINTF(Commit,"[tid:%i] Still Squashing, cannot commit any"
654  " insts this cycle.\n", tid);
655  rob->doSquash(tid);
656  toIEW->commitInfo[tid].robSquashing = true;
657  wroteToTimeBuffer = true;
658  }
659  }
660  }
661 
662  commit();
663 
665 
666  threads = activeThreads->begin();
667 
668  while (threads != end) {
669  ThreadID tid = *threads++;
670 
671  if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) {
672  // The ROB has more instructions it can commit. Its next status
673  // will be active.
675 
676  [[maybe_unused]] const DynInstPtr &inst = rob->readHeadInst(tid);
677 
678  DPRINTF(Commit,"[tid:%i] Instruction [sn:%llu] PC %s is head of"
679  " ROB and ready to commit\n",
680  tid, inst->seqNum, inst->pcState());
681 
682  } else if (!rob->isEmpty(tid)) {
683  const DynInstPtr &inst = rob->readHeadInst(tid);
684 
685  ppCommitStall->notify(inst);
686 
687  DPRINTF(Commit,"[tid:%i] Can't commit, Instruction [sn:%llu] PC "
688  "%s is head of ROB and not ready\n",
689  tid, inst->seqNum, inst->pcState());
690  }
691 
692  DPRINTF(Commit, "[tid:%i] ROB has %d insts & %d free entries.\n",
693  tid, rob->countInsts(tid), rob->numFreeEntries(tid));
694  }
695 
696 
697  if (wroteToTimeBuffer) {
698  DPRINTF(Activity, "Activity This Cycle.\n");
700  }
701 
702  updateStatus();
703 }
704 
705 void
707 {
708  // Verify that we still have an interrupt to handle
709  if (!cpu->checkInterrupts(0)) {
710  DPRINTF(Commit, "Pending interrupt is cleared by requestor before "
711  "it got handled. Restart fetching from the orig path.\n");
712  toIEW->commitInfo[0].clearInterrupt = true;
713  interrupt = NoFault;
714  avoidQuiesceLiveLock = true;
715  return;
716  }
717 
718  // Wait until all in flight instructions are finished before enterring
719  // the interrupt.
720  if (canHandleInterrupts && cpu->instList.empty()) {
721  // Squash or record that I need to squash this cycle if
722  // an interrupt needed to be handled.
723  DPRINTF(Commit, "Interrupt detected.\n");
724 
725  // Clear the interrupt now that it's going to be handled
726  toIEW->commitInfo[0].clearInterrupt = true;
727 
728  assert(!thread[0]->noSquashFromTC);
729  thread[0]->noSquashFromTC = true;
730 
731  if (cpu->checker) {
732  cpu->checker->handlePendingInt();
733  }
734 
735  // CPU will handle interrupt. Note that we ignore the local copy of
736  // interrupt. This is because the local copy may no longer be the
737  // interrupt that the interrupt controller thinks is being handled.
739 
740  thread[0]->noSquashFromTC = false;
741 
743 
744  interrupt = NoFault;
745 
746  // Generate trap squash event.
748 
749  avoidQuiesceLiveLock = false;
750  } else {
751  DPRINTF(Commit, "Interrupt pending: instruction is %sin "
752  "flight, ROB is %sempty\n",
753  canHandleInterrupts ? "not " : "",
754  cpu->instList.empty() ? "" : "not " );
755  }
756 }
757 
758 void
760 {
761  // Don't propagate intterupts if we are currently handling a trap or
762  // in draining and the last observable instruction has been committed.
763  if (commitStatus[0] == TrapPending || interrupt || trapSquash[0] ||
764  tcSquash[0] || drainImminent)
765  return;
766 
767  // Process interrupts if interrupts are enabled, not in PAL
768  // mode, and no other traps or external squashes are currently
769  // pending.
770  // @todo: Allow other threads to handle interrupts.
771 
772  // Get any interrupt that happened
774 
775  // Tell fetch that there is an interrupt pending. This
776  // will make fetch wait until it sees a non PAL-mode PC,
777  // at which point it stops fetching instructions.
778  if (interrupt != NoFault)
779  toIEW->commitInfo[0].interruptPending = true;
780 }
781 
782 void
784 {
785  if (FullSystem) {
786  // Check if we have a interrupt and get read to handle it
787  if (cpu->checkInterrupts(0))
789  }
790 
792  // Check for any possible squashes, handle them first
794  std::list<ThreadID>::iterator threads = activeThreads->begin();
796 
797  int num_squashing_threads = 0;
798 
799  while (threads != end) {
800  ThreadID tid = *threads++;
801 
802  // Not sure which one takes priority. I think if we have
803  // both, that's a bad sign.
804  if (trapSquash[tid]) {
805  assert(!tcSquash[tid]);
806  squashFromTrap(tid);
807 
808  // If the thread is trying to exit (i.e., an exit syscall was
809  // executed), this trapSquash was originated by the exit
810  // syscall earlier. In this case, schedule an exit event in
811  // the next cycle to fully terminate this thread
812  if (cpu->isThreadExiting(tid))
814  } else if (tcSquash[tid]) {
815  assert(commitStatus[tid] != TrapPending);
816  squashFromTC(tid);
817  } else if (commitStatus[tid] == SquashAfterPending) {
818  // A squash from the previous cycle of the commit stage (i.e.,
819  // commitInsts() called squashAfter) is pending. Squash the
820  // thread now.
822  }
823 
824  // Squashed sequence number must be older than youngest valid
825  // instruction in the ROB. This prevents squashes from younger
826  // instructions overriding squashes from older instructions.
827  if (fromIEW->squash[tid] &&
828  commitStatus[tid] != TrapPending &&
829  fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
830 
831  if (fromIEW->mispredictInst[tid]) {
832  DPRINTF(Commit,
833  "[tid:%i] Squashing due to branch mispred "
834  "PC:%#x [sn:%llu]\n",
835  tid,
836  fromIEW->mispredictInst[tid]->pcState().instAddr(),
837  fromIEW->squashedSeqNum[tid]);
838  } else {
839  DPRINTF(Commit,
840  "[tid:%i] Squashing due to order violation [sn:%llu]\n",
841  tid, fromIEW->squashedSeqNum[tid]);
842  }
843 
844  DPRINTF(Commit, "[tid:%i] Redirecting to PC %#x\n",
845  tid, *fromIEW->pc[tid]);
846 
847  commitStatus[tid] = ROBSquashing;
848 
849  // If we want to include the squashing instruction in the squash,
850  // then use one older sequence number.
851  InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
852 
853  if (fromIEW->includeSquashInst[tid]) {
854  squashed_inst--;
855  }
856 
857  // All younger instructions will be squashed. Set the sequence
858  // number as the youngest instruction in the ROB.
859  youngestSeqNum[tid] = squashed_inst;
860 
861  rob->squash(squashed_inst, tid);
862  changedROBNumEntries[tid] = true;
863 
864  toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
865 
866  toIEW->commitInfo[tid].squash = true;
867 
868  // Send back the rob squashing signal so other stages know that
869  // the ROB is in the process of squashing.
870  toIEW->commitInfo[tid].robSquashing = true;
871 
872  toIEW->commitInfo[tid].mispredictInst =
873  fromIEW->mispredictInst[tid];
874  toIEW->commitInfo[tid].branchTaken =
875  fromIEW->branchTaken[tid];
876  toIEW->commitInfo[tid].squashInst =
877  rob->findInst(tid, squashed_inst);
878  if (toIEW->commitInfo[tid].mispredictInst) {
879  if (toIEW->commitInfo[tid].mispredictInst->isUncondCtrl()) {
880  toIEW->commitInfo[tid].branchTaken = true;
881  }
882  ++stats.branchMispredicts;
883  }
884 
885  set(toIEW->commitInfo[tid].pc, fromIEW->pc[tid]);
886  }
887 
888  if (commitStatus[tid] == ROBSquashing) {
889  num_squashing_threads++;
890  }
891  }
892 
893  // If commit is currently squashing, then it will have activity for the
894  // next cycle. Set its next status as active.
895  if (num_squashing_threads) {
897  }
898 
899  if (num_squashing_threads != numThreads) {
900  // If we're not currently squashing, then get instructions.
901  getInsts();
902 
903  // Try to commit any instructions.
904  commitInsts();
905  }
906 
907  //Check for any activity
908  threads = activeThreads->begin();
909 
910  while (threads != end) {
911  ThreadID tid = *threads++;
912 
913  if (changedROBNumEntries[tid]) {
914  toIEW->commitInfo[tid].usedROB = true;
915  toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
916 
917  wroteToTimeBuffer = true;
918  changedROBNumEntries[tid] = false;
919  if (rob->isEmpty(tid))
920  checkEmptyROB[tid] = true;
921  }
922 
923  // ROB is only considered "empty" for previous stages if: a)
924  // ROB is empty, b) there are no outstanding stores, c) IEW
925  // stage has received any information regarding stores that
926  // committed.
927  // c) is checked by making sure to not consider the ROB empty
928  // on the same cycle as when stores have been committed.
929  // @todo: Make this handle multi-cycle communication between
930  // commit and IEW.
931  if (checkEmptyROB[tid] && rob->isEmpty(tid) &&
932  !iewStage->hasStoresToWB(tid) && !committedStores[tid]) {
933  checkEmptyROB[tid] = false;
934  toIEW->commitInfo[tid].usedROB = true;
935  toIEW->commitInfo[tid].emptyROB = true;
936  toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
937  wroteToTimeBuffer = true;
938  }
939 
940  }
941 }
942 
943 void
945 {
947  // Handle commit
948  // Note that commit will be handled prior to putting new
949  // instructions in the ROB so that the ROB only tries to commit
950  // instructions it has in this current cycle, and not instructions
951  // it is writing in during this cycle. Can't commit and squash
952  // things at the same time...
954 
955  DPRINTF(Commit, "Trying to commit instructions in the ROB.\n");
956 
957  unsigned num_committed = 0;
958 
959  DynInstPtr head_inst;
960 
961  // Commit as many instructions as possible until the commit bandwidth
962  // limit is reached, or it becomes impossible to commit any more.
963  while (num_committed < commitWidth) {
964  // hardware transactionally memory
965  // If executing within a transaction,
966  // need to handle interrupts specially
967 
968  ThreadID commit_thread = getCommittingThread();
969 
970  // Check for any interrupt that we've already squashed for
971  // and start processing it.
972  if (interrupt != NoFault) {
973  // If inside a transaction, postpone interrupts
974  if (executingHtmTransaction(commit_thread)) {
975  cpu->clearInterrupts(0);
976  toIEW->commitInfo[0].clearInterrupt = true;
977  interrupt = NoFault;
978  avoidQuiesceLiveLock = true;
979  } else {
980  handleInterrupt();
981  }
982  }
983 
984  // ThreadID commit_thread = getCommittingThread();
985 
986  if (commit_thread == -1 || !rob->isHeadReady(commit_thread))
987  break;
988 
989  head_inst = rob->readHeadInst(commit_thread);
990 
991  ThreadID tid = head_inst->threadNumber;
992 
993  assert(tid == commit_thread);
994 
995  DPRINTF(Commit,
996  "Trying to commit head instruction, [tid:%i] [sn:%llu]\n",
997  tid, head_inst->seqNum);
998 
999  // If the head instruction is squashed, it is ready to retire
1000  // (be removed from the ROB) at any time.
1001  if (head_inst->isSquashed()) {
1002 
1003  DPRINTF(Commit, "Retiring squashed instruction from "
1004  "ROB.\n");
1005 
1006  rob->retireHead(commit_thread);
1007 
1008  ++stats.commitSquashedInsts;
1009  // Notify potential listeners that this instruction is squashed
1010  ppSquash->notify(head_inst);
1011 
1012  // Record that the number of ROB entries has changed.
1013  changedROBNumEntries[tid] = true;
1014  } else {
1015  set(pc[tid], head_inst->pcState());
1016 
1017  // Try to commit the head instruction.
1018  bool commit_success = commitHead(head_inst, num_committed);
1019 
1020  if (commit_success) {
1021  ++num_committed;
1022  stats.committedInstType[tid][head_inst->opClass()]++;
1023  ppCommit->notify(head_inst);
1024 
1025  // hardware transactional memory
1026 
1027  // update nesting depth
1028  if (head_inst->isHtmStart())
1029  htmStarts[tid]++;
1030 
1031  // sanity check
1032  if (head_inst->inHtmTransactionalState()) {
1033  assert(executingHtmTransaction(tid));
1034  } else {
1035  assert(!executingHtmTransaction(tid));
1036  }
1037 
1038  // update nesting depth
1039  if (head_inst->isHtmStop())
1040  htmStops[tid]++;
1041 
1042  changedROBNumEntries[tid] = true;
1043 
1044  // Set the doneSeqNum to the youngest committed instruction.
1045  toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;
1046 
1047  if (tid == 0)
1048  canHandleInterrupts = !head_inst->isDelayedCommit();
1049 
1050  // at this point store conditionals should either have
1051  // been completed or predicated false
1052  assert(!head_inst->isStoreConditional() ||
1053  head_inst->isCompleted() ||
1054  !head_inst->readPredicate());
1055 
1056  // Updates misc. registers.
1057  head_inst->updateMiscRegs();
1058 
1059  // Check instruction execution if it successfully commits and
1060  // is not carrying a fault.
1061  if (cpu->checker) {
1062  cpu->checker->verify(head_inst);
1063  }
1064 
1065  cpu->traceFunctions(pc[tid]->instAddr());
1066 
1067  head_inst->staticInst->advancePC(*pc[tid]);
1068 
1069  // Keep track of the last sequence number commited
1070  lastCommitedSeqNum[tid] = head_inst->seqNum;
1071 
1072  // If this is an instruction that doesn't play nicely with
1073  // others squash everything and restart fetch
1074  if (head_inst->isSquashAfter())
1075  squashAfter(tid, head_inst);
1076 
1077  if (drainPending) {
1078  if (pc[tid]->microPC() == 0 && interrupt == NoFault &&
1079  !thread[tid]->trapPending) {
1080  // Last architectually committed instruction.
1081  // Squash the pipeline, stall fetch, and use
1082  // drainImminent to disable interrupts
1083  DPRINTF(Drain, "Draining: %i:%s\n", tid, *pc[tid]);
1084  squashAfter(tid, head_inst);
1085  cpu->commitDrained(tid);
1086  drainImminent = true;
1087  }
1088  }
1089 
1090  bool onInstBoundary = !head_inst->isMicroop() ||
1091  head_inst->isLastMicroop() ||
1092  !head_inst->isDelayedCommit();
1093 
1094  if (onInstBoundary) {
1095  int count = 0;
1096  Addr oldpc;
1097  // Make sure we're not currently updating state while
1098  // handling PC events.
1099  assert(!thread[tid]->noSquashFromTC &&
1100  !thread[tid]->trapPending);
1101  do {
1102  oldpc = pc[tid]->instAddr();
1103  thread[tid]->pcEventQueue.service(
1104  oldpc, thread[tid]->getTC());
1105  count++;
1106  } while (oldpc != pc[tid]->instAddr());
1107  if (count > 1) {
1108  DPRINTF(Commit,
1109  "PC skip function event, stopping commit\n");
1110  break;
1111  }
1112  }
1113 
1114  // Check if an instruction just enabled interrupts and we've
1115  // previously had an interrupt pending that was not handled
1116  // because interrupts were subsequently disabled before the
1117  // pipeline reached a place to handle the interrupt. In that
1118  // case squash now to make sure the interrupt is handled.
1119  //
1120  // If we don't do this, we might end up in a live lock
1121  // situation.
1122  if (!interrupt && avoidQuiesceLiveLock &&
1123  onInstBoundary && cpu->checkInterrupts(0))
1124  squashAfter(tid, head_inst);
1125  } else {
1126  DPRINTF(Commit, "Unable to commit head instruction PC:%s "
1127  "[tid:%i] [sn:%llu].\n",
1128  head_inst->pcState(), tid ,head_inst->seqNum);
1129  break;
1130  }
1131  }
1132  }
1133 
1134  DPRINTF(CommitRate, "%i\n", num_committed);
1135  stats.numCommittedDist.sample(num_committed);
1136 
1137  if (num_committed == commitWidth) {
1138  stats.commitEligibleSamples++;
1139  }
1140 }
1141 
1142 bool
1143 Commit::commitHead(const DynInstPtr &head_inst, unsigned inst_num)
1144 {
1145  assert(head_inst);
1146 
1147  ThreadID tid = head_inst->threadNumber;
1148 
1149  // If the instruction is not executed yet, then it will need extra
1150  // handling. Signal backwards that it should be executed.
1151  if (!head_inst->isExecuted()) {
1152  // Make sure we are only trying to commit un-executed instructions we
1153  // think are possible.
1154  assert(head_inst->isNonSpeculative() || head_inst->isStoreConditional()
1155  || head_inst->isReadBarrier() || head_inst->isWriteBarrier()
1156  || head_inst->isAtomic()
1157  || (head_inst->isLoad() && head_inst->strictlyOrdered()));
1158 
1159  DPRINTF(Commit,
1160  "Encountered a barrier or non-speculative "
1161  "instruction [tid:%i] [sn:%llu] "
1162  "at the head of the ROB, PC %s.\n",
1163  tid, head_inst->seqNum, head_inst->pcState());
1164 
1165  if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
1166  DPRINTF(Commit,
1167  "[tid:%i] [sn:%llu] "
1168  "Waiting for all stores to writeback.\n",
1169  tid, head_inst->seqNum);
1170  return false;
1171  }
1172 
1173  toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
1174 
1175  // Change the instruction so it won't try to commit again until
1176  // it is executed.
1177  head_inst->clearCanCommit();
1178 
1179  if (head_inst->isLoad() && head_inst->strictlyOrdered()) {
1180  DPRINTF(Commit, "[tid:%i] [sn:%llu] "
1181  "Strictly ordered load, PC %s.\n",
1182  tid, head_inst->seqNum, head_inst->pcState());
1183  toIEW->commitInfo[tid].strictlyOrdered = true;
1184  toIEW->commitInfo[tid].strictlyOrderedLoad = head_inst;
1185  } else {
1186  ++stats.commitNonSpecStalls;
1187  }
1188 
1189  return false;
1190  }
1191 
1192  // Check if the instruction caused a fault. If so, trap.
1193  Fault inst_fault = head_inst->getFault();
1194 
1195  // hardware transactional memory
1196  // if a fault occurred within a HTM transaction
1197  // ensure that the transaction aborts
1198  if (inst_fault != NoFault && head_inst->inHtmTransactionalState()) {
1199  // There exists a generic HTM fault common to all ISAs
1200  if (!std::dynamic_pointer_cast<GenericHtmFailureFault>(inst_fault)) {
1201  DPRINTF(HtmCpu, "%s - fault (%s) encountered within transaction"
1202  " - converting to GenericHtmFailureFault\n",
1203  head_inst->staticInst->getName(), inst_fault->name());
1204  inst_fault = std::make_shared<GenericHtmFailureFault>(
1205  head_inst->getHtmTransactionUid(),
1207  }
1208  // If this point is reached and the fault inherits from the HTM fault,
1209  // then there is no need to raise a new fault
1210  }
1211 
1212  // Stores mark themselves as completed.
1213  if (!head_inst->isStore() && inst_fault == NoFault) {
1214  head_inst->setCompleted();
1215  }
1216 
1217  if (inst_fault != NoFault) {
1218  DPRINTF(Commit, "Inst [tid:%i] [sn:%llu] PC %s has a fault\n",
1219  tid, head_inst->seqNum, head_inst->pcState());
1220 
1221  if (iewStage->hasStoresToWB(tid) || inst_num > 0) {
1222  DPRINTF(Commit,
1223  "[tid:%i] [sn:%llu] "
1224  "Stores outstanding, fault must wait.\n",
1225  tid, head_inst->seqNum);
1226  return false;
1227  }
1228 
1229  head_inst->setCompleted();
1230 
1231  // If instruction has faulted, let the checker execute it and
1232  // check if it sees the same fault and control flow.
1233  if (cpu->checker) {
1234  // Need to check the instruction before its fault is processed
1235  cpu->checker->verify(head_inst);
1236  }
1237 
1238  assert(!thread[tid]->noSquashFromTC);
1239 
1240  // Mark that we're in state update mode so that the trap's
1241  // execution doesn't generate extra squashes.
1242  thread[tid]->noSquashFromTC = true;
1243 
1244  // Execute the trap. Although it's slightly unrealistic in
1245  // terms of timing (as it doesn't wait for the full timing of
1246  // the trap event to complete before updating state), it's
1247  // needed to update the state as soon as possible. This
1248  // prevents external agents from changing any specific state
1249  // that the trap need.
1250  cpu->trap(inst_fault, tid,
1251  head_inst->notAnInst() ? nullStaticInstPtr :
1252  head_inst->staticInst);
1253 
1254  // Exit state update mode to avoid accidental updating.
1255  thread[tid]->noSquashFromTC = false;
1256 
1257  commitStatus[tid] = TrapPending;
1258 
1259  DPRINTF(Commit,
1260  "[tid:%i] [sn:%llu] Committing instruction with fault\n",
1261  tid, head_inst->seqNum);
1262  if (head_inst->traceData) {
1263  // We ignore ReExecution "faults" here as they are not real
1264  // (architectural) faults but signal flush/replays.
1265  if (debug::ExecFaulting
1266  && dynamic_cast<ReExec*>(inst_fault.get()) == nullptr) {
1267 
1268  head_inst->traceData->setFaulting(true);
1269  head_inst->traceData->setFetchSeq(head_inst->seqNum);
1270  head_inst->traceData->setCPSeq(thread[tid]->numOp);
1271  head_inst->traceData->dump();
1272  }
1273  delete head_inst->traceData;
1274  head_inst->traceData = NULL;
1275  }
1276 
1277  // Generate trap squash event.
1278  generateTrapEvent(tid, inst_fault);
1279  return false;
1280  }
1281 
1282  updateComInstStats(head_inst);
1283 
1284  DPRINTF(Commit,
1285  "[tid:%i] [sn:%llu] Committing instruction with PC %s\n",
1286  tid, head_inst->seqNum, head_inst->pcState());
1287  if (head_inst->traceData) {
1288  head_inst->traceData->setFetchSeq(head_inst->seqNum);
1289  head_inst->traceData->setCPSeq(thread[tid]->numOp);
1290  head_inst->traceData->dump();
1291  delete head_inst->traceData;
1292  head_inst->traceData = NULL;
1293  }
1294  if (head_inst->isReturn()) {
1295  DPRINTF(Commit,
1296  "[tid:%i] [sn:%llu] Return Instruction Committed PC %s \n",
1297  tid, head_inst->seqNum, head_inst->pcState());
1298  }
1299 
1300  // Update the commit rename map
1301  for (int i = 0; i < head_inst->numDestRegs(); i++) {
1302  renameMap[tid]->setEntry(head_inst->flattenedDestIdx(i),
1303  head_inst->renamedDestIdx(i));
1304  }
1305 
1306  // hardware transactional memory
1307  // the HTM UID is purely for correctness and debugging purposes
1308  if (head_inst->isHtmStart())
1309  iewStage->setLastRetiredHtmUid(tid, head_inst->getHtmTransactionUid());
1310 
1311  // Finally clear the head ROB entry.
1312  rob->retireHead(tid);
1313 
1314 #if TRACING_ON
1315  if (debug::O3PipeView) {
1316  head_inst->commitTick = curTick() - head_inst->fetchTick;
1317  }
1318 #endif
1319 
1320  // If this was a store, record it for this cycle.
1321  if (head_inst->isStore() || head_inst->isAtomic())
1322  committedStores[tid] = true;
1323 
1324  // Return true to indicate that we have committed an instruction.
1325  return true;
1326 }
1327 
1328 void
1330 {
1331  DPRINTF(Commit, "Getting instructions from Rename stage.\n");
1332 
1333  // Read any renamed instructions and place them into the ROB.
1334  int insts_to_process = std::min((int)renameWidth, fromRename->size);
1335 
1336  for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) {
1337  const DynInstPtr &inst = fromRename->insts[inst_num];
1338  ThreadID tid = inst->threadNumber;
1339 
1340  if (!inst->isSquashed() &&
1341  commitStatus[tid] != ROBSquashing &&
1342  commitStatus[tid] != TrapPending) {
1343  changedROBNumEntries[tid] = true;
1344 
1345  DPRINTF(Commit, "[tid:%i] [sn:%llu] Inserting PC %s into ROB.\n",
1346  tid, inst->seqNum, inst->pcState());
1347 
1348  rob->insertInst(inst);
1349 
1350  assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid));
1351 
1352  youngestSeqNum[tid] = inst->seqNum;
1353  } else {
1354  DPRINTF(Commit, "[tid:%i] [sn:%llu] "
1355  "Instruction PC %s was squashed, skipping.\n",
1356  tid, inst->seqNum, inst->pcState());
1357  }
1358  }
1359 }
1360 
1361 void
1363 {
1364  // Grab completed insts out of the IEW instruction queue, and mark
1365  // instructions completed within the ROB.
1366  for (int inst_num = 0; inst_num < fromIEW->size; ++inst_num) {
1367  assert(fromIEW->insts[inst_num]);
1368  if (!fromIEW->insts[inst_num]->isSquashed()) {
1369  DPRINTF(Commit, "[tid:%i] Marking PC %s, [sn:%llu] ready "
1370  "within ROB.\n",
1371  fromIEW->insts[inst_num]->threadNumber,
1372  fromIEW->insts[inst_num]->pcState(),
1373  fromIEW->insts[inst_num]->seqNum);
1374 
1375  // Mark the instruction as ready to commit.
1376  fromIEW->insts[inst_num]->setCanCommit();
1377  }
1378  }
1379 }
1380 
1381 void
1383 {
1384  ThreadID tid = inst->threadNumber;
1385 
1386  if (!inst->isMicroop() || inst->isLastMicroop())
1387  stats.instsCommitted[tid]++;
1388  stats.opsCommitted[tid]++;
1389 
1390  // To match the old model, don't count nops and instruction
1391  // prefetches towards the total commit count.
1392  if (!inst->isNop() && !inst->isInstPrefetch()) {
1393  cpu->instDone(tid, inst);
1394  }
1395 
1396  //
1397  // Control Instructions
1398  //
1399  if (inst->isControl())
1400  stats.branches[tid]++;
1401 
1402  //
1403  // Memory references
1404  //
1405  if (inst->isMemRef()) {
1406  stats.memRefs[tid]++;
1407 
1408  if (inst->isLoad()) {
1409  stats.loads[tid]++;
1410  }
1411 
1412  if (inst->isAtomic()) {
1413  stats.amos[tid]++;
1414  }
1415  }
1416 
1417  if (inst->isFullMemBarrier()) {
1418  stats.membars[tid]++;
1419  }
1420 
1421  // Integer Instruction
1422  if (inst->isInteger())
1423  stats.integer[tid]++;
1424 
1425  // Floating Point Instruction
1426  if (inst->isFloating())
1427  stats.floating[tid]++;
1428  // Vector Instruction
1429  if (inst->isVector())
1430  stats.vectorInstructions[tid]++;
1431 
1432  // Function Calls
1433  if (inst->isCall())
1434  stats.functionCalls[tid]++;
1435 
1436 }
1437 
1439 // //
1440 // SMT COMMIT POLICY MAINTAINED HERE //
1441 // //
1443 ThreadID
1445 {
1446  if (numThreads > 1) {
1447  switch (commitPolicy) {
1448  case CommitPolicy::RoundRobin:
1449  return roundRobin();
1450 
1451  case CommitPolicy::OldestReady:
1452  return oldestReady();
1453 
1454  default:
1455  return InvalidThreadID;
1456  }
1457  } else {
1458  assert(!activeThreads->empty());
1459  ThreadID tid = activeThreads->front();
1460 
1461  if (commitStatus[tid] == Running ||
1462  commitStatus[tid] == Idle ||
1463  commitStatus[tid] == FetchTrapPending) {
1464  return tid;
1465  } else {
1466  return InvalidThreadID;
1467  }
1468  }
1469 }
1470 
1471 ThreadID
1473 {
1474  std::list<ThreadID>::iterator pri_iter = priority_list.begin();
1476 
1477  while (pri_iter != end) {
1478  ThreadID tid = *pri_iter;
1479 
1480  if (commitStatus[tid] == Running ||
1481  commitStatus[tid] == Idle ||
1482  commitStatus[tid] == FetchTrapPending) {
1483 
1484  if (rob->isHeadReady(tid)) {
1485  priority_list.erase(pri_iter);
1486  priority_list.push_back(tid);
1487 
1488  return tid;
1489  }
1490  }
1491 
1492  pri_iter++;
1493  }
1494 
1495  return InvalidThreadID;
1496 }
1497 
1498 ThreadID
1500 {
1501  unsigned oldest = 0;
1502  unsigned oldest_seq_num = 0;
1503  bool first = true;
1504 
1505  std::list<ThreadID>::iterator threads = activeThreads->begin();
1507 
1508  while (threads != end) {
1509  ThreadID tid = *threads++;
1510 
1511  if (!rob->isEmpty(tid) &&
1512  (commitStatus[tid] == Running ||
1513  commitStatus[tid] == Idle ||
1514  commitStatus[tid] == FetchTrapPending)) {
1515 
1516  if (rob->isHeadReady(tid)) {
1517 
1518  const DynInstPtr &head_inst = rob->readHeadInst(tid);
1519 
1520  if (first) {
1521  oldest = tid;
1522  oldest_seq_num = head_inst->seqNum;
1523  first = false;
1524  } else if (head_inst->seqNum < oldest_seq_num) {
1525  oldest = tid;
1526  oldest_seq_num = head_inst->seqNum;
1527  }
1528  }
1529  }
1530  }
1531 
1532  if (!first) {
1533  return oldest;
1534  } else {
1535  return InvalidThreadID;
1536  }
1537 }
1538 
1539 } // namespace o3
1540 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
Cycles syscallRetryLatency
Definition: base.hh:639
void clearInterrupts(ThreadID tid)
Definition: base.hh:244
ThreadID numThreads
Number of threads we're actually simulating (<= SMT_MAX_THREADS).
Definition: base.hh:367
bool checkInterrupts(ThreadID tid) const
Definition: base.hh:250
void traceFunctions(Addr pc)
Definition: base.hh:584
virtual PCStateBase * newPCState(Addr new_inst_addr=0) const =0
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...
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
virtual std::string name() const
Definition: named.hh:47
ProbePointArg generates a point for the class of Arg.
Definition: probe.hh:264
virtual BaseISA * getIsaPtr() const =0
O3CPU class, has each of the stages (fetch through commit) within it, as well as all of the time buff...
Definition: cpu.hh:94
void instDone(ThreadID tid, const DynInstPtr &inst)
Function to tell the CPU that an instruction has completed.
Definition: cpu.cc:1224
gem5::Checker< DynInstPtr > * checker
Pointer to the checker, which can dynamically verify instruction results at run time.
Definition: cpu.hh:524
std::list< DynInstPtr > instList
List of all the instructions in flight.
Definition: cpu.hh:381
void trap(const Fault &fault, ThreadID tid, const StaticInstPtr &inst)
Traps to handle given fault.
Definition: cpu.cc:791
void commitDrained(ThreadID tid)
Commit has reached a safe point to drain a thread.
Definition: cpu.cc:935
void activityThisCycle()
Records that there was time buffer activity this cycle.
Definition: cpu.hh:485
void processInterrupts(const Fault &interrupt)
Processes any an interrupt fault.
Definition: cpu.cc:775
@ CommitIdx
Definition: cpu.hh:457
void deactivateStage(const StageIdx idx)
Changes a stage's status to inactive within the activity recorder.
Definition: cpu.hh:496
gem5::ThreadContext * tcBase(ThreadID tid)
Returns a pointer to a thread context.
Definition: cpu.hh:512
Fault getInterrupts()
Returns the Fault for any valid interrupt.
Definition: cpu.cc:768
void scheduleThreadExitEvent(ThreadID tid)
If a thread is trying to exit and its corresponding trap event has been completed,...
Definition: cpu.cc:1486
bool isThreadExiting(ThreadID tid) const
Is the thread trying to exit?
Definition: cpu.cc:1480
void activateStage(const StageIdx idx)
Changes a stage's status to active within the activity recorder.
Definition: cpu.hh:489
Commit handles single threaded and SMT commit.
Definition: commit.hh:92
ThreadStatus commitStatus[MaxThreads]
Per-thread status.
Definition: commit.hh:120
TimeBuffer< IEWStruct >::wire fromIEW
Wire to read information from IEW queue.
Definition: commit.hh:332
std::vector< ThreadState * > thread
Vector of all of the threads.
Definition: commit.hh:349
ThreadID oldestReady()
Returns the thread ID to use based on an oldest instruction policy.
Definition: commit.cc:1499
ProbePointArg< DynInstPtr > * ppCommitStall
Definition: commit.hh:126
int htmStops[MaxThreads]
Definition: commit.hh:462
void squashFromSquashAfter(ThreadID tid)
Handles a squash from a squashAfter() request.
Definition: commit.cc:600
void squashAll(ThreadID tid)
Squashes all in flight instructions.
Definition: commit.cc:532
void startupStage()
Initializes stage by sending back the number of free entries.
Definition: commit.cc:313
bool changedROBNumEntries[MaxThreads]
Records if the number of ROB entries has changed this cycle.
Definition: commit.hh:359
bool changedROBEntries()
Returns if any of the threads have the number of ROB entries changed on this cycle.
Definition: commit.cc:475
DynInstPtr squashAfterInst[MaxThreads]
Instruction passed to squashAfter().
Definition: commit.hh:374
bool executingHtmTransaction(ThreadID) const
Is the CPU currently processing a HTM transaction?
Definition: commit.cc:425
CommitStatus _status
Overall commit status.
Definition: commit.hh:116
void setIEWQueue(TimeBuffer< IEWStruct > *iq_ptr)
Sets the pointer to the queue coming from IEW.
Definition: commit.cc:283
size_t numROBFreeEntries(ThreadID tid)
Returns the number of free ROB entries for a specific thread.
Definition: commit.cc:492
void setFetchQueue(TimeBuffer< FetchStruct > *fq_ptr)
Definition: commit.cc:265
ROB * rob
ROB interface.
Definition: commit.hh:342
void processTrapEvent(ThreadID tid)
Mark the thread as processing a trap.
Definition: commit.cc:77
void setRenameQueue(TimeBuffer< RenameStruct > *rq_ptr)
Sets the pointer to the queue coming from rename.
Definition: commit.cc:274
bool checkEmptyROB[MaxThreads]
Records if commit should check if the ROB is truly empty (see commit_impl.hh).
Definition: commit.hh:440
void generateTrapEvent(ThreadID tid, Fault inst_fault)
Generates an event to schedule a squash due to a trap.
Definition: commit.cc:498
void deactivateThread(ThreadID tid)
Deschedules a thread from scheduling.
Definition: commit.cc:414
TimeBuffer< TimeStruct >::wire toIEW
Wire to write information heading to previous stages.
Definition: commit.hh:319
CPU * cpu
Pointer to O3CPU.
Definition: commit.hh:346
void squashFromTC(ThreadID tid)
Handles squashing due to an TC write.
Definition: commit.cc:584
const ThreadID numThreads
Number of Active Threads.
Definition: commit.hh:399
ProbePointArg< DynInstPtr > * ppSquash
To probe when an instruction is squashed.
Definition: commit.hh:128
Commit(CPU *_cpu, const BaseO3CPUParams &params)
Construct a Commit with the given parameters.
Definition: commit.cc:84
bool trapInFlight[MaxThreads]
Records if there is a trap currently in flight.
Definition: commit.hh:433
void handleInterrupt()
Handles processing an interrupt.
Definition: commit.cc:706
const Cycles fetchToCommitDelay
Definition: commit.hh:388
void propagateInterrupt()
Get fetch redirecting so we can handle an interrupt.
Definition: commit.cc:759
std::string name() const
Returns the name of the Commit.
Definition: commit.cc:135
TimeBuffer< FetchStruct > * fetchQueue
Definition: commit.hh:324
void setROB(ROB *rob_ptr)
Sets pointer to the ROB.
Definition: commit.cc:310
int htmStarts[MaxThreads]
Definition: commit.hh:461
CommitPolicy commitPolicy
Commit policy used in SMT mode.
Definition: commit.hh:122
TimeBuffer< TimeStruct >::wire robInfoFromIEW
Wire to read information from IEW (for ROB).
Definition: commit.hh:322
void tick()
Ticks the commit stage, which tries to commit instructions.
Definition: commit.cc:628
void setIEWStage(IEW *iew_stage)
Sets the pointer to the IEW stage.
Definition: commit.cc:292
const unsigned renameWidth
Rename width, in instructions.
Definition: commit.hh:393
bool drainPending
Is a drain pending? Commit is looking for an instruction boundary while there are no pending interrup...
Definition: commit.hh:404
const Cycles trapLatency
The latency to handle a trap.
Definition: commit.hh:416
ProbePointArg< DynInstPtr > * ppCommit
Probe Points.
Definition: commit.hh:125
bool wroteToTimeBuffer
Records that commit has written to the time buffer this cycle.
Definition: commit.hh:354
TimeBuffer< IEWStruct > * iewQueue
IEW instruction queue interface.
Definition: commit.hh:329
void setTimeBuffer(TimeBuffer< TimeStruct > *tb_ptr)
Sets the main time buffer pointer, used for backwards communication.
Definition: commit.cc:253
void setActiveThreads(std::list< ThreadID > *at_ptr)
Sets pointer to list of active threads.
Definition: commit.cc:298
const Cycles renameToROBDelay
Rename to ROB delay.
Definition: commit.hh:386
std::list< ThreadID > * activeThreads
Pointer to the list of active threads.
Definition: commit.hh:443
void updateStatus()
Updates the overall status of commit with the nextStatus, and tell the CPU if commit is active/inacti...
Definition: commit.cc:445
void squashAfter(ThreadID tid, const DynInstPtr &head_inst)
Handle squashing from instruction with SquashAfter set.
Definition: commit.cc:617
bool commitHead(const DynInstPtr &head_inst, unsigned inst_num)
Tries to commit the head ROB instruction passed in.
Definition: commit.cc:1143
void resetHtmStartsStops(ThreadID)
Definition: commit.cc:434
void getInsts()
Gets instructions from rename and inserts them into the ROB.
Definition: commit.cc:1329
bool tcSquash[MaxThreads]
Records if a thread has to squash this cycle due to an XC write.
Definition: commit.hh:365
void drainSanityCheck() const
Perform sanity checks after a drain.
Definition: commit.cc:357
void takeOverFrom()
Takes over from another CPU's thread.
Definition: commit.cc:399
void clearStates(ThreadID tid)
Clear all thread-specific states.
Definition: commit.cc:333
void drainResume()
Resumes execution after draining.
Definition: commit.cc:350
TimeBuffer< RenameStruct > * renameQueue
Rename instruction queue interface, for ROB.
Definition: commit.hh:335
void drain()
Initializes the draining of commit.
Definition: commit.cc:347
bool trapSquash[MaxThreads]
Records if a thread has to squash this cycle due to a trap.
Definition: commit.hh:362
InstSeqNum youngestSeqNum[MaxThreads]
The sequence number of the youngest valid instruction in the ROB.
Definition: commit.hh:427
InstSeqNum lastCommitedSeqNum[MaxThreads]
The sequence number of the last commited instruction.
Definition: commit.hh:430
CommitStatus _nextStatus
Next commit status, to be set at the end of the cycle.
Definition: commit.hh:118
bool drainImminent
Is a drain imminent? Commit has found an instruction boundary while no interrupts were present or in ...
Definition: commit.hh:411
void commitInsts()
Commits as many instructions as possible.
Definition: commit.cc:944
void markCompletedInsts()
Marks completed instructions using information sent from IEW.
Definition: commit.cc:1362
void setRenameMap(UnifiedRenameMap rm_ptr[MaxThreads])
Sets pointer to the commited state rename map.
Definition: commit.cc:304
bool canHandleInterrupts
True if last committed microop can be followed by an interrupt.
Definition: commit.hh:449
TimeBuffer< TimeStruct > * timeBuffer
Time buffer interface.
Definition: commit.hh:316
TimeBuffer< RenameStruct >::wire fromRename
Wire to read information from rename queue.
Definition: commit.hh:338
ThreadID roundRobin()
Returns the thread ID to use based on a round robin policy.
Definition: commit.cc:1472
void generateTCEvent(ThreadID tid)
Records that commit needs to initiate a squash due to an external state update through the TC.
Definition: commit.cc:523
std::unique_ptr< PCStateBase > pc[MaxThreads]
The commit PC state of each thread.
Definition: commit.hh:424
void regProbePoints()
Registers probes.
Definition: commit.cc:138
IEW * iewStage
The pointer to the IEW stage.
Definition: commit.hh:164
void setThreads(std::vector< ThreadState * > &threads)
Sets the list of threads.
Definition: commit.cc:247
void updateComInstStats(const DynInstPtr &inst)
Updates commit stats based on this instruction.
Definition: commit.cc:1382
ThreadID getCommittingThread()
Gets the thread to commit, based on the SMT policy.
Definition: commit.cc:1444
const Cycles iewToCommitDelay
IEW to Commit delay.
Definition: commit.hh:380
bool avoidQuiesceLiveLock
Have we had an interrupt pending and then seen it de-asserted because of a masking change?...
Definition: commit.hh:455
std::list< ThreadID > priority_list
Priority List used for Commit Policy.
Definition: commit.hh:377
void commit()
Handles any squashes that are sent from IEW, and adds instructions to the ROB and tries to commit ins...
Definition: commit.cc:783
UnifiedRenameMap * renameMap[MaxThreads]
Rename map interface.
Definition: commit.hh:446
void squashFromTrap(ThreadID tid)
Handles squashing due to a trap.
Definition: commit.cc:567
bool committedStores[MaxThreads]
Records if there were any stores committed this cycle.
Definition: commit.hh:436
const unsigned commitWidth
Commit width, in instructions.
Definition: commit.hh:396
bool isDrained() const
Has the stage drained?
Definition: commit.cc:372
Fault interrupt
The interrupt fault.
Definition: commit.hh:419
TimeBuffer< FetchStruct >::wire fromFetch
Definition: commit.hh:326
IEW handles both single threaded and SMT IEW (issue/execute/writeback).
Definition: iew.hh:88
void setLastRetiredHtmUid(ThreadID tid, uint64_t htmUid)
Definition: iew.hh:234
bool hasStoresToWB()
Returns if the LSQ has any stores to writeback.
Definition: iew.hh:221
ROB class.
Definition: rob.hh:72
int countInsts()
This is more of a debugging function than anything.
Definition: rob.cc:180
void insertInst(const DynInstPtr &inst)
Function to insert an instruction into the ROB.
Definition: rob.cc:197
unsigned getMaxEntries(ThreadID tid)
Returns the maximum number of entries for a specific thread.
Definition: rob.hh:178
unsigned numFreeEntries()
Returns the number of total free entries in the ROB.
Definition: rob.cc:297
void resetEntries()
Re-adjust ROB partitioning.
Definition: rob.cc:148
void squash(InstSeqNum squash_num, ThreadID tid)
Squashes all instructions younger than the given sequence number for the specific thread.
Definition: rob.cc:473
bool isHeadReady(ThreadID tid)
Is the oldest instruction across all threads ready.
Definition: rob.cc:268
void retireHead(ThreadID tid)
Retires the head instruction, removing it from the ROB.
Definition: rob.cc:234
DynInstPtr findInst(ThreadID tid, InstSeqNum squash_inst)
Returns a pointer to the instruction with the given sequence if it is in the ROB.
Definition: rob.cc:534
void drainSanityCheck() const
Perform sanity checks after a drain.
Definition: rob.cc:134
void doSquash(ThreadID tid)
Executes the squash, marking squashed instructions.
Definition: rob.cc:309
const DynInstPtr & readHeadInst(ThreadID tid)
Returns pointer to the head instruction within the ROB.
Definition: rob.cc:502
unsigned getThreadEntries(ThreadID tid)
Returns the number of entries being used by a specific thread.
Definition: rob.hh:182
void setActiveThreads(std::list< ThreadID > *at_ptr)
Sets pointer to the list of active threads.
Definition: rob.cc:127
bool isEmpty() const
Returns if the ROB is empty.
Definition: rob.hh:194
void takeOverFrom()
Takes over another CPU's thread.
Definition: rob.cc:142
bool isDoneSquashing(ThreadID tid) const
Reads the PC of the oldest head instruction.
Definition: rob.hh:249
Unified register rename map for all classes of registers.
Definition: rename_map.hh:169
void setEntry(const RegId &arch_reg, PhysRegIdPtr phys_reg)
Update rename map with a specific mapping.
Definition: rename_map.hh:247
Derived & ysubnames(const char **names)
Definition: statistics.hh:478
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
Definition: statistics.hh:358
Derived & prereq(const Stat &prereq)
Set the prerequisite stat and marks this stat to print at the end of simulation.
Definition: statistics.hh:372
Distribution & init(Counter min, Counter max, Counter bkt)
Set the parameters of this distribution.
Definition: statistics.hh:2113
Statistics container.
Definition: group.hh:94
std::vector< Info * > stats
Definition: group.hh:221
Derived & init(size_type _x, size_type _y)
Definition: statistics.hh:1174
Derived & init(size_type size)
Set this vector to have the given size.
Definition: statistics.hh:1040
STL vector class.
Definition: stl.hh:37
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
void schedule(Event &event, Tick when)
Definition: eventq.hh:1019
static const Priority CPU_Tick_Pri
CPU ticks must come after other associated CPU events (such as writebacks).
Definition: eventq.hh:204
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
ProbeManager * getProbeManager()
Get the probe manager for this object.
Definition: sim_object.cc:120
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 12, 11 > set
Definition: misc_types.hh:709
static constexpr int MaxThreads
Definition: limits.hh:38
static constexpr int MaxWidth
Definition: limits.hh:37
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition: info.hh:62
const FlagsType total
Print the total.
Definition: info.hh:60
const FlagsType dist
Print the distribution.
Definition: info.hh:66
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
std::shared_ptr< FaultBase > Fault
Definition: types.hh:248
int16_t ThreadID
Thread index/ID type.
Definition: types.hh:235
const ThreadID InvalidThreadID
Definition: types.hh:236
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
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
Definition: root.cc:220
const StaticInstPtr nullStaticInstPtr
Statically allocated null StaticInstPtr.
constexpr decltype(nullptr) NoFault
Definition: types.hh:253
uint64_t InstSeqNum
Definition: inst_seq.hh:40
statistics::Vector amos
Stat for the total number of committed atomics.
Definition: commit.hh:491
statistics::Vector instsCommitted
Total number of instructions committed.
Definition: commit.hh:483
CommitStats(CPU *cpu, Commit *commit)
Definition: commit.cc:148
statistics::Distribution numCommittedDist
Distribution of the number of committed instructions each cycle.
Definition: commit.hh:480
statistics::Scalar commitNonSpecStalls
Stat for the total number of times commit has had to stall due to a non-speculative instruction reach...
Definition: commit.hh:474
statistics::Scalar commitSquashedInsts
Stat for the total number of squashed instructions discarded by commit.
Definition: commit.hh:470
statistics::Scalar branchMispredicts
Stat for the total number of branch mispredicts that caused a squash.
Definition: commit.hh:478
statistics::Vector2d committedInstType
Committed instructions by instruction type (OpClass)
Definition: commit.hh:505
statistics::Vector integer
Total number of integer instructions.
Definition: commit.hh:501
statistics::Vector vectorInstructions
Total number of vector instructions.
Definition: commit.hh:497
statistics::Vector branches
Total number of committed branches.
Definition: commit.hh:495
statistics::Vector memRefs
Stat for the total number of committed memory references.
Definition: commit.hh:487
statistics::Vector floating
Total number of floating point instructions.
Definition: commit.hh:499
statistics::Vector loads
Stat for the total number of committed loads.
Definition: commit.hh:489
statistics::Vector functionCalls
Total number of function calls.
Definition: commit.hh:503
statistics::Vector opsCommitted
Total number of ops (including micro ops) committed.
Definition: commit.hh:485
statistics::Vector membars
Total number of committed memory barriers.
Definition: commit.hh:493

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