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

Generated on Sun Jul 30 2023 01:56:52 for gem5 by doxygen 1.8.17