gem5  v22.1.0.0
execute.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2014,2018-2020 ARM Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are
16  * met: redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer;
18  * redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution;
21  * neither the name of the copyright holders nor the names of its
22  * contributors may be used to endorse or promote products derived from
23  * this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include "cpu/minor/execute.hh"
39 
40 #include <functional>
41 
42 #include "cpu/minor/cpu.hh"
44 #include "cpu/minor/fetch1.hh"
45 #include "cpu/minor/lsq.hh"
46 #include "cpu/op_class.hh"
47 #include "debug/Activity.hh"
48 #include "debug/Branch.hh"
49 #include "debug/Drain.hh"
50 #include "debug/ExecFaulting.hh"
51 #include "debug/MinorExecute.hh"
52 #include "debug/MinorInterrupt.hh"
53 #include "debug/MinorMem.hh"
54 #include "debug/MinorTrace.hh"
55 #include "debug/PCEvent.hh"
56 
57 namespace gem5
58 {
59 
61 namespace minor
62 {
63 
64 Execute::Execute(const std::string &name_,
65  MinorCPU &cpu_,
66  const BaseMinorCPUParams &params,
69  Named(name_),
70  inp(inp_),
71  out(out_),
72  cpu(cpu_),
73  issueLimit(params.executeIssueLimit),
74  memoryIssueLimit(params.executeMemoryIssueLimit),
75  commitLimit(params.executeCommitLimit),
76  memoryCommitLimit(params.executeMemoryCommitLimit),
77  processMoreThanOneInput(params.executeCycleInput),
78  fuDescriptions(*params.executeFuncUnits),
79  numFuncUnits(fuDescriptions.funcUnits.size()),
80  setTraceTimeOnCommit(params.executeSetTraceTimeOnCommit),
81  setTraceTimeOnIssue(params.executeSetTraceTimeOnIssue),
82  allowEarlyMemIssue(params.executeAllowEarlyMemoryIssue),
83  noCostFUIndex(fuDescriptions.funcUnits.size() + 1),
84  lsq(name_ + ".lsq", name_ + ".dcache_port",
85  cpu_, *this,
86  params.executeMaxAccessesInMemory,
87  params.executeMemoryWidth,
88  params.executeLSQRequestsQueueSize,
89  params.executeLSQTransfersQueueSize,
90  params.executeLSQStoreBufferSize,
91  params.executeLSQMaxStoreBufferStoresPerCycle),
92  executeInfo(params.numThreads,
93  ExecuteThreadInfo(params.executeCommitLimit)),
94  interruptPriority(0),
95  issuePriority(0),
96  commitPriority(0)
97 {
98  if (commitLimit < 1) {
99  fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_,
100  commitLimit);
101  }
102 
103  if (issueLimit < 1) {
104  fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_,
105  issueLimit);
106  }
107 
108  if (memoryIssueLimit < 1) {
109  fatal("%s: executeMemoryIssueLimit must be >= 1 (%d)\n", name_,
111  }
112 
114  fatal("%s: executeMemoryCommitLimit (%d) must be <="
115  " executeCommitLimit (%d)\n",
117  }
118 
119  if (params.executeInputBufferSize < 1) {
120  fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_,
121  params.executeInputBufferSize);
122  }
123 
124  if (params.executeInputBufferSize < 1) {
125  fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_,
126  params.executeInputBufferSize);
127  }
128 
129  /* This should be large enough to count all the in-FU instructions
130  * which need to be accounted for in the inFlightInsts
131  * queue */
132  unsigned int total_slots = 0;
133 
134  /* Make FUPipelines for each MinorFU */
135  for (unsigned int i = 0; i < numFuncUnits; i++) {
136  std::ostringstream fu_name;
137  MinorFU *fu_description = fuDescriptions.funcUnits[i];
138 
139  /* Note the total number of instruction slots (for sizing
140  * the inFlightInst queue) and the maximum latency of any FU
141  * (for sizing the activity recorder) */
142  total_slots += fu_description->opLat;
143 
144  fu_name << name_ << ".fu." << i;
145 
146  FUPipeline *fu = new FUPipeline(fu_name.str(), *fu_description, cpu);
147 
148  funcUnits.push_back(fu);
149  }
150 
152  for (int op_class = No_OpClass + 1; op_class < Num_OpClasses; op_class++) {
153  bool found_fu = false;
154  unsigned int fu_index = 0;
155 
156  while (fu_index < numFuncUnits && !found_fu)
157  {
158  if (funcUnits[fu_index]->provides(
159  static_cast<OpClass>(op_class)))
160  {
161  found_fu = true;
162  }
163  fu_index++;
164  }
165 
166  if (!found_fu) {
167  warn("No functional unit for OpClass %s\n",
168  enums::OpClassStrings[op_class]);
169  }
170  }
171 
172  /* Per-thread structures */
173  for (ThreadID tid = 0; tid < params.numThreads; tid++) {
174  std::string tid_str = std::to_string(tid);
175 
176  /* Input Buffers */
177  inputBuffer.push_back(
179  name_ + ".inputBuffer" + tid_str, "insts",
180  params.executeInputBufferSize));
181 
182  const auto &regClasses = cpu.threads[tid]->getIsaPtr()->regClasses();
183 
184  /* Scoreboards */
185  scoreboard.emplace_back(name_ + ".scoreboard" + tid_str, regClasses);
186 
187  /* In-flight instruction records */
188  executeInfo[tid].inFlightInsts = new Queue<QueuedInst,
190  name_ + ".inFlightInsts" + tid_str, "insts", total_slots);
191 
192  executeInfo[tid].inFUMemInsts = new Queue<QueuedInst,
194  name_ + ".inFUMemInsts" + tid_str, "insts", total_slots);
195  }
196 }
197 
198 const ForwardInstData *
200 {
201  /* Get a line from the inputBuffer to work with */
202  if (!inputBuffer[tid].empty()) {
203  const ForwardInstData &head = inputBuffer[tid].front();
204 
205  return (head.isBubble() ? NULL : &(inputBuffer[tid].front()));
206  } else {
207  return NULL;
208  }
209 }
210 
211 void
213 {
214  if (!inputBuffer[tid].empty())
215  inputBuffer[tid].pop();
216 
217  executeInfo[tid].inputIndex = 0;
218 }
219 
220 void
222 {
223  ThreadContext *thread = cpu.getContext(inst->id.threadId);
224  const std::unique_ptr<PCStateBase> pc_before(inst->pc->clone());
225  std::unique_ptr<PCStateBase> target(thread->pcState().clone());
226 
227  /* Force a branch for SerializeAfter/SquashAfter instructions
228  * at the end of micro-op sequence when we're not suspended */
229  bool force_branch = thread->status() != ThreadContext::Suspended &&
230  !inst->isFault() &&
231  inst->isLastOpInInst() &&
232  (inst->staticInst->isSerializeAfter() ||
233  inst->staticInst->isSquashAfter());
234 
235  DPRINTF(Branch, "tryToBranch before: %s after: %s%s\n",
236  *pc_before, *target, (force_branch ? " (forcing)" : ""));
237 
238  /* Will we change the PC to something other than the next instruction? */
239  bool must_branch = *pc_before != *target ||
240  fault != NoFault ||
241  force_branch;
242 
243  /* The reason for the branch data we're about to generate, set below */
245 
246  if (fault == NoFault) {
247  inst->staticInst->advancePC(*target);
248  thread->pcState(*target);
249 
250  DPRINTF(Branch, "Advancing current PC from: %s to: %s\n",
251  *pc_before, *target);
252  }
253 
254  if (inst->predictedTaken && !force_branch) {
255  /* Predicted to branch */
256  if (!must_branch) {
257  /* No branch was taken, change stream to get us back to the
258  * intended PC value */
259  DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x but"
260  " none happened inst: %s\n",
261  inst->pc->instAddr(), inst->predictedTarget->instAddr(),
262  *inst);
263 
265  } else if (*inst->predictedTarget == *target) {
266  /* Branch prediction got the right target, kill the branch and
267  * carry on.
268  * Note that this information to the branch predictor might get
269  * overwritten by a "real" branch during this cycle */
270  DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x correctly"
271  " inst: %s\n",
272  inst->pc->instAddr(), inst->predictedTarget->instAddr(),
273  *inst);
274 
276  } else {
277  /* Branch prediction got the wrong target */
278  DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x"
279  " but got the wrong target (actual: 0x%x) inst: %s\n",
280  inst->pc->instAddr(), inst->predictedTarget->instAddr(),
281  target->instAddr(), *inst);
282 
284  }
285  } else if (must_branch) {
286  /* Unpredicted branch */
287  DPRINTF(Branch, "Unpredicted branch from 0x%x to 0x%x inst: %s\n",
288  inst->pc->instAddr(), target->instAddr(), *inst);
289 
291  } else {
292  /* No branch at all */
293  reason = BranchData::NoBranch;
294  }
295 
296  updateBranchData(inst->id.threadId, reason, inst, *target, branch);
297 }
298 
299 void
301  ThreadID tid,
302  BranchData::Reason reason,
303  MinorDynInstPtr inst, const PCStateBase &target,
304  BranchData &branch)
305 {
306  if (reason != BranchData::NoBranch) {
307  /* Bump up the stream sequence number on a real branch*/
308  if (BranchData::isStreamChange(reason))
309  executeInfo[tid].streamSeqNum++;
310 
311  /* Branches (even mis-predictions) don't change the predictionSeqNum,
312  * just the streamSeqNum */
313  branch = BranchData(reason, tid,
314  executeInfo[tid].streamSeqNum,
315  /* Maintaining predictionSeqNum if there's no inst is just a
316  * courtesy and looks better on minorview */
317  (inst->isBubble() ? executeInfo[tid].lastPredictionSeqNum
318  : inst->id.predictionSeqNum),
319  target, inst);
320 
321  DPRINTF(Branch, "Branch data signalled: %s\n", branch);
322  }
323 }
324 
325 void
327  LSQ::LSQRequestPtr response, BranchData &branch, Fault &fault)
328 {
329  ThreadID thread_id = inst->id.threadId;
330  ThreadContext *thread = cpu.getContext(thread_id);
331 
332  ExecContext context(cpu, *cpu.threads[thread_id], *this, inst);
333 
334  PacketPtr packet = response->packet;
335 
336  bool is_load = inst->staticInst->isLoad();
337  bool is_store = inst->staticInst->isStore();
338  bool is_atomic = inst->staticInst->isAtomic();
339  bool is_prefetch = inst->staticInst->isDataPrefetch();
340 
341  /* If true, the trace's predicate value will be taken from the exec
342  * context predicate, otherwise, it will be set to false */
343  bool use_context_predicate = true;
344 
345  if (inst->translationFault != NoFault) {
346  /* Invoke memory faults. */
347  DPRINTF(MinorMem, "Completing fault from DTLB access: %s\n",
348  inst->translationFault->name());
349 
350  if (inst->staticInst->isPrefetch()) {
351  DPRINTF(MinorMem, "Not taking fault on prefetch: %s\n",
352  inst->translationFault->name());
353 
354  /* Don't assign to fault */
355  } else {
356  /* Take the fault raised during the TLB/memory access */
357  fault = inst->translationFault;
358 
359  fault->invoke(thread, inst->staticInst);
360  }
361  } else if (!packet) {
362  DPRINTF(MinorMem, "Completing failed request inst: %s\n",
363  *inst);
364  use_context_predicate = false;
365  if (!context.readMemAccPredicate())
366  inst->staticInst->completeAcc(nullptr, &context, inst->traceData);
367  } else if (packet->isError()) {
368  DPRINTF(MinorMem, "Trying to commit error response: %s\n",
369  *inst);
370 
371  fatal("Received error response packet for inst: %s\n", *inst);
372  } else if (is_store || is_load || is_prefetch || is_atomic) {
373  assert(packet);
374 
375  DPRINTF(MinorMem, "Memory response inst: %s addr: 0x%x size: %d\n",
376  *inst, packet->getAddr(), packet->getSize());
377 
378  if (is_load && packet->getSize() > 0) {
379  DPRINTF(MinorMem, "Memory data[0]: 0x%x\n",
380  static_cast<unsigned int>(packet->getConstPtr<uint8_t>()[0]));
381  }
382 
383  /* Complete the memory access instruction */
384  fault = inst->staticInst->completeAcc(packet, &context,
385  inst->traceData);
386 
387  if (fault != NoFault) {
388  /* Invoke fault created by instruction completion */
389  DPRINTF(MinorMem, "Fault in memory completeAcc: %s\n",
390  fault->name());
391  fault->invoke(thread, inst->staticInst);
392  } else {
393  /* Stores need to be pushed into the store buffer to finish
394  * them off */
395  if (response->needsToBeSentToStoreBuffer())
396  lsq.sendStoreToStoreBuffer(response);
397  }
398  } else {
399  fatal("There should only ever be reads, "
400  "writes or faults at this point\n");
401  }
402 
403  lsq.popResponse(response);
404 
405  if (inst->traceData) {
406  inst->traceData->setPredicate((use_context_predicate ?
407  context.readPredicate() : false));
408  }
409 
411 
412  /* Generate output to account for branches */
413  tryToBranch(inst, fault, branch);
414 }
415 
416 bool
418 {
419  return cpu.checkInterrupts(thread_id);
420 }
421 
422 bool
424 {
425  DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n",
426  cpu.getContext(thread_id)->pcState());
427 
428  Fault interrupt = cpu.getInterruptController(thread_id)->getInterrupt();
429 
430  if (interrupt != NoFault) {
431  /* The interrupt *must* set pcState */
433  interrupt->invoke(cpu.getContext(thread_id));
434 
435  assert(!lsq.accessesInFlight());
436 
437  DPRINTF(MinorInterrupt, "Invoking interrupt: %s to PC: %s\n",
438  interrupt->name(), cpu.getContext(thread_id)->pcState());
439 
440  /* Assume that an interrupt *must* cause a branch. Assert this? */
441 
443  MinorDynInst::bubble(), cpu.getContext(thread_id)->pcState(),
444  branch);
445  }
446 
447  return interrupt != NoFault;
448 }
449 
450 bool
452  bool &passed_predicate, Fault &fault)
453 {
454  bool issued = false;
455 
456  /* Set to true if the mem op. is issued and sent to the mem system */
457  passed_predicate = false;
458 
459  if (!lsq.canRequest()) {
460  /* Not acting on instruction yet as the memory
461  * queues are full */
462  issued = false;
463  } else {
464  ThreadContext *thread = cpu.getContext(inst->id.threadId);
465  std::unique_ptr<PCStateBase> old_pc(thread->pcState().clone());
466 
467  ExecContext context(cpu, *cpu.threads[inst->id.threadId], *this, inst);
468 
469  DPRINTF(MinorExecute, "Initiating memRef inst: %s\n", *inst);
470 
471  Fault init_fault = inst->staticInst->initiateAcc(&context,
472  inst->traceData);
473 
474  if (inst->inLSQ) {
475  if (init_fault != NoFault) {
476  assert(inst->translationFault != NoFault);
477  // Translation faults are dealt with in handleMemResponse()
478  init_fault = NoFault;
479  } else {
480  // If we have a translation fault then it got suppressed by
481  // initateAcc()
482  inst->translationFault = NoFault;
483  }
484  }
485 
486  if (init_fault != NoFault) {
487  DPRINTF(MinorExecute, "Fault on memory inst: %s"
488  " initiateAcc: %s\n", *inst, init_fault->name());
489  fault = init_fault;
490  } else {
491  /* Only set this if the instruction passed its
492  * predicate */
493  if (!context.readMemAccPredicate()) {
494  DPRINTF(MinorMem, "No memory access for inst: %s\n", *inst);
495  assert(context.readPredicate());
496  }
497  passed_predicate = context.readPredicate();
498 
499  /* Set predicate in tracing */
500  if (inst->traceData)
501  inst->traceData->setPredicate(passed_predicate);
502 
503  /* If the instruction didn't pass its predicate
504  * or it is a predicated vector instruction and the
505  * associated predicate register is all-false (and so will not
506  * progress from here) Try to branch to correct and branch
507  * mis-prediction. */
508  if (!inst->inLSQ) {
509  /* Leave it up to commit to handle the fault */
510  lsq.pushFailedRequest(inst);
511  inst->inLSQ = true;
512  }
513  }
514 
515  /* Restore thread PC */
516  thread->pcState(*old_pc);
517  issued = true;
518  }
519 
520  return issued;
521 }
522 
524 inline unsigned int
525 cyclicIndexInc(unsigned int index, unsigned int cycle_size)
526 {
527  unsigned int ret = index + 1;
528 
529  if (ret == cycle_size)
530  ret = 0;
531 
532  return ret;
533 }
534 
536 inline unsigned int
537 cyclicIndexDec(unsigned int index, unsigned int cycle_size)
538 {
539  int ret = index - 1;
540 
541  if (ret < 0)
542  ret = cycle_size - 1;
543 
544  return ret;
545 }
546 
547 unsigned int
549 {
550  const ForwardInstData *insts_in = getInput(thread_id);
551  ExecuteThreadInfo &thread = executeInfo[thread_id];
552 
553  /* Early termination if we have no instructions */
554  if (!insts_in)
555  return 0;
556 
557  /* Start from the first FU */
558  unsigned int fu_index = 0;
559 
560  /* Remains true while instructions are still being issued. If any
561  * instruction fails to issue, this is set to false and we exit issue.
562  * This strictly enforces in-order issue. For other issue behaviours,
563  * a more complicated test in the outer while loop below is needed. */
564  bool issued = true;
565 
566  /* Number of insts issues this cycle to check for issueLimit */
567  unsigned num_insts_issued = 0;
568 
569  /* Number of memory ops issues this cycle to check for memoryIssueLimit */
570  unsigned num_mem_insts_issued = 0;
571 
572  /* Number of instructions discarded this cycle in order to enforce a
573  * discardLimit. @todo, add that parameter? */
574  unsigned num_insts_discarded = 0;
575 
576  do {
577  MinorDynInstPtr inst = insts_in->insts[thread.inputIndex];
578  Fault fault = inst->fault;
579  bool discarded = false;
580  bool issued_mem_ref = false;
581 
582  if (inst->isBubble()) {
583  /* Skip */
584  issued = true;
585  } else if (cpu.getContext(thread_id)->status() ==
587  {
588  DPRINTF(MinorExecute, "Discarding inst: %s from suspended"
589  " thread\n", *inst);
590 
591  issued = true;
592  discarded = true;
593  } else if (inst->id.streamSeqNum != thread.streamSeqNum) {
594  DPRINTF(MinorExecute, "Discarding inst: %s as its stream"
595  " state was unexpected, expected: %d\n",
596  *inst, thread.streamSeqNum);
597  issued = true;
598  discarded = true;
599  } else {
600  /* Try and issue an instruction into an FU, assume we didn't and
601  * fix that in the loop */
602  issued = false;
603 
604  /* Try FU from 0 each instruction */
605  fu_index = 0;
606 
607  /* Try and issue a single instruction stepping through the
608  * available FUs */
609  do {
610  FUPipeline *fu = funcUnits[fu_index];
611 
612  DPRINTF(MinorExecute, "Trying to issue inst: %s to FU: %d\n",
613  *inst, fu_index);
614 
615  /* Does the examined fu have the OpClass-related capability
616  * needed to execute this instruction? Faults can always
617  * issue to any FU but probably should just 'live' in the
618  * inFlightInsts queue rather than having an FU. */
619  bool fu_is_capable = (!inst->isFault() ?
620  fu->provides(inst->staticInst->opClass()) : true);
621 
622  if (inst->isNoCostInst()) {
623  /* Issue free insts. to a fake numbered FU */
624  fu_index = noCostFUIndex;
625 
626  /* And start the countdown on activity to allow
627  * this instruction to get to the end of its FU */
629 
630  /* Mark the destinations for this instruction as
631  * busy */
632  scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() +
633  Cycles(0), cpu.getContext(thread_id), false);
634 
635  DPRINTF(MinorExecute, "Issuing %s to %d\n", inst->id, noCostFUIndex);
636  inst->fuIndex = noCostFUIndex;
637  inst->extraCommitDelay = Cycles(0);
638  inst->extraCommitDelayExpr = NULL;
639 
640  /* Push the instruction onto the inFlight queue so
641  * it can be committed in order */
642  QueuedInst fu_inst(inst);
643  thread.inFlightInsts->push(fu_inst);
644 
645  issued = true;
646 
647  } else if (!fu_is_capable || fu->alreadyPushed()) {
648  /* Skip */
649  if (!fu_is_capable) {
650  DPRINTF(MinorExecute, "Can't issue as FU: %d isn't"
651  " capable\n", fu_index);
652  } else {
653  DPRINTF(MinorExecute, "Can't issue as FU: %d is"
654  " already busy\n", fu_index);
655  }
656  } else if (fu->stalled) {
657  DPRINTF(MinorExecute, "Can't issue inst: %s into FU: %d,"
658  " it's stalled\n",
659  *inst, fu_index);
660  } else if (!fu->canInsert()) {
661  DPRINTF(MinorExecute, "Can't issue inst: %s to busy FU"
662  " for another: %d cycles\n",
663  *inst, fu->cyclesBeforeInsert());
664  } else {
665  MinorFUTiming *timing = (!inst->isFault() ?
666  fu->findTiming(inst->staticInst) : NULL);
667 
668  const std::vector<Cycles> *src_latencies =
669  (timing ? &(timing->srcRegsRelativeLats)
670  : NULL);
671 
672  const std::vector<bool> *cant_forward_from_fu_indices =
673  &(fu->cantForwardFromFUIndices);
674 
675  if (timing && timing->suppress) {
676  DPRINTF(MinorExecute, "Can't issue inst: %s as extra"
677  " decoding is suppressing it\n",
678  *inst);
679  } else if (!scoreboard[thread_id].canInstIssue(inst,
680  src_latencies, cant_forward_from_fu_indices,
681  cpu.curCycle(), cpu.getContext(thread_id)))
682  {
683  DPRINTF(MinorExecute, "Can't issue inst: %s yet\n",
684  *inst);
685  } else {
686  /* Can insert the instruction into this FU */
687  DPRINTF(MinorExecute, "Issuing inst: %s"
688  " into FU %d\n", *inst,
689  fu_index);
690 
691  Cycles extra_dest_retire_lat = Cycles(0);
692  TimingExpr *extra_dest_retire_lat_expr = NULL;
693  Cycles extra_assumed_lat = Cycles(0);
694 
695  /* Add the extraCommitDelay and extraAssumeLat to
696  * the FU pipeline timings */
697  if (timing) {
698  extra_dest_retire_lat =
699  timing->extraCommitLat;
700  extra_dest_retire_lat_expr =
701  timing->extraCommitLatExpr;
702  extra_assumed_lat =
703  timing->extraAssumedLat;
704  }
705 
706  issued_mem_ref = inst->isMemRef();
707 
708  QueuedInst fu_inst(inst);
709 
710  /* Decorate the inst with FU details */
711  inst->fuIndex = fu_index;
712  inst->extraCommitDelay = extra_dest_retire_lat;
713  inst->extraCommitDelayExpr =
714  extra_dest_retire_lat_expr;
715 
716  if (issued_mem_ref) {
717  /* Remember which instruction this memory op
718  * depends on so that initiateAcc can be called
719  * early */
720  if (allowEarlyMemIssue) {
721  inst->instToWaitFor =
722  scoreboard[thread_id].execSeqNumToWaitFor(inst,
723  cpu.getContext(thread_id));
724 
725  if (lsq.getLastMemBarrier(thread_id) >
726  inst->instToWaitFor)
727  {
728  DPRINTF(MinorExecute, "A barrier will"
729  " cause a delay in mem ref issue of"
730  " inst: %s until after inst"
731  " %d(exec)\n", *inst,
732  lsq.getLastMemBarrier(thread_id));
733 
734  inst->instToWaitFor =
735  lsq.getLastMemBarrier(thread_id);
736  } else {
737  DPRINTF(MinorExecute, "Memory ref inst:"
738  " %s must wait for inst %d(exec)"
739  " before issuing\n",
740  *inst, inst->instToWaitFor);
741  }
742 
743  inst->canEarlyIssue = true;
744  }
745  /* Also queue this instruction in the memory ref
746  * queue to ensure in-order issue to the LSQ */
747  DPRINTF(MinorExecute, "Pushing mem inst: %s\n",
748  *inst);
749  thread.inFUMemInsts->push(fu_inst);
750  }
751 
752  /* Issue to FU */
753  fu->push(fu_inst);
754  /* And start the countdown on activity to allow
755  * this instruction to get to the end of its FU */
757 
758  /* Mark the destinations for this instruction as
759  * busy */
760  scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() +
761  fu->description.opLat +
762  extra_dest_retire_lat +
763  extra_assumed_lat,
764  cpu.getContext(thread_id),
765  issued_mem_ref && extra_assumed_lat == Cycles(0));
766 
767  /* Push the instruction onto the inFlight queue so
768  * it can be committed in order */
769  thread.inFlightInsts->push(fu_inst);
770 
771  issued = true;
772  }
773  }
774 
775  fu_index++;
776  } while (fu_index != numFuncUnits && !issued);
777 
778  if (!issued)
779  DPRINTF(MinorExecute, "Didn't issue inst: %s\n", *inst);
780  }
781 
782  if (issued) {
783  /* Generate MinorTrace's MinorInst lines. Do this at commit
784  * to allow better instruction annotation? */
785  if (debug::MinorTrace && !inst->isBubble()) {
786  inst->minorTraceInst(*this);
787  }
788 
789  /* Mark up barriers in the LSQ */
790  if (!discarded && inst->isInst() &&
791  inst->staticInst->isFullMemBarrier())
792  {
793  DPRINTF(MinorMem, "Issuing memory barrier inst: %s\n", *inst);
795  }
796 
797  if (inst->traceData && setTraceTimeOnIssue) {
798  inst->traceData->setWhen(curTick());
799  }
800 
801  if (issued_mem_ref)
802  num_mem_insts_issued++;
803 
804  if (discarded) {
805  num_insts_discarded++;
806  } else if (!inst->isBubble()) {
807  num_insts_issued++;
808 
809  if (num_insts_issued == issueLimit)
810  DPRINTF(MinorExecute, "Reached inst issue limit\n");
811  }
812 
813  thread.inputIndex++;
814  DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n",
815  thread.inputIndex);
816  }
817 
818  /* Got to the end of a line */
819  if (thread.inputIndex == insts_in->width()) {
820  popInput(thread_id);
821  /* Set insts_in to null to force us to leave the surrounding
822  * loop */
823  insts_in = NULL;
824 
826  DPRINTF(MinorExecute, "Wrapping\n");
827  insts_in = getInput(thread_id);
828  }
829  }
830  } while (insts_in && thread.inputIndex < insts_in->width() &&
831  /* We still have instructions */
832  fu_index != numFuncUnits && /* Not visited all FUs */
833  issued && /* We've not yet failed to issue an instruction */
834  num_insts_issued != issueLimit && /* Still allowed to issue */
835  num_mem_insts_issued != memoryIssueLimit);
836 
837  return num_insts_issued;
838 }
839 
840 bool
842 {
843  ThreadContext *thread = cpu.getContext(thread_id);
844  unsigned int num_pc_event_checks = 0;
845 
846  /* Handle PC events on instructions */
847  Addr oldPC;
848  do {
849  oldPC = thread->pcState().instAddr();
850  cpu.threads[thread_id]->pcEventQueue.service(oldPC, thread);
851  num_pc_event_checks++;
852  } while (oldPC != thread->pcState().instAddr());
853 
854  if (num_pc_event_checks > 1) {
855  DPRINTF(PCEvent, "Acting on PC Event to PC: %s\n",
856  thread->pcState());
857  }
858 
859  return num_pc_event_checks > 1;
860 }
861 
862 void
864 {
865  assert(!inst->isFault());
866 
867  MinorThread *thread = cpu.threads[inst->id.threadId];
868 
869  /* Increment the many and various inst and op counts in the
870  * thread and system */
871  if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop())
872  {
873  thread->numInst++;
874  thread->threadStats.numInsts++;
875  cpu.stats.numInsts++;
876 
877  /* Act on events related to instruction counts */
878  thread->comInstEventQueue.serviceEvents(thread->numInst);
879  }
880  thread->numOp++;
881  thread->threadStats.numOps++;
882  cpu.stats.numOps++;
883  cpu.stats.committedInstType[inst->id.threadId]
884  [inst->staticInst->opClass()]++;
885 
887  if (inst->staticInst->isControl()) {
888  if (inst->staticInst->isReturn()) {
889  cpu.stats.committedControl[inst->id.threadId]
890  [gem5::StaticInstFlags::Flags::IsReturn]++;
891  }
892  if (inst->staticInst->isCall()) {
893  cpu.stats.committedControl[inst->id.threadId]
894  [gem5::StaticInstFlags::Flags::IsCall]++;
895  }
896  if (inst->staticInst->isDirectCtrl()) {
897  cpu.stats.committedControl[inst->id.threadId]
898  [gem5::StaticInstFlags::Flags::IsDirectControl]++;
899  }
900  if (inst->staticInst->isIndirectCtrl()) {
901  cpu.stats.committedControl[inst->id.threadId]
902  [gem5::StaticInstFlags::Flags::IsIndirectControl]++;
903  }
904  if (inst->staticInst->isCondCtrl()) {
905  cpu.stats.committedControl[inst->id.threadId]
906  [gem5::StaticInstFlags::Flags::IsCondControl]++;
907  }
908  if (inst->staticInst->isUncondCtrl()) {
909  cpu.stats.committedControl[inst->id.threadId]
910  [gem5::StaticInstFlags::Flags::IsUncondControl]++;
911 
912  }
913  cpu.stats.committedControl[inst->id.threadId]
914  [gem5::StaticInstFlags::Flags::IsControl]++;
915  }
916 
917 
918 
919  /* Set the CP SeqNum to the numOps commit number */
920  if (inst->traceData)
921  inst->traceData->setCPSeq(thread->numOp);
922 
923  cpu.probeInstCommit(inst->staticInst, inst->pc->instAddr());
924 }
925 
926 bool
927 Execute::commitInst(MinorDynInstPtr inst, bool early_memory_issue,
928  BranchData &branch, Fault &fault, bool &committed,
929  bool &completed_mem_issue)
930 {
931  ThreadID thread_id = inst->id.threadId;
932  ThreadContext *thread = cpu.getContext(thread_id);
933 
934  bool completed_inst = true;
935  fault = NoFault;
936 
937  /* Is the thread for this instruction suspended? In that case, just
938  * stall as long as there are no pending interrupts */
939  if (thread->status() == ThreadContext::Suspended &&
940  !isInterrupted(thread_id))
941  {
942  panic("We should never hit the case where we try to commit from a "
943  "suspended thread as the streamSeqNum should not match");
944  } else if (inst->isFault()) {
945  ExecContext context(cpu, *cpu.threads[thread_id], *this, inst);
946 
947  DPRINTF(MinorExecute, "Fault inst reached Execute: %s\n",
948  inst->fault->name());
949 
950  fault = inst->fault;
951  inst->fault->invoke(thread, NULL);
952 
953  tryToBranch(inst, fault, branch);
954  } else if (inst->staticInst->isMemRef()) {
955  /* Memory accesses are executed in two parts:
956  * executeMemRefInst -- calculates the EA and issues the access
957  * to memory. This is done here.
958  * handleMemResponse -- handles the response packet, done by
959  * Execute::commit
960  *
961  * While the memory access is in its FU, the EA is being
962  * calculated. At the end of the FU, when it is ready to
963  * 'commit' (in this function), the access is presented to the
964  * memory queues. When a response comes back from memory,
965  * Execute::commit will commit it.
966  */
967  bool predicate_passed = false;
968  bool completed_mem_inst = executeMemRefInst(inst, branch,
969  predicate_passed, fault);
970 
971  if (completed_mem_inst && fault != NoFault) {
972  if (early_memory_issue) {
973  DPRINTF(MinorExecute, "Fault in early executing inst: %s\n",
974  fault->name());
975  /* Don't execute the fault, just stall the instruction
976  * until it gets to the head of inFlightInsts */
977  inst->canEarlyIssue = false;
978  /* Not completed as we'll come here again to pick up
979  * the fault when we get to the end of the FU */
980  completed_inst = false;
981  } else {
982  DPRINTF(MinorExecute, "Fault in execute: %s\n",
983  fault->name());
984  fault->invoke(thread, NULL);
985 
986  tryToBranch(inst, fault, branch);
987  completed_inst = true;
988  }
989  } else {
990  completed_inst = completed_mem_inst;
991  }
992  completed_mem_issue = completed_inst;
993  } else if (inst->isInst() && inst->staticInst->isFullMemBarrier() &&
995  {
996  DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as"
997  " there isn't space in the store buffer\n", *inst);
998 
999  completed_inst = false;
1000  } else if (inst->isInst() && inst->staticInst->isQuiesce()
1001  && !branch.isBubble()){
1002  /* This instruction can suspend, need to be able to communicate
1003  * backwards, so no other branches may evaluate this cycle*/
1004  completed_inst = false;
1005  } else {
1006  ExecContext context(cpu, *cpu.threads[thread_id], *this, inst);
1007 
1008  DPRINTF(MinorExecute, "Committing inst: %s\n", *inst);
1009 
1010  fault = inst->staticInst->execute(&context,
1011  inst->traceData);
1012 
1013  /* Set the predicate for tracing and dump */
1014  if (inst->traceData)
1015  inst->traceData->setPredicate(context.readPredicate());
1016 
1017  committed = true;
1018 
1019  if (fault != NoFault) {
1020  if (inst->traceData) {
1021  if (debug::ExecFaulting) {
1022  inst->traceData->setFaulting(true);
1023  } else {
1024  delete inst->traceData;
1025  inst->traceData = NULL;
1026  }
1027  }
1028 
1029  DPRINTF(MinorExecute, "Fault in execute of inst: %s fault: %s\n",
1030  *inst, fault->name());
1031  fault->invoke(thread, inst->staticInst);
1032  }
1033 
1034  doInstCommitAccounting(inst);
1035  tryToBranch(inst, fault, branch);
1036  }
1037 
1038  if (completed_inst) {
1039  /* Keep a copy of this instruction's predictionSeqNum just in case
1040  * we need to issue a branch without an instruction (such as an
1041  * interrupt) */
1042  executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum;
1043 
1044  /* Check to see if this instruction suspended the current thread. */
1045  if (!inst->isFault() &&
1046  thread->status() == ThreadContext::Suspended &&
1047  branch.isBubble() && /* It didn't branch too */
1048  !isInterrupted(thread_id)) /* Don't suspend if we have
1049  interrupts */
1050  {
1051  auto &resume_pc = cpu.getContext(thread_id)->pcState();
1052 
1053  assert(resume_pc.microPC() == 0);
1054 
1055  DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute"
1056  " inst: %s\n", thread_id, *inst);
1057 
1059 
1061  resume_pc, branch);
1062  }
1063  }
1064 
1065  return completed_inst;
1066 }
1067 
1068 void
1069 Execute::commit(ThreadID thread_id, bool only_commit_microops, bool discard,
1070  BranchData &branch)
1071 {
1072  Fault fault = NoFault;
1073  Cycles now = cpu.curCycle();
1074  ExecuteThreadInfo &ex_info = executeInfo[thread_id];
1075 
1101  /* Has an instruction been completed? Once this becomes false, we stop
1102  * trying to complete instructions. */
1103  bool completed_inst = true;
1104 
1105  /* Number of insts committed this cycle to check against commitLimit */
1106  unsigned int num_insts_committed = 0;
1107 
1108  /* Number of memory access instructions committed to check against
1109  * memCommitLimit */
1110  unsigned int num_mem_refs_committed = 0;
1111 
1112  if (only_commit_microops && !ex_info.inFlightInsts->empty()) {
1113  DPRINTF(MinorInterrupt, "Only commit microops %s %d\n",
1114  *(ex_info.inFlightInsts->front().inst),
1115  ex_info.lastCommitWasEndOfMacroop);
1116  }
1117 
1118  while (!ex_info.inFlightInsts->empty() && /* Some more instructions to process */
1119  !branch.isStreamChange() && /* No real branch */
1120  fault == NoFault && /* No faults */
1121  completed_inst && /* Still finding instructions to execute */
1122  num_insts_committed != commitLimit /* Not reached commit limit */
1123  )
1124  {
1125  if (only_commit_microops) {
1126  DPRINTF(MinorInterrupt, "Committing tail of insts before"
1127  " interrupt: %s\n",
1128  *(ex_info.inFlightInsts->front().inst));
1129  }
1130 
1131  QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front());
1132 
1133  InstSeqNum head_exec_seq_num =
1134  head_inflight_inst->inst->id.execSeqNum;
1135 
1136  /* The instruction we actually process if completed_inst
1137  * remains true to the end of the loop body.
1138  * Start by considering the the head of the in flight insts queue */
1139  MinorDynInstPtr inst = head_inflight_inst->inst;
1140 
1141  bool committed_inst = false;
1142  bool discard_inst = false;
1143  bool completed_mem_ref = false;
1144  bool issued_mem_ref = false;
1145  bool early_memory_issue = false;
1146 
1147  /* Must set this again to go around the loop */
1148  completed_inst = false;
1149 
1150  /* If we're just completing a macroop before an interrupt or drain,
1151  * can we stil commit another microop (rather than a memory response)
1152  * without crosing into the next full instruction? */
1153  bool can_commit_insts = !ex_info.inFlightInsts->empty() &&
1154  !(only_commit_microops && ex_info.lastCommitWasEndOfMacroop);
1155 
1156  /* Can we find a mem response for this inst */
1157  LSQ::LSQRequestPtr mem_response =
1158  (inst->inLSQ ? lsq.findResponse(inst) : NULL);
1159 
1160  DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n",
1161  can_commit_insts);
1162 
1163  /* Test for PC events after every instruction */
1164  if (isInbetweenInsts(thread_id) && tryPCEvents(thread_id)) {
1165  ThreadContext *thread = cpu.getContext(thread_id);
1166 
1167  /* Branch as there was a change in PC */
1169  MinorDynInst::bubble(), thread->pcState(), branch);
1170  } else if (mem_response &&
1171  num_mem_refs_committed < memoryCommitLimit)
1172  {
1173  /* Try to commit from the memory responses next */
1174  discard_inst = inst->id.streamSeqNum !=
1175  ex_info.streamSeqNum || discard;
1176 
1177  DPRINTF(MinorExecute, "Trying to commit mem response: %s\n",
1178  *inst);
1179 
1180  /* Complete or discard the response */
1181  if (discard_inst) {
1182  DPRINTF(MinorExecute, "Discarding mem inst: %s as its"
1183  " stream state was unexpected, expected: %d\n",
1184  *inst, ex_info.streamSeqNum);
1185 
1186  lsq.popResponse(mem_response);
1187  } else {
1188  handleMemResponse(inst, mem_response, branch, fault);
1189  committed_inst = true;
1190  }
1191 
1192  completed_mem_ref = true;
1193  completed_inst = true;
1194  } else if (can_commit_insts) {
1195  /* If true, this instruction will, subject to timing tweaks,
1196  * be considered for completion. try_to_commit flattens
1197  * the `if' tree a bit and allows other tests for inst
1198  * commit to be inserted here. */
1199  bool try_to_commit = false;
1200 
1201  /* Try and issue memory ops early if they:
1202  * - Can push a request into the LSQ
1203  * - Have reached the end of their FUs
1204  * - Have had all their dependencies satisfied
1205  * - Are from the right stream
1206  *
1207  * For any other case, leave it to the normal instruction
1208  * issue below to handle them.
1209  */
1210  if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) {
1211  DPRINTF(MinorExecute, "Trying to commit from mem FUs\n");
1212 
1213  const MinorDynInstPtr head_mem_ref_inst =
1214  ex_info.inFUMemInsts->front().inst;
1215  FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex];
1216  const MinorDynInstPtr &fu_inst = fu->front().inst;
1217 
1218  /* Use this, possibly out of order, inst as the one
1219  * to 'commit'/send to the LSQ */
1220  if (!fu_inst->isBubble() &&
1221  !fu_inst->inLSQ &&
1222  fu_inst->canEarlyIssue &&
1223  ex_info.streamSeqNum == fu_inst->id.streamSeqNum &&
1224  head_exec_seq_num > fu_inst->instToWaitFor)
1225  {
1226  DPRINTF(MinorExecute, "Issuing mem ref early"
1227  " inst: %s instToWaitFor: %d\n",
1228  *(fu_inst), fu_inst->instToWaitFor);
1229 
1230  inst = fu_inst;
1231  try_to_commit = true;
1232  early_memory_issue = true;
1233  completed_inst = true;
1234  }
1235  }
1236 
1237  /* Try and commit FU-less insts */
1238  if (!completed_inst && inst->isNoCostInst()) {
1239  DPRINTF(MinorExecute, "Committing no cost inst: %s", *inst);
1240 
1241  try_to_commit = true;
1242  completed_inst = true;
1243  }
1244 
1245  /* Try to issue from the ends of FUs and the inFlightInsts
1246  * queue */
1247  if (!completed_inst && !inst->inLSQ) {
1248  DPRINTF(MinorExecute, "Trying to commit from FUs\n");
1249 
1250  /* Try to commit from a functional unit */
1251  /* Is the head inst of the expected inst's FU actually the
1252  * expected inst? */
1253  QueuedInst &fu_inst =
1254  funcUnits[inst->fuIndex]->front();
1255  InstSeqNum fu_inst_seq_num = fu_inst.inst->id.execSeqNum;
1256 
1257  if (fu_inst.inst->isBubble()) {
1258  /* No instruction ready */
1259  completed_inst = false;
1260  } else if (fu_inst_seq_num != head_exec_seq_num) {
1261  /* Past instruction: we must have already executed it
1262  * in the same cycle and so the head inst isn't
1263  * actually at the end of its pipeline
1264  * Future instruction: handled above and only for
1265  * mem refs on their way to the LSQ */
1266  } else if (fu_inst.inst->id == inst->id) {
1267  /* All instructions can be committed if they have the
1268  * right execSeqNum and there are no in-flight
1269  * mem insts before us */
1270  try_to_commit = true;
1271  completed_inst = true;
1272  }
1273  }
1274 
1275  if (try_to_commit) {
1276  discard_inst = inst->id.streamSeqNum !=
1277  ex_info.streamSeqNum || discard;
1278 
1279  /* Is this instruction discardable as its streamSeqNum
1280  * doesn't match? */
1281  if (!discard_inst) {
1282  /* Try to commit or discard a non-memory instruction.
1283  * Memory ops are actually 'committed' from this FUs
1284  * and 'issued' into the memory system so we need to
1285  * account for them later (commit_was_mem_issue gets
1286  * set) */
1287  if (inst->extraCommitDelayExpr) {
1288  DPRINTF(MinorExecute, "Evaluating expression for"
1289  " extra commit delay inst: %s\n", *inst);
1290 
1291  ThreadContext *thread = cpu.getContext(thread_id);
1292 
1293  TimingExprEvalContext context(inst->staticInst,
1294  thread, NULL);
1295 
1296  uint64_t extra_delay = inst->extraCommitDelayExpr->
1297  eval(context);
1298 
1299  DPRINTF(MinorExecute, "Extra commit delay expr"
1300  " result: %d\n", extra_delay);
1301 
1302  if (extra_delay < 128) {
1303  inst->extraCommitDelay += Cycles(extra_delay);
1304  } else {
1305  DPRINTF(MinorExecute, "Extra commit delay was"
1306  " very long: %d\n", extra_delay);
1307  }
1308  inst->extraCommitDelayExpr = NULL;
1309  }
1310 
1311  /* Move the extraCommitDelay from the instruction
1312  * into the minimumCommitCycle */
1313  if (inst->extraCommitDelay != Cycles(0)) {
1314  inst->minimumCommitCycle = cpu.curCycle() +
1315  inst->extraCommitDelay;
1316  inst->extraCommitDelay = Cycles(0);
1317  }
1318 
1319  /* @todo Think about making lastMemBarrier be
1320  * MAX_UINT_64 to avoid using 0 as a marker value */
1321  if (!inst->isFault() && inst->isMemRef() &&
1322  lsq.getLastMemBarrier(thread_id) <
1323  inst->id.execSeqNum &&
1324  lsq.getLastMemBarrier(thread_id) != 0)
1325  {
1326  DPRINTF(MinorExecute, "Not committing inst: %s yet"
1327  " as there are incomplete barriers in flight\n",
1328  *inst);
1329  completed_inst = false;
1330  } else if (inst->minimumCommitCycle > now) {
1331  DPRINTF(MinorExecute, "Not committing inst: %s yet"
1332  " as it wants to be stalled for %d more cycles\n",
1333  *inst, inst->minimumCommitCycle - now);
1334  completed_inst = false;
1335  } else {
1336  completed_inst = commitInst(inst,
1337  early_memory_issue, branch, fault,
1338  committed_inst, issued_mem_ref);
1339  }
1340  } else {
1341  /* Discard instruction */
1342  completed_inst = true;
1343  }
1344 
1345  if (completed_inst) {
1346  /* Allow the pipeline to advance. If the FU head
1347  * instruction wasn't the inFlightInsts head
1348  * but had already been committed, it would have
1349  * unstalled the pipeline before here */
1350  if (inst->fuIndex != noCostFUIndex) {
1351  DPRINTF(MinorExecute, "Unstalling %d for inst %s\n", inst->fuIndex, inst->id);
1352  funcUnits[inst->fuIndex]->stalled = false;
1353  }
1354  }
1355  }
1356  } else {
1357  DPRINTF(MinorExecute, "No instructions to commit\n");
1358  completed_inst = false;
1359  }
1360 
1361  /* All discardable instructions must also be 'completed' by now */
1362  assert(!(discard_inst && !completed_inst));
1363 
1364  /* Instruction committed but was discarded due to streamSeqNum
1365  * mismatch */
1366  if (discard_inst) {
1367  DPRINTF(MinorExecute, "Discarding inst: %s as its stream"
1368  " state was unexpected, expected: %d\n",
1369  *inst, ex_info.streamSeqNum);
1370 
1371  if (fault == NoFault)
1373  }
1374 
1375  /* Mark the mem inst as being in the LSQ */
1376  if (issued_mem_ref) {
1377  inst->fuIndex = 0;
1378  inst->inLSQ = true;
1379  }
1380 
1381  /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts
1382  * as they've *definitely* exited the FUs */
1383  if (completed_inst && inst->isMemRef()) {
1384  /* The MemRef could have been discarded from the FU or the memory
1385  * queue, so just check an FU instruction */
1386  if (!ex_info.inFUMemInsts->empty() &&
1387  ex_info.inFUMemInsts->front().inst == inst)
1388  {
1389  ex_info.inFUMemInsts->pop();
1390  }
1391  }
1392 
1393  if (completed_inst && !(issued_mem_ref && fault == NoFault)) {
1394  /* Note that this includes discarded insts */
1395  DPRINTF(MinorExecute, "Completed inst: %s\n", *inst);
1396 
1397  /* Got to the end of a full instruction? */
1398  ex_info.lastCommitWasEndOfMacroop = inst->isFault() ||
1399  inst->isLastOpInInst();
1400 
1401  /* lastPredictionSeqNum is kept as a convenience to prevent its
1402  * value from changing too much on the minorview display */
1403  ex_info.lastPredictionSeqNum = inst->id.predictionSeqNum;
1404 
1405  /* Finished with the inst, remove it from the inst queue and
1406  * clear its dependencies */
1407  ex_info.inFlightInsts->pop();
1408 
1409  /* Complete barriers in the LSQ/move to store buffer */
1410  if (inst->isInst() && inst->staticInst->isFullMemBarrier()) {
1411  DPRINTF(MinorMem, "Completing memory barrier"
1412  " inst: %s committed: %d\n", *inst, committed_inst);
1413  lsq.completeMemBarrierInst(inst, committed_inst);
1414  }
1415 
1416  scoreboard[thread_id].clearInstDests(inst, inst->isMemRef());
1417  }
1418 
1419  /* Handle per-cycle instruction counting */
1420  if (committed_inst) {
1421  bool is_no_cost_inst = inst->isNoCostInst();
1422 
1423  /* Don't show no cost instructions as having taken a commit
1424  * slot */
1425  if (debug::MinorTrace && !is_no_cost_inst)
1426  ex_info.instsBeingCommitted.insts[num_insts_committed] = inst;
1427 
1428  if (!is_no_cost_inst)
1429  num_insts_committed++;
1430 
1431  if (num_insts_committed == commitLimit)
1432  DPRINTF(MinorExecute, "Reached inst commit limit\n");
1433 
1434  /* Re-set the time of the instruction if that's required for
1435  * tracing */
1436  if (inst->traceData) {
1438  inst->traceData->setWhen(curTick());
1439  inst->traceData->dump();
1440  }
1441 
1442  if (completed_mem_ref)
1443  num_mem_refs_committed++;
1444 
1445  if (num_mem_refs_committed == memoryCommitLimit)
1446  DPRINTF(MinorExecute, "Reached mem ref commit limit\n");
1447  }
1448  }
1449 }
1450 
1451 bool
1453 {
1454  return executeInfo[thread_id].lastCommitWasEndOfMacroop &&
1455  !lsq.accessesInFlight();
1456 }
1457 
1458 void
1460 {
1461  if (!inp.outputWire->isBubble())
1462  inputBuffer[inp.outputWire->threadId].setTail(*inp.outputWire);
1463 
1464  BranchData &branch = *out.inputWire;
1465 
1466  unsigned int num_issued = 0;
1467 
1468  /* Do all the cycle-wise activities for dcachePort here to potentially
1469  * free up input spaces in the LSQ's requests queue */
1470  lsq.step();
1471 
1472  /* Check interrupts first. Will halt commit if interrupt found */
1473  bool interrupted = false;
1474  ThreadID interrupt_tid = checkInterrupts(branch, interrupted);
1475 
1476  if (interrupt_tid != InvalidThreadID) {
1477  /* Signalling an interrupt this cycle, not issuing/committing from
1478  * any other threads */
1479  } else if (!branch.isBubble()) {
1480  /* It's important that this is here to carry Fetch1 wakeups to Fetch1
1481  * without overwriting them */
1482  DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old"
1483  " branch to complete\n");
1484  } else {
1485  ThreadID commit_tid = getCommittingThread();
1486 
1487  if (commit_tid != InvalidThreadID) {
1488  ExecuteThreadInfo& commit_info = executeInfo[commit_tid];
1489 
1490  DPRINTF(MinorExecute, "Attempting to commit [tid:%d]\n",
1491  commit_tid);
1492  /* commit can set stalled flags observable to issue and so *must* be
1493  * called first */
1494  if (commit_info.drainState != NotDraining) {
1495  if (commit_info.drainState == DrainCurrentInst) {
1496  /* Commit only micro-ops, don't kill anything else */
1497  commit(commit_tid, true, false, branch);
1498 
1499  if (isInbetweenInsts(commit_tid))
1500  setDrainState(commit_tid, DrainHaltFetch);
1501 
1502  /* Discard any generated branch */
1503  branch = BranchData::bubble();
1504  } else if (commit_info.drainState == DrainAllInsts) {
1505  /* Kill all instructions */
1506  while (getInput(commit_tid))
1507  popInput(commit_tid);
1508  commit(commit_tid, false, true, branch);
1509  }
1510  } else {
1511  /* Commit micro-ops only if interrupted. Otherwise, commit
1512  * anything you like */
1513  DPRINTF(MinorExecute, "Committing micro-ops for interrupt[tid:%d]\n",
1514  commit_tid);
1515  bool only_commit_microops = interrupted &&
1516  hasInterrupt(commit_tid);
1517  commit(commit_tid, only_commit_microops, false, branch);
1518  }
1519 
1520  /* Halt fetch, but don't do it until we have the current instruction in
1521  * the bag */
1522  if (commit_info.drainState == DrainHaltFetch) {
1525  cpu.getContext(commit_tid)->pcState(), branch);
1526 
1528  setDrainState(commit_tid, DrainAllInsts);
1529  }
1530  }
1531  ThreadID issue_tid = getIssuingThread();
1532  /* This will issue merrily even when interrupted in the sure and
1533  * certain knowledge that the interrupt with change the stream */
1534  if (issue_tid != InvalidThreadID) {
1535  DPRINTF(MinorExecute, "Attempting to issue [tid:%d]\n",
1536  issue_tid);
1537  num_issued = issue(issue_tid);
1538  }
1539 
1540  }
1541 
1542  /* Run logic to step functional units + decide if we are active on the next
1543  * clock cycle */
1544  std::vector<MinorDynInstPtr> next_issuable_insts;
1545  bool can_issue_next = false;
1546 
1547  for (ThreadID tid = 0; tid < cpu.numThreads; tid++) {
1548  /* Find the next issuable instruction for each thread and see if it can
1549  be issued */
1550  if (getInput(tid)) {
1551  unsigned int input_index = executeInfo[tid].inputIndex;
1552  MinorDynInstPtr inst = getInput(tid)->insts[input_index];
1553  if (inst->isFault()) {
1554  can_issue_next = true;
1555  } else if (!inst->isBubble()) {
1556  next_issuable_insts.push_back(inst);
1557  }
1558  }
1559  }
1560 
1561  bool becoming_stalled = true;
1562 
1563  /* Advance the pipelines and note whether they still need to be
1564  * advanced */
1565  for (unsigned int i = 0; i < numFuncUnits; i++) {
1566  FUPipeline *fu = funcUnits[i];
1567  fu->advance();
1568 
1569  /* If we need to tick again, the pipeline will have been left or set
1570  * to be unstalled */
1571  if (fu->occupancy !=0 && !fu->stalled)
1572  becoming_stalled = false;
1573 
1574  /* Could we possibly issue the next instruction from any thread?
1575  * This is quite an expensive test and is only used to determine
1576  * if the CPU should remain active, only run it if we aren't sure
1577  * we are active next cycle yet */
1578  for (auto inst : next_issuable_insts) {
1579  if (!fu->stalled && fu->provides(inst->staticInst->opClass()) &&
1580  scoreboard[inst->id.threadId].canInstIssue(inst,
1581  NULL, NULL, cpu.curCycle() + Cycles(1),
1582  cpu.getContext(inst->id.threadId))) {
1583  can_issue_next = true;
1584  break;
1585  }
1586  }
1587  }
1588 
1589  bool head_inst_might_commit = false;
1590 
1591  /* Could the head in flight insts be committed */
1592  for (auto const &info : executeInfo) {
1593  if (!info.inFlightInsts->empty()) {
1594  const QueuedInst &head_inst = info.inFlightInsts->front();
1595 
1596  if (head_inst.inst->isNoCostInst()) {
1597  head_inst_might_commit = true;
1598  } else {
1599  FUPipeline *fu = funcUnits[head_inst.inst->fuIndex];
1600  if ((fu->stalled &&
1601  fu->front().inst->id == head_inst.inst->id) ||
1602  lsq.findResponse(head_inst.inst))
1603  {
1604  head_inst_might_commit = true;
1605  break;
1606  }
1607  }
1608  }
1609  }
1610 
1611  DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n",
1612  (num_issued != 0 ? " (issued some insts)" : ""),
1613  (becoming_stalled ? "(becoming stalled)" : "(not becoming stalled)"),
1614  (can_issue_next ? " (can issued next inst)" : ""),
1615  (head_inst_might_commit ? "(head inst might commit)" : ""),
1616  (lsq.needsToTick() ? " (LSQ needs to tick)" : ""),
1617  (interrupted ? " (interrupted)" : ""));
1618 
1619  bool need_to_tick =
1620  num_issued != 0 || /* Issued some insts this cycle */
1621  !becoming_stalled || /* Some FU pipelines can still move */
1622  can_issue_next || /* Can still issue a new inst */
1623  head_inst_might_commit || /* Could possible commit the next inst */
1624  lsq.needsToTick() || /* Must step the dcache port */
1625  interrupted; /* There are pending interrupts */
1626 
1627  if (!need_to_tick) {
1628  DPRINTF(Activity, "The next cycle might be skippable as there are no"
1629  " advanceable FUs\n");
1630  }
1631 
1632  /* Wake up if we need to tick again */
1633  if (need_to_tick)
1635 
1636  /* Note activity of following buffer */
1637  if (!branch.isBubble())
1639 
1640  /* Make sure the input (if any left) is pushed */
1641  if (!inp.outputWire->isBubble())
1642  inputBuffer[inp.outputWire->threadId].pushTail();
1643 }
1644 
1645 ThreadID
1646 Execute::checkInterrupts(BranchData& branch, bool& interrupted)
1647 {
1649  /* Evaluate interrupts in round-robin based upon service */
1650  do {
1651  /* Has an interrupt been signalled? This may not be acted on
1652  * straighaway so this is different from took_interrupt */
1653  bool thread_interrupted = false;
1654 
1655  if (FullSystem && cpu.getInterruptController(tid)) {
1656  /* This is here because it seems that after drainResume the
1657  * interrupt controller isn't always set */
1658  thread_interrupted = executeInfo[tid].drainState == NotDraining &&
1659  isInterrupted(tid);
1660  interrupted = interrupted || thread_interrupted;
1661  } else {
1662  DPRINTF(MinorInterrupt, "No interrupt controller\n");
1663  }
1664  DPRINTF(MinorInterrupt, "[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n",
1665  tid, thread_interrupted, isInbetweenInsts(tid));
1666  /* Act on interrupts */
1667  if (thread_interrupted && isInbetweenInsts(tid)) {
1668  if (takeInterrupt(tid, branch)) {
1669  interruptPriority = tid;
1670  return tid;
1671  }
1672  } else {
1673  tid = (tid + 1) % cpu.numThreads;
1674  }
1675  } while (tid != interruptPriority);
1676 
1677  return InvalidThreadID;
1678 }
1679 
1680 bool
1682 {
1683  if (FullSystem && cpu.getInterruptController(thread_id)) {
1684  return executeInfo[thread_id].drainState == NotDraining &&
1685  isInterrupted(thread_id);
1686  }
1687 
1688  return false;
1689 }
1690 
1691 void
1693 {
1694  std::ostringstream insts;
1695  std::ostringstream stalled;
1696 
1697  executeInfo[0].instsBeingCommitted.reportData(insts);
1698  lsq.minorTrace();
1699  inputBuffer[0].minorTrace();
1700  scoreboard[0].minorTrace();
1701 
1702  /* Report functional unit stalling in one string */
1703  unsigned int i = 0;
1704  while (i < numFuncUnits)
1705  {
1706  stalled << (funcUnits[i]->stalled ? '1' : 'E');
1707  i++;
1708  if (i != numFuncUnits)
1709  stalled << ',';
1710  }
1711 
1712  minor::minorTrace("insts=%s inputIndex=%d streamSeqNum=%d"
1713  " stalled=%s drainState=%d isInbetweenInsts=%d\n",
1714  insts.str(), executeInfo[0].inputIndex, executeInfo[0].streamSeqNum,
1715  stalled.str(), executeInfo[0].drainState, isInbetweenInsts(0));
1716 
1717  std::for_each(funcUnits.begin(), funcUnits.end(),
1718  std::mem_fn(&FUPipeline::minorTrace));
1719 
1720  executeInfo[0].inFlightInsts->minorTrace();
1721  executeInfo[0].inFUMemInsts->minorTrace();
1722 }
1723 
1724 inline ThreadID
1726 {
1727  std::vector<ThreadID> priority_list;
1728 
1729  switch (cpu.threadPolicy) {
1730  case enums::SingleThreaded:
1731  return 0;
1732  case enums::RoundRobin:
1733  priority_list = cpu.roundRobinPriority(commitPriority);
1734  break;
1735  case enums::Random:
1736  priority_list = cpu.randomPriority();
1737  break;
1738  default:
1739  panic("Invalid thread policy");
1740  }
1741 
1742  for (auto tid : priority_list) {
1743  ExecuteThreadInfo &ex_info = executeInfo[tid];
1744  bool can_commit_insts = !ex_info.inFlightInsts->empty();
1745  if (can_commit_insts) {
1746  QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front());
1747  MinorDynInstPtr inst = head_inflight_inst->inst;
1748 
1749  can_commit_insts = can_commit_insts &&
1750  (!inst->inLSQ || (lsq.findResponse(inst) != NULL));
1751 
1752  if (!inst->inLSQ) {
1753  bool can_transfer_mem_inst = false;
1754  if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) {
1755  const MinorDynInstPtr head_mem_ref_inst =
1756  ex_info.inFUMemInsts->front().inst;
1757  FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex];
1758  const MinorDynInstPtr &fu_inst = fu->front().inst;
1759  can_transfer_mem_inst =
1760  !fu_inst->isBubble() &&
1761  fu_inst->id.threadId == tid &&
1762  !fu_inst->inLSQ &&
1763  fu_inst->canEarlyIssue &&
1764  inst->id.execSeqNum > fu_inst->instToWaitFor;
1765  }
1766 
1767  bool can_execute_fu_inst = inst->fuIndex == noCostFUIndex;
1768  if (can_commit_insts && !can_transfer_mem_inst &&
1769  inst->fuIndex != noCostFUIndex)
1770  {
1771  QueuedInst& fu_inst = funcUnits[inst->fuIndex]->front();
1772  can_execute_fu_inst = !fu_inst.inst->isBubble() &&
1773  fu_inst.inst->id == inst->id;
1774  }
1775 
1776  can_commit_insts = can_commit_insts &&
1777  (can_transfer_mem_inst || can_execute_fu_inst);
1778  }
1779  }
1780 
1781 
1782  if (can_commit_insts) {
1783  commitPriority = tid;
1784  return tid;
1785  }
1786  }
1787 
1788  return InvalidThreadID;
1789 }
1790 
1791 inline ThreadID
1793 {
1794  std::vector<ThreadID> priority_list;
1795 
1796  switch (cpu.threadPolicy) {
1797  case enums::SingleThreaded:
1798  return 0;
1799  case enums::RoundRobin:
1800  priority_list = cpu.roundRobinPriority(issuePriority);
1801  break;
1802  case enums::Random:
1803  priority_list = cpu.randomPriority();
1804  break;
1805  default:
1806  panic("Invalid thread scheduling policy.");
1807  }
1808 
1809  for (auto tid : priority_list) {
1810  if (getInput(tid)) {
1811  issuePriority = tid;
1812  return tid;
1813  }
1814  }
1815 
1816  return InvalidThreadID;
1817 }
1818 
1819 void
1821 {
1822  DPRINTF(Drain, "MinorExecute drainResume\n");
1823 
1824  for (ThreadID tid = 0; tid < cpu.numThreads; tid++) {
1825  setDrainState(tid, NotDraining);
1826  }
1827 
1829 }
1830 
1831 std::ostream &operator <<(std::ostream &os, Execute::DrainState state)
1832 {
1833  switch (state)
1834  {
1835  case Execute::NotDraining:
1836  os << "NotDraining";
1837  break;
1839  os << "DrainCurrentInst";
1840  break;
1842  os << "DrainHaltFetch";
1843  break;
1845  os << "DrainAllInsts";
1846  break;
1847  default:
1848  os << "Drain-" << static_cast<int>(state);
1849  break;
1850  }
1851 
1852  return os;
1853 }
1854 
1855 void
1857 {
1858  DPRINTF(Drain, "setDrainState[%d]: %s\n", thread_id, state);
1859  executeInfo[thread_id].drainState = state;
1860 }
1861 
1862 unsigned int
1864 {
1865  DPRINTF(Drain, "MinorExecute drain\n");
1866 
1867  for (ThreadID tid = 0; tid < cpu.numThreads; tid++) {
1868  if (executeInfo[tid].drainState == NotDraining) {
1870 
1871  /* Go to DrainCurrentInst if we're between microops
1872  * or waiting on an unbufferable memory operation.
1873  * Otherwise we can go straight to DrainHaltFetch
1874  */
1875  if (isInbetweenInsts(tid))
1877  else
1879  }
1880  }
1881  return (isDrained() ? 0 : 1);
1882 }
1883 
1884 bool
1886 {
1887  if (!lsq.isDrained())
1888  return false;
1889 
1890  for (ThreadID tid = 0; tid < cpu.numThreads; tid++) {
1891  if (!inputBuffer[tid].empty() ||
1892  !executeInfo[tid].inFlightInsts->empty()) {
1893 
1894  return false;
1895  }
1896  }
1897 
1898  return true;
1899 }
1900 
1902 {
1903  for (unsigned int i = 0; i < numFuncUnits; i++)
1904  delete funcUnits[i];
1905 
1906  for (ThreadID tid = 0; tid < cpu.numThreads; tid++)
1907  delete executeInfo[tid].inFlightInsts;
1908 }
1909 
1910 bool
1912 {
1913  return inst->id.streamSeqNum == executeInfo[inst->id.threadId].streamSeqNum;
1914 }
1915 
1916 bool
1918 {
1919  bool ret = false;
1920 
1921  if (!executeInfo[inst->id.threadId].inFlightInsts->empty())
1922  ret = executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id;
1923 
1924  return ret;
1925 }
1926 
1929 {
1930  return lsq.getDcachePort();
1931 }
1932 
1933 } // namespace minor
1934 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
void activity()
Records that there is activity this cycle.
Definition: activity.cc:55
virtual ThreadContext * getContext(int tn)
Given a thread num get tho thread context for it.
Definition: base.hh:284
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
BaseInterrupts * getInterruptController(ThreadID tid)
Definition: base.hh:224
virtual void probeInstCommit(const StaticInstPtr &inst, Addr pc)
Helper method to trigger PMU probes for a committed instruction.
Definition: base.cc:353
virtual void updateIntrInfo()=0
virtual Fault getInterrupt()=0
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
Provide a non-protected base class for Minor's Ports as derived classes are created by Fetch1 and Exe...
Definition: cpu.hh:107
MinorCPU is an in-order CPU model with four fixed pipeline stages:
Definition: cpu.hh:86
minor::MinorStats stats
Processor-specific statistics.
Definition: cpu.hh:140
minor::MinorActivityRecorder * activityRecorder
Activity recording for pipeline.
Definition: cpu.hh:96
void wakeupOnEvent(unsigned int stage_id)
Interface for stages to signal that they have become active after a callback or eventq event where th...
Definition: cpu.cc:291
std::vector< ThreadID > roundRobinPriority(ThreadID priority)
Thread scheduling utility functions.
Definition: cpu.hh:173
std::vector< ThreadID > randomPriority()
Definition: cpu.hh:182
enums::ThreadPolicy threadPolicy
Thread Scheduling Policy (RoundRobin, Random, etc)
Definition: cpu.hh:120
std::vector< minor::MinorThread * > threads
These are thread state-representing objects for this CPU.
Definition: cpu.hh:101
std::vector< MinorFU * > funcUnits
Definition: func_unit.hh:192
Extra timing capability to allow individual ops to have their source register dependency latencies tw...
Definition: func_unit.hh:104
TimingExpr * extraCommitLatExpr
Definition: func_unit.hh:121
std::vector< Cycles > srcRegsRelativeLats
Cycle offsets from the scoreboard delivery times of register values for each of this instruction's so...
Definition: func_unit.hh:136
Cycles extraAssumedLat
Extra delay that results should show in the scoreboard after leaving the pipeline.
Definition: func_unit.hh:127
bool suppress
If true, instructions matching this mask/match should not be issued in this FU.
Definition: func_unit.hh:116
Cycles extraCommitLat
Extra latency that the instruction should spend at the end of the pipeline.
Definition: func_unit.hh:120
A functional unit that can execute any of opClasses operations with a single op(eration)Lat(ency) and...
Definition: func_unit.hh:158
Cycles opLat
Delay from issuing the operation, to it reaching the end of the associated pipeline.
Definition: func_unit.hh:164
Interface for things with names.
Definition: named.hh:39
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
Definition: pcstate.hh:107
virtual PCStateBase * clone() const =0
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
Addr getAddr() const
Definition: packet.hh:805
bool isError() const
Definition: packet.hh:621
unsigned getSize() const
Definition: packet.hh:815
const T * getConstPtr() const
Definition: packet.hh:1221
The SimpleThread object provides a combination of the ThreadState object and the ThreadContext interf...
EventQueue comInstEventQueue
An instruction-based event queue.
Base class for branch operations.
Definition: branch.hh:49
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual const PCStateBase & pcState() const =0
@ Suspended
Temporarily inactive.
virtual Status status() const =0
Object to gather the visible context for evaluation.
Definition: timing_expr.hh:73
Forward data betwen Execute and Fetch1 carrying change-of-address/stream information.
Definition: pipe_data.hh:67
static bool isStreamChange(const BranchData::Reason reason)
Is a request with this reason actually a request to change the PC rather than a bubble or branch pred...
Definition: pipe_data.cc:85
bool isStreamChange() const
As static isStreamChange but on this branch data.
Definition: pipe_data.hh:167
bool isBubble() const
Definition: pipe_data.hh:164
static BranchData bubble()
BubbleIF interface.
Definition: pipe_data.hh:163
ExecContext bears the exec_context interface for Minor.
Definition: exec_context.hh:74
bool readMemAccPredicate() const override
bool readPredicate() const override
bool setTraceTimeOnIssue
Modify instruction trace times on issue.
Definition: execute.hh:112
void handleMemResponse(MinorDynInstPtr inst, LSQ::LSQRequestPtr response, BranchData &branch, Fault &fault)
Handle extracting mem ref responses from the memory queues and completing the associated instructions...
Definition: execute.cc:326
bool processMoreThanOneInput
If true, more than one input line can be processed each cycle if there is room to execute more instru...
Definition: execute.hh:96
LSQ lsq
Dcache port to pass on to the CPU.
Definition: execute.hh:123
void evaluate()
Pass on input/buffer data to the output if you can.
Definition: execute.cc:1459
unsigned int commitLimit
Number of instructions that can be committed per cycle.
Definition: execute.hh:88
void popInput(ThreadID tid)
Pop an element off the input buffer, if there are any.
Definition: execute.cc:212
unsigned int memoryCommitLimit
Number of memory instructions that can be committed per cycle.
Definition: execute.hh:91
bool executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, bool &failed_predicate, Fault &fault)
Execute a memory reference instruction.
Definition: execute.cc:451
unsigned int issue(ThreadID thread_id)
Try and issue instructions from the inputBuffer.
Definition: execute.cc:548
unsigned int noCostFUIndex
The FU index of the non-existent costless FU for instructions which pass the MinorDynInst::isNoCostIn...
Definition: execute.hh:120
unsigned int memoryIssueLimit
Number of memory ops that can be issued per cycle.
Definition: execute.hh:85
Latch< ForwardInstData >::Output inp
Input port carrying instructions from Decode.
Definition: execute.hh:73
ThreadID commitPriority
Definition: execute.hh:212
void commit(ThreadID thread_id, bool only_commit_microops, bool discard, BranchData &branch)
Try and commit instructions from the ends of the functional unit pipelines.
Definition: execute.cc:1069
MinorCPU & cpu
Pointer back to the containing CPU.
Definition: execute.hh:79
ThreadID getIssuingThread()
Definition: execute.cc:1792
unsigned int drain()
Like the drain interface on SimObject.
Definition: execute.cc:1863
unsigned int issueLimit
Number of instructions that can be issued per cycle.
Definition: execute.hh:82
bool instIsRightStream(MinorDynInstPtr inst)
Does the given instruction have the right stream sequence number to be committed?
Definition: execute.cc:1911
void setDrainState(ThreadID thread_id, DrainState state)
Set the drain state (with useful debugging messages)
Definition: execute.cc:1856
bool setTraceTimeOnCommit
Modify instruction trace times on commit.
Definition: execute.hh:109
ThreadID checkInterrupts(BranchData &branch, bool &interrupted)
Check all threads for possible interrupts.
Definition: execute.cc:1646
void updateBranchData(ThreadID tid, BranchData::Reason reason, MinorDynInstPtr inst, const PCStateBase &target, BranchData &branch)
Actually create a branch to communicate to Fetch1/Fetch2 and, if that is a stream-changing branch upd...
Definition: execute.cc:300
DrainState
Stage cycle-by-cycle state.
Definition: execute.hh:146
MinorFUPool & fuDescriptions
Descriptions of the functional units we want to generate.
Definition: execute.hh:99
bool allowEarlyMemIssue
Allow mem refs to leave their FUs before reaching the head of the in flight insts queue if their depe...
Definition: execute.hh:116
unsigned int numFuncUnits
Number of functional units to produce.
Definition: execute.hh:102
std::vector< FUPipeline * > funcUnits
The execution functional units.
Definition: execute.hh:129
void tryToBranch(MinorDynInstPtr inst, Fault fault, BranchData &branch)
Generate Branch data based (into branch) on an observed (or not) change in PC while executing an inst...
Definition: execute.cc:221
bool commitInst(MinorDynInstPtr inst, bool early_memory_issue, BranchData &branch, Fault &fault, bool &committed, bool &completed_mem_issue)
Commit a single instruction.
Definition: execute.cc:927
bool hasInterrupt(ThreadID thread_id)
Checks if a specific thread has an interrupt.
Definition: execute.cc:1681
bool isInterrupted(ThreadID thread_id) const
Has an interrupt been raised.
Definition: execute.cc:417
bool isInbetweenInsts(ThreadID thread_id) const
Are we between instructions? Can we be interrupted?
Definition: execute.cc:1452
Execute(const std::string &name_, MinorCPU &cpu_, const BaseMinorCPUParams &params, Latch< ForwardInstData >::Output inp_, Latch< BranchData >::Input out_)
Definition: execute.cc:64
ThreadID interruptPriority
Definition: execute.hh:210
std::vector< Scoreboard > scoreboard
Scoreboard of instruction dependencies.
Definition: execute.hh:126
bool takeInterrupt(ThreadID thread_id, BranchData &branch)
Act on an interrupt.
Definition: execute.cc:423
std::vector< ExecuteThreadInfo > executeInfo
Definition: execute.hh:208
std::vector< InputBuffer< ForwardInstData > > inputBuffer
Definition: execute.hh:132
void doInstCommitAccounting(MinorDynInstPtr inst)
Do the stats handling and instruction count and PC event events related to the new instruction/op cou...
Definition: execute.cc:863
MinorCPU::MinorCPUPort & getDcachePort()
Returns the DcachePort owned by this Execute to pass upwards.
Definition: execute.cc:1928
bool instIsHeadInst(MinorDynInstPtr inst)
Returns true if the given instruction is at the head of the inFlightInsts instruction queue.
Definition: execute.cc:1917
const ForwardInstData * getInput(ThreadID tid)
Get a piece of data to work on from the inputBuffer, or 0 if there is no data.
Definition: execute.cc:199
void minorTrace() const
Definition: execute.cc:1692
Latch< BranchData >::Input out
Input port carrying stream changes to Fetch1.
Definition: execute.hh:76
ThreadID issuePriority
Definition: execute.hh:211
bool isDrained()
After thread suspension, has Execute been drained of in-flight instructions and memory accesses.
Definition: execute.cc:1885
ThreadID getCommittingThread()
Use the current threading policy to determine the next thread to decode from.
Definition: execute.cc:1725
bool tryPCEvents(ThreadID thread_id)
Try to act on PC-related events.
Definition: execute.cc:841
A functional unit configured from a MinorFU object.
Definition: func_unit.hh:234
Forward flowing data between Fetch2,Decode,Execute carrying a packet of instructions of a width appro...
Definition: pipe_data.hh:285
bool isBubble() const
BubbleIF interface.
Definition: pipe_data.cc:251
MinorDynInstPtr insts[MAX_FORWARD_INSTS]
Array of carried insts, ref counted.
Definition: pipe_data.hh:288
unsigned int width() const
Number of instructions carried by this object.
Definition: pipe_data.hh:304
Like a Queue but with a restricted interface and a setTail function which, when the queue is empty,...
Definition: buffers.hh:573
Derived SenderState to carry data access info.
Definition: lsq.hh:130
bool needsToBeSentToStoreBuffer()
This request, once processed by the requests/transfers queues, will need to go to the store buffer.
Definition: lsq.cc:165
bool needsToTick()
May need to be ticked next cycle as one of the queues contains an actionable transfers or address tra...
Definition: lsq.cc:1564
void issuedMemBarrierInst(MinorDynInstPtr inst)
A memory barrier instruction has been issued, remember its execSeqNum that we can avoid issuing memor...
Definition: lsq.cc:1718
void minorTrace() const
Definition: lsq.cc:1674
void sendStoreToStoreBuffer(LSQRequestPtr request)
A store has been committed, please move it to the store buffer.
Definition: lsq.cc:1544
void pushFailedRequest(MinorDynInstPtr inst)
Push a predicate failed-representing request into the queues just to maintain commit order.
Definition: lsq.cc:1667
bool canPushIntoStoreBuffer() const
Must check this before trying to insert into the store buffer.
Definition: lsq.hh:682
bool accessesInFlight() const
Are there any accesses other than normal cached loads in the memory system or having received respons...
Definition: lsq.hh:690
void step()
Step checks the queues to see if their are issuable transfers which were not otherwise picked up by t...
Definition: lsq.cc:1476
MinorCPU::MinorCPUPort & getDcachePort()
Return the raw-bindable port.
Definition: lsq.hh:732
InstSeqNum getLastMemBarrier(ThreadID thread_id) const
Get the execSeqNum of the last issued memory barrier.
Definition: lsq.hh:699
void completeMemBarrierInst(MinorDynInstPtr inst, bool committed)
Complete a barrier instruction.
Definition: lsq.cc:914
void popResponse(LSQRequestPtr response)
Sanity check and pop the head response.
Definition: lsq.cc:1522
LSQRequestPtr findResponse(MinorDynInstPtr inst)
Returns a response if it's at the head of the transfers queue and it's either complete or can be sent...
Definition: lsq.cc:1487
bool isDrained()
Is there nothing left in the LSQ.
Definition: lsq.cc:1557
bool canRequest()
Is their space in the request queue to be able to push a request by issuing an isMemRef instruction.
Definition: lsq.hh:670
Encapsulate wires on either input or output of the latch.
Definition: buffers.hh:253
void minorTrace() const
Report buffer states from 'slot' 'from' to 'to'.
Definition: buffers.hh:198
static MinorDynInstPtr bubble()
There is a single bubble inst.
Definition: dyn_inst.hh:251
Wrapper for a queue type to act as a pipeline stage input queue.
Definition: buffers.hh:405
Container class to box instructions in the FUs to make those queues have correct bubble behaviour whe...
Definition: func_unit.hh:208
MinorDynInstPtr inst
Definition: func_unit.hh:210
...ReportTraits are trait classes with the same functionality as ReportIF, but with elements explicit...
Definition: buffers.hh:98
STL vector class.
Definition: stl.hh:37
Top level definition of the Minor in-order CPU model.
All the fun of executing instructions from Decode and sending branch/new instruction stream info.
Fetch1 is responsible for fetching "lines" from memory and passing them to Fetch2.
void serviceEvents(Tick when)
process all events up to the given timestamp.
Definition: eventq.hh:876
#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
atomic_var_t state
Definition: helpers.cc:188
#define warn(...)
Definition: logging.hh:246
ExecContext bears the exec_context interface for Minor.
A load/store queue that allows outstanding reads and writes.
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 30, 0 > index
Bitfield< 12 > fu
Definition: misc.hh:94
Bitfield< 17 > os
Definition: misc.hh:810
unsigned int cyclicIndexInc(unsigned int index, unsigned int cycle_size)
Increment a cyclic buffer index for indices [0, cycle_size-1].
Definition: execute.cc:525
unsigned int cyclicIndexDec(unsigned int index, unsigned int cycle_size)
Decrement a cyclic buffer index for indices [0, cycle_size-1].
Definition: execute.cc:537
std::ostream & operator<<(std::ostream &os, const InstId &id)
Print this id in the usual slash-separated format expected by MinorTrace.
Definition: dyn_inst.cc:64
void minorTrace(const char *fmt, Args ...args)
DPRINTFN for MinorTrace reporting.
Definition: trace.hh:67
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
static const OpClass Num_OpClasses
Definition: op_class.hh:108
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
constexpr decltype(nullptr) NoFault
Definition: types.hh:253
uint64_t InstSeqNum
Definition: inst_seq.hh:40
GEM5_DEPRECATED_NAMESPACE(GuestABI, guest_abi)
Minor contains all the definitions within the MinorCPU apart from the CPU class itself.
const std::string to_string(sc_enc enc)
Definition: sc_fxdefs.cc:60
statistics::Scalar numOps
Stat for number ops (including micro ops) committed.
Definition: thread_state.hh:98
statistics::Scalar numInsts
Stat for number instructions committed.
Definition: thread_state.hh:96
Counter numInst
Number of instructions committed.
Definition: thread_state.hh:88
Counter numOp
Number of ops (including micro ops) committed.
Definition: thread_state.hh:90
gem5::ThreadState::ThreadStateStats threadStats
unsigned int inputIndex
Index that we've completed upto in getInput data.
Definition: execute.hh:182
ForwardInstData instsBeingCommitted
Structure for reporting insts currently being processed/retired for MinorTrace.
Definition: execute.hh:190
bool lastCommitWasEndOfMacroop
The last commit was the end of a full instruction so an interrupt can safely happen.
Definition: execute.hh:186
Queue< QueuedInst, ReportTraitsAdaptor< QueuedInst > > * inFlightInsts
In-order instructions either in FUs or the LSQ.
Definition: execute.hh:175
DrainState drainState
State progression for draining NotDraining -> ...
Definition: execute.hh:205
InstSeqNum lastPredictionSeqNum
A prediction number for use where one isn't available from an instruction.
Definition: execute.hh:202
InstSeqNum streamSeqNum
Source of sequence number for instuction streams.
Definition: execute.hh:196
Queue< QueuedInst, ReportTraitsAdaptor< QueuedInst > > * inFUMemInsts
Memory ref instructions still in the FUs.
Definition: execute.hh:178
statistics::Vector2d committedControl
Number of branches commited.
Definition: stats.hh:86
statistics::Scalar numFetchSuspends
Number of times fetch was asked to suspend by Execute.
Definition: stats.hh:73
statistics::Vector2d committedInstType
Number of instructions by type (OpClass)
Definition: stats.hh:83
statistics::Scalar numOps
Number of simulated insts and microops.
Definition: stats.hh:67
statistics::Scalar numInsts
Number of simulated instructions.
Definition: stats.hh:64
statistics::Scalar numDiscardedOps
Number of ops discarded before committing.
Definition: stats.hh:70

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