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"
65 const BaseMinorCPUParams ¶ms,
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",
85 params.executeMaxAccessesInMemory,
86 params.executeMemoryWidth,
87 params.executeLSQRequestsQueueSize,
88 params.executeLSQTransfersQueueSize,
89 params.executeLSQStoreBufferSize,
90 params.executeLSQMaxStoreBufferStoresPerCycle),
91 executeInfo(params.numThreads,
98 fatal(
"%s: executeCommitLimit must be >= 1 (%d)\n", name_,
103 fatal(
"%s: executeCommitLimit must be >= 1 (%d)\n", name_,
108 fatal(
"%s: executeMemoryIssueLimit must be >= 1 (%d)\n", name_,
113 fatal(
"%s: executeMemoryCommitLimit (%d) must be <="
114 " executeCommitLimit (%d)\n",
118 if (params.executeInputBufferSize < 1) {
119 fatal(
"%s: executeInputBufferSize must be >= 1 (%d)\n", name_,
120 params.executeInputBufferSize);
123 if (params.executeInputBufferSize < 1) {
124 fatal(
"%s: executeInputBufferSize must be >= 1 (%d)\n", name_,
125 params.executeInputBufferSize);
131 unsigned int total_slots = 0;
135 std::ostringstream fu_name;
141 total_slots += fu_description->
opLat;
143 fu_name << name_ <<
".fu." <<
i;
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;
158 static_cast<OpClass
>(op_class)))
166 warn(
"No functional unit for OpClass %s\n",
167 enums::OpClassStrings[op_class]);
172 for (
ThreadID tid = 0; tid < params.numThreads; tid++) {
173 std::string tid_str = std::to_string(tid);
178 name_ +
".inputBuffer" + tid_str,
"insts",
179 params.executeInputBufferSize));
181 const auto ®Classes =
cpu.
threads[tid]->getIsaPtr()->regClasses();
184 scoreboard.emplace_back(name_ +
".scoreboard" + tid_str, regClasses);
189 name_ +
".inFlightInsts" + tid_str,
"insts", total_slots);
193 name_ +
".inFUMemInsts" + tid_str,
"insts", total_slots);
223 const std::unique_ptr<PCStateBase> pc_before(inst->pc->clone());
224 std::unique_ptr<PCStateBase> target(thread->
pcState().
clone());
230 inst->isLastOpInInst() &&
231 (inst->staticInst->isSerializeAfter() ||
232 inst->staticInst->isSquashAfter());
235 *pc_before, *target, (force_branch ?
" (forcing)" :
""));
238 bool must_branch = *pc_before != *target ||
246 inst->staticInst->advancePC(*target);
250 *pc_before, *target);
253 if (inst->predictedTaken && !force_branch) {
259 " none happened inst: %s\n",
260 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
264 }
else if (*inst->predictedTarget == *target) {
269 DPRINTF(
Branch,
"Predicted a branch from 0x%x to 0x%x correctly"
271 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
278 " but got the wrong target (actual: 0x%x) inst: %s\n",
279 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
280 target->instAddr(), *inst);
284 }
else if (must_branch) {
286 DPRINTF(
Branch,
"Unpredicted branch from 0x%x to 0x%x inst: %s\n",
287 inst->pc->instAddr(), target->instAddr(), *inst);
316 (inst->isBubble() ?
executeInfo[tid].lastPredictionSeqNum
317 : inst->id.predictionSeqNum),
328 ThreadID thread_id = inst->id.threadId;
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();
342 bool use_context_predicate =
true;
344 if (inst->translationFault !=
NoFault) {
346 DPRINTF(MinorMem,
"Completing fault from DTLB access: %s\n",
347 inst->translationFault->name());
349 if (inst->staticInst->isPrefetch()) {
350 DPRINTF(MinorMem,
"Not taking fault on prefetch: %s\n",
351 inst->translationFault->name());
356 fault = inst->translationFault;
358 fault->invoke(thread, inst->staticInst);
360 }
else if (!packet) {
361 DPRINTF(MinorMem,
"Completing failed request inst: %s\n",
363 use_context_predicate =
false;
365 inst->staticInst->completeAcc(
nullptr, &context, inst->traceData);
366 }
else if (packet->
isError()) {
367 DPRINTF(MinorMem,
"Trying to commit error response: %s\n",
370 fatal(
"Received error response packet for inst: %s\n", *inst);
371 }
else if (is_store || is_load || is_prefetch || is_atomic) {
374 DPRINTF(MinorMem,
"Memory response inst: %s addr: 0x%x size: %d\n",
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]));
383 fault = inst->staticInst->completeAcc(packet, &context,
388 DPRINTF(MinorMem,
"Fault in memory completeAcc: %s\n",
390 fault->invoke(thread, inst->staticInst);
398 fatal(
"There should only ever be reads, "
399 "writes or faults at this point\n");
404 if (inst->traceData) {
405 inst->traceData->setPredicate((use_context_predicate ?
424 DPRINTF(MinorInterrupt,
"Considering interrupt status from PC: %s\n",
436 DPRINTF(MinorInterrupt,
"Invoking interrupt: %s to PC: %s\n",
451 bool &passed_predicate,
Fault &fault)
456 passed_predicate =
false;
464 std::unique_ptr<PCStateBase> old_pc(thread->
pcState().
clone());
468 DPRINTF(MinorExecute,
"Initiating memRef inst: %s\n", *inst);
470 Fault init_fault = inst->staticInst->initiateAcc(&context,
475 assert(inst->translationFault !=
NoFault);
481 inst->translationFault =
NoFault;
486 DPRINTF(MinorExecute,
"Fault on memory inst: %s"
487 " initiateAcc: %s\n", *inst, init_fault->name());
493 DPRINTF(MinorMem,
"No memory access for inst: %s\n", *inst);
500 inst->traceData->setPredicate(passed_predicate);
526 unsigned int ret =
index + 1;
528 if (ret == cycle_size)
541 ret = cycle_size - 1;
557 unsigned int fu_index = 0;
566 unsigned num_insts_issued = 0;
569 unsigned num_mem_insts_issued = 0;
573 Fault fault = inst->fault;
574 bool discarded =
false;
575 bool issued_mem_ref =
false;
577 if (inst->isBubble()) {
583 DPRINTF(MinorExecute,
"Discarding inst: %s from suspended"
588 }
else if (inst->id.streamSeqNum != thread.
streamSeqNum) {
589 DPRINTF(MinorExecute,
"Discarding inst: %s as its stream"
590 " state was unexpected, expected: %d\n",
607 DPRINTF(MinorExecute,
"Trying to issue inst: %s to FU: %d\n",
614 bool fu_is_capable = (!inst->isFault() ?
615 fu->provides(inst->staticInst->opClass()) :
true);
617 if (inst->isNoCostInst()) {
632 inst->extraCommitDelay =
Cycles(0);
633 inst->extraCommitDelayExpr = NULL;
642 }
else if (!fu_is_capable ||
fu->alreadyPushed()) {
644 if (!fu_is_capable) {
645 DPRINTF(MinorExecute,
"Can't issue as FU: %d isn't"
646 " capable\n", fu_index);
648 DPRINTF(MinorExecute,
"Can't issue as FU: %d is"
649 " already busy\n", fu_index);
651 }
else if (
fu->stalled) {
652 DPRINTF(MinorExecute,
"Can't issue inst: %s into FU: %d,"
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());
661 fu->findTiming(inst->staticInst) : NULL);
668 &(
fu->cantForwardFromFUIndices);
671 DPRINTF(MinorExecute,
"Can't issue inst: %s as extra"
672 " decoding is suppressing it\n",
674 }
else if (!
scoreboard[thread_id].canInstIssue(inst,
675 src_latencies, cant_forward_from_fu_indices,
678 DPRINTF(MinorExecute,
"Can't issue inst: %s yet\n",
682 DPRINTF(MinorExecute,
"Issuing inst: %s"
683 " into FU %d\n", *inst,
687 TimingExpr *extra_dest_retire_lat_expr = NULL;
693 extra_dest_retire_lat =
695 extra_dest_retire_lat_expr =
701 issued_mem_ref = inst->isMemRef();
706 inst->fuIndex = fu_index;
707 inst->extraCommitDelay = extra_dest_retire_lat;
708 inst->extraCommitDelayExpr =
709 extra_dest_retire_lat_expr;
711 if (issued_mem_ref) {
716 inst->instToWaitFor =
717 scoreboard[thread_id].execSeqNumToWaitFor(inst,
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,
729 inst->instToWaitFor =
732 DPRINTF(MinorExecute,
"Memory ref inst:"
733 " %s must wait for inst %d(exec)"
735 *inst, inst->instToWaitFor);
738 inst->canEarlyIssue =
true;
742 DPRINTF(MinorExecute,
"Pushing mem inst: %s\n",
756 fu->description.opLat +
757 extra_dest_retire_lat +
760 issued_mem_ref && extra_assumed_lat ==
Cycles(0));
774 DPRINTF(MinorExecute,
"Didn't issue inst: %s\n", *inst);
780 if (debug::MinorTrace && !inst->isBubble()) {
781 inst->minorTraceInst(*
this);
785 if (!discarded && inst->isInst() &&
786 inst->staticInst->isFullMemBarrier())
788 DPRINTF(MinorMem,
"Issuing memory barrier inst: %s\n", *inst);
793 inst->traceData->setWhen(
curTick());
797 num_mem_insts_issued++;
799 if (!discarded && !inst->isBubble()) {
803 DPRINTF(MinorExecute,
"Reached inst issue limit\n");
807 DPRINTF(MinorExecute,
"Stepping to next inst inputIndex: %d\n",
819 DPRINTF(MinorExecute,
"Wrapping\n");
830 return num_insts_issued;
837 unsigned int num_pc_event_checks = 0;
843 cpu.
threads[thread_id]->pcEventQueue.service(oldPC, thread);
844 num_pc_event_checks++;
847 if (num_pc_event_checks > 1) {
852 return num_pc_event_checks > 1;
858 assert(!inst->isFault());
864 if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop())
878 ->committedInstType[inst->staticInst->opClass()]++;
882 inst->traceData->setCPSeq(thread->
numOp);
890 bool &completed_mem_issue)
892 ThreadID thread_id = inst->id.threadId;
895 bool completed_inst =
true;
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()) {
908 DPRINTF(MinorExecute,
"Fault inst reached Execute: %s\n",
909 inst->fault->name());
912 inst->fault->invoke(thread, NULL);
915 }
else if (inst->staticInst->isMemRef()) {
928 bool predicate_passed =
false;
930 predicate_passed, fault);
932 if (completed_mem_inst && fault !=
NoFault) {
933 if (early_memory_issue) {
934 DPRINTF(MinorExecute,
"Fault in early executing inst: %s\n",
938 inst->canEarlyIssue =
false;
941 completed_inst =
false;
943 DPRINTF(MinorExecute,
"Fault in execute: %s\n",
945 fault->invoke(thread, NULL);
948 completed_inst =
true;
951 completed_inst = completed_mem_inst;
953 completed_mem_issue = completed_inst;
954 }
else if (inst->isInst() && inst->staticInst->isFullMemBarrier() &&
957 DPRINTF(MinorExecute,
"Can't commit data barrier inst: %s yet as"
958 " there isn't space in the store buffer\n", *inst);
960 completed_inst =
false;
961 }
else if (inst->isInst() && inst->staticInst->isQuiesce()
965 completed_inst =
false;
969 DPRINTF(MinorExecute,
"Committing inst: %s\n", *inst);
971 fault = inst->staticInst->execute(&context,
981 if (inst->traceData) {
982 if (debug::ExecFaulting) {
983 inst->traceData->setFaulting(
true);
985 delete inst->traceData;
986 inst->traceData = NULL;
990 DPRINTF(MinorExecute,
"Fault in execute of inst: %s fault: %s\n",
991 *inst, fault->name());
992 fault->invoke(thread, inst->staticInst);
999 if (completed_inst) {
1003 executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum;
1006 if (!inst->isFault() &&
1014 assert(resume_pc.microPC() == 0);
1016 DPRINTF(MinorInterrupt,
"Suspending thread: %d from Execute"
1017 " inst: %s\n", thread_id, *inst);
1026 return completed_inst;
1064 bool completed_inst =
true;
1067 unsigned int num_insts_committed = 0;
1071 unsigned int num_mem_refs_committed = 0;
1073 if (only_commit_microops && !ex_info.
inFlightInsts->empty()) {
1074 DPRINTF(MinorInterrupt,
"Only commit microops %s %d\n",
1086 if (only_commit_microops) {
1087 DPRINTF(MinorInterrupt,
"Committing tail of insts before"
1095 head_inflight_inst->
inst->id.execSeqNum;
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;
1109 completed_inst =
false;
1121 DPRINTF(MinorExecute,
"Trying to commit canCommitInsts: %d\n",
1131 }
else if (mem_response &&
1135 discard_inst = inst->id.streamSeqNum !=
1138 DPRINTF(MinorExecute,
"Trying to commit mem response: %s\n",
1143 DPRINTF(MinorExecute,
"Discarding mem inst: %s as its"
1144 " stream state was unexpected, expected: %d\n",
1150 committed_inst =
true;
1153 completed_mem_ref =
true;
1154 completed_inst =
true;
1155 }
else if (can_commit_insts) {
1160 bool try_to_commit =
false;
1172 DPRINTF(MinorExecute,
"Trying to commit from mem FUs\n");
1181 if (!fu_inst->isBubble() &&
1183 fu_inst->canEarlyIssue &&
1185 head_exec_seq_num > fu_inst->instToWaitFor)
1187 DPRINTF(MinorExecute,
"Issuing mem ref early"
1188 " inst: %s instToWaitFor: %d\n",
1189 *(fu_inst), fu_inst->instToWaitFor);
1192 try_to_commit =
true;
1193 early_memory_issue =
true;
1194 completed_inst =
true;
1199 if (!completed_inst && inst->isNoCostInst()) {
1200 DPRINTF(MinorExecute,
"Committing no cost inst: %s", *inst);
1202 try_to_commit =
true;
1203 completed_inst =
true;
1208 if (!completed_inst && !inst->inLSQ) {
1209 DPRINTF(MinorExecute,
"Trying to commit from FUs\n");
1218 if (fu_inst.
inst->isBubble()) {
1220 completed_inst =
false;
1221 }
else if (fu_inst_seq_num != head_exec_seq_num) {
1227 }
else if (fu_inst.
inst->id == inst->id) {
1231 try_to_commit =
true;
1232 completed_inst =
true;
1236 if (try_to_commit) {
1237 discard_inst = inst->id.streamSeqNum !=
1242 if (!discard_inst) {
1248 if (inst->extraCommitDelayExpr) {
1249 DPRINTF(MinorExecute,
"Evaluating expression for"
1250 " extra commit delay inst: %s\n", *inst);
1257 uint64_t extra_delay = inst->extraCommitDelayExpr->
1260 DPRINTF(MinorExecute,
"Extra commit delay expr"
1261 " result: %d\n", extra_delay);
1263 if (extra_delay < 128) {
1264 inst->extraCommitDelay +=
Cycles(extra_delay);
1266 DPRINTF(MinorExecute,
"Extra commit delay was"
1267 " very long: %d\n", extra_delay);
1269 inst->extraCommitDelayExpr = NULL;
1274 if (inst->extraCommitDelay !=
Cycles(0)) {
1276 inst->extraCommitDelay;
1277 inst->extraCommitDelay =
Cycles(0);
1282 if (!inst->isFault() && inst->isMemRef() &&
1284 inst->id.execSeqNum &&
1287 DPRINTF(MinorExecute,
"Not committing inst: %s yet"
1288 " as there are incomplete barriers in flight\n",
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;
1298 early_memory_issue, branch, fault,
1299 committed_inst, issued_mem_ref);
1303 completed_inst =
true;
1306 if (completed_inst) {
1312 DPRINTF(MinorExecute,
"Unstalling %d for inst %s\n", inst->fuIndex, inst->id);
1313 funcUnits[inst->fuIndex]->stalled =
false;
1318 DPRINTF(MinorExecute,
"No instructions to commit\n");
1319 completed_inst =
false;
1323 assert(!(discard_inst && !completed_inst));
1328 DPRINTF(MinorExecute,
"Discarding inst: %s as its stream"
1329 " state was unexpected, expected: %d\n",
1338 if (issued_mem_ref) {
1345 if (completed_inst && inst->isMemRef()) {
1355 if (completed_inst && !(issued_mem_ref && fault ==
NoFault)) {
1357 DPRINTF(MinorExecute,
"Completed inst: %s\n", *inst);
1361 inst->isLastOpInInst();
1372 if (inst->isInst() && inst->staticInst->isFullMemBarrier()) {
1373 DPRINTF(MinorMem,
"Completing memory barrier"
1374 " inst: %s committed: %d\n", *inst, committed_inst);
1378 scoreboard[thread_id].clearInstDests(inst, inst->isMemRef());
1382 if (committed_inst) {
1383 bool is_no_cost_inst = inst->isNoCostInst();
1387 if (debug::MinorTrace && !is_no_cost_inst)
1390 if (!is_no_cost_inst)
1391 num_insts_committed++;
1394 DPRINTF(MinorExecute,
"Reached inst commit limit\n");
1398 if (inst->traceData) {
1400 inst->traceData->setWhen(
curTick());
1401 inst->traceData->dump();
1404 if (completed_mem_ref)
1405 num_mem_refs_committed++;
1408 DPRINTF(MinorExecute,
"Reached mem ref commit limit\n");
1416 return executeInfo[thread_id].lastCommitWasEndOfMacroop &&
1423 if (!
inp.outputWire->isBubble())
1428 unsigned int num_issued = 0;
1435 bool interrupted =
false;
1444 DPRINTF(MinorInterrupt,
"Execute skipping a cycle to allow old"
1445 " branch to complete\n");
1452 DPRINTF(MinorExecute,
"Attempting to commit [tid:%d]\n",
1459 commit(commit_tid,
true,
false, branch);
1470 commit(commit_tid,
false,
true, branch);
1475 DPRINTF(MinorExecute,
"Committing micro-ops for interrupt[tid:%d]\n",
1477 bool only_commit_microops = interrupted &&
1479 commit(commit_tid, only_commit_microops,
false, branch);
1497 DPRINTF(MinorExecute,
"Attempting to issue [tid:%d]\n",
1499 num_issued =
issue(issue_tid);
1507 bool can_issue_next =
false;
1513 unsigned int input_index =
executeInfo[tid].inputIndex;
1515 if (inst->isFault()) {
1516 can_issue_next =
true;
1517 }
else if (!inst->isBubble()) {
1518 next_issuable_insts.push_back(inst);
1523 bool becoming_stalled =
true;
1533 if (
fu->occupancy !=0 && !
fu->stalled)
1534 becoming_stalled =
false;
1540 for (
auto inst : next_issuable_insts) {
1541 if (!
fu->stalled &&
fu->provides(inst->staticInst->opClass()) &&
1542 scoreboard[inst->id.threadId].canInstIssue(inst,
1545 can_issue_next =
true;
1551 bool head_inst_might_commit =
false;
1555 if (!info.inFlightInsts->empty()) {
1556 const QueuedInst &head_inst = info.inFlightInsts->front();
1558 if (head_inst.
inst->isNoCostInst()) {
1559 head_inst_might_commit =
true;
1563 fu->front().inst->id == head_inst.
inst->id) ||
1566 head_inst_might_commit =
true;
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)" :
""),
1579 (interrupted ?
" (interrupted)" :
""));
1583 !becoming_stalled ||
1585 head_inst_might_commit ||
1589 if (!need_to_tick) {
1590 DPRINTF(Activity,
"The next cycle might be skippable as there are no"
1591 " advanceable FUs\n");
1603 if (!
inp.outputWire->isBubble())
1615 bool thread_interrupted =
false;
1622 interrupted = interrupted || thread_interrupted;
1624 DPRINTF(MinorInterrupt,
"No interrupt controller\n");
1626 DPRINTF(MinorInterrupt,
"[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n",
1656 std::ostringstream insts;
1657 std::ostringstream stalled;
1659 executeInfo[0].instsBeingCommitted.reportData(insts);
1668 stalled << (
funcUnits[
i]->stalled ?
'1' :
'E');
1675 " stalled=%s drainState=%d isInbetweenInsts=%d\n",
1692 case enums::SingleThreaded:
1694 case enums::RoundRobin:
1701 panic(
"Invalid thread policy");
1704 for (
auto tid : priority_list) {
1707 if (can_commit_insts) {
1711 can_commit_insts = can_commit_insts &&
1715 bool can_transfer_mem_inst =
false;
1721 can_transfer_mem_inst =
1722 !fu_inst->isBubble() &&
1723 fu_inst->id.threadId == tid &&
1725 fu_inst->canEarlyIssue &&
1726 inst->id.execSeqNum > fu_inst->instToWaitFor;
1730 if (can_commit_insts && !can_transfer_mem_inst &&
1734 can_execute_fu_inst = !fu_inst.
inst->isBubble() &&
1735 fu_inst.
inst->id == inst->id;
1738 can_commit_insts = can_commit_insts &&
1739 (can_transfer_mem_inst || can_execute_fu_inst);
1744 if (can_commit_insts) {
1759 case enums::SingleThreaded:
1761 case enums::RoundRobin:
1768 panic(
"Invalid thread scheduling policy.");
1771 for (
auto tid : priority_list) {
1784 DPRINTF(Drain,
"MinorExecute drainResume\n");
1798 os <<
"NotDraining";
1801 os <<
"DrainCurrentInst";
1804 os <<
"DrainHaltFetch";
1807 os <<
"DrainAllInsts";
1810 os <<
"Drain-" <<
static_cast<int>(
state);
1820 DPRINTF(Drain,
"setDrainState[%d]: %s\n", thread_id,
state);
1827 DPRINTF(Drain,
"MinorExecute drain\n");
1875 return inst->id.streamSeqNum ==
executeInfo[inst->id.threadId].streamSeqNum;
1883 if (!
executeInfo[inst->id.threadId].inFlightInsts->empty())
1884 ret =
executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id;
void activity()
Records that there is activity this cycle.
BaseInterrupts * getInterruptController(ThreadID tid)
virtual ThreadContext * getContext(int tn)
Given a thread num get tho thread context for it.
std::vector< std::unique_ptr< CommitCPUStats > > commitStats
gem5::BaseCPU::BaseCPUStats baseStats
ThreadID numThreads
Number of threads we're actually simulating (<= SMT_MAX_THREADS).
std::vector< std::unique_ptr< ExecuteCPUStats > > executeStats
bool checkInterrupts(ThreadID tid) const
std::vector< std::unique_ptr< FetchCPUStats > > fetchStats
virtual void probeInstCommit(const StaticInstPtr &inst, Addr pc)
Helper method to trigger PMU probes for a committed instruction.
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.
Provide a non-protected base class for Minor's Ports as derived classes are created by Fetch1 and Exe...
MinorCPU is an in-order CPU model with four fixed pipeline stages:
minor::MinorActivityRecorder * activityRecorder
Activity recording for pipeline.
void wakeupOnEvent(unsigned int stage_id)
Interface for stages to signal that they have become active after a callback or eventq event where th...
std::vector< ThreadID > randomPriority()
std::vector< ThreadID > roundRobinPriority(ThreadID priority)
Thread scheduling utility functions.
enums::ThreadPolicy threadPolicy
Thread Scheduling Policy (RoundRobin, Random, etc)
std::vector< minor::MinorThread * > threads
These are thread state-representing objects for this CPU.
std::vector< MinorFU * > funcUnits
Extra timing capability to allow individual ops to have their source register dependency latencies tw...
TimingExpr * extraCommitLatExpr
std::vector< Cycles > srcRegsRelativeLats
Cycle offsets from the scoreboard delivery times of register values for each of this instruction's so...
Cycles extraAssumedLat
Extra delay that results should show in the scoreboard after leaving the pipeline.
bool suppress
If true, instructions matching this mask/match should not be issued in this FU.
Cycles extraCommitLat
Extra latency that the instruction should spend at the end of the pipeline.
A functional unit that can execute any of opClasses operations with a single op(eration)Lat(ency) and...
Cycles opLat
Delay from issuing the operation, to it reaching the end of the associated pipeline.
Interface for things with names.
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
virtual PCStateBase * clone() const =0
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
const T * getConstPtr() const
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.
ThreadContext is the external interface to all thread state for anything outside of the CPU.
@ Suspended
Temporarily inactive.
virtual const PCStateBase & pcState() const =0
virtual Status status() const =0
Object to gather the visible context for evaluation.
Forward data betwen Execute and Fetch1 carrying change-of-address/stream information.
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...
@ BadlyPredictedBranchTarget
@ CorrectlyPredictedBranch
bool isStreamChange() const
As static isStreamChange but on this branch data.
static BranchData bubble()
BubbleIF interface.
ExecContext bears the exec_context interface for Minor.
bool readMemAccPredicate() const override
bool readPredicate() const override
bool setTraceTimeOnIssue
Modify instruction trace times on issue.
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...
bool processMoreThanOneInput
If true, more than one input line can be processed each cycle if there is room to execute more instru...
LSQ lsq
Dcache port to pass on to the CPU.
void evaluate()
Pass on input/buffer data to the output if you can.
unsigned int commitLimit
Number of instructions that can be committed per cycle.
void popInput(ThreadID tid)
Pop an element off the input buffer, if there are any.
unsigned int memoryCommitLimit
Number of memory instructions that can be committed per cycle.
bool executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, bool &failed_predicate, Fault &fault)
Execute a memory reference instruction.
unsigned int issue(ThreadID thread_id)
Try and issue instructions from the inputBuffer.
unsigned int noCostFUIndex
The FU index of the non-existent costless FU for instructions which pass the MinorDynInst::isNoCostIn...
unsigned int memoryIssueLimit
Number of memory ops that can be issued per cycle.
Latch< ForwardInstData >::Output inp
Input port carrying instructions from Decode.
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.
MinorCPU & cpu
Pointer back to the containing CPU.
ThreadID getIssuingThread()
unsigned int drain()
Like the drain interface on SimObject.
unsigned int issueLimit
Number of instructions that can be issued per cycle.
bool instIsRightStream(MinorDynInstPtr inst)
Does the given instruction have the right stream sequence number to be committed?
void setDrainState(ThreadID thread_id, DrainState state)
Set the drain state (with useful debugging messages)
bool setTraceTimeOnCommit
Modify instruction trace times on commit.
ThreadID checkInterrupts(BranchData &branch, bool &interrupted)
Check all threads for possible interrupts.
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...
DrainState
Stage cycle-by-cycle state.
MinorFUPool & fuDescriptions
Descriptions of the functional units we want to generate.
bool allowEarlyMemIssue
Allow mem refs to leave their FUs before reaching the head of the in flight insts queue if their depe...
unsigned int numFuncUnits
Number of functional units to produce.
std::vector< FUPipeline * > funcUnits
The execution functional units.
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...
bool commitInst(MinorDynInstPtr inst, bool early_memory_issue, BranchData &branch, Fault &fault, bool &committed, bool &completed_mem_issue)
Commit a single instruction.
bool hasInterrupt(ThreadID thread_id)
Checks if a specific thread has an interrupt.
bool isInterrupted(ThreadID thread_id) const
Has an interrupt been raised.
bool isInbetweenInsts(ThreadID thread_id) const
Are we between instructions? Can we be interrupted?
Execute(const std::string &name_, MinorCPU &cpu_, const BaseMinorCPUParams ¶ms, Latch< ForwardInstData >::Output inp_, Latch< BranchData >::Input out_)
ThreadID interruptPriority
std::vector< Scoreboard > scoreboard
Scoreboard of instruction dependencies.
bool takeInterrupt(ThreadID thread_id, BranchData &branch)
Act on an interrupt.
std::vector< ExecuteThreadInfo > executeInfo
std::vector< InputBuffer< ForwardInstData > > inputBuffer
void doInstCommitAccounting(MinorDynInstPtr inst)
Do the stats handling and instruction count and PC event events related to the new instruction/op cou...
MinorCPU::MinorCPUPort & getDcachePort()
Returns the DcachePort owned by this Execute to pass upwards.
bool instIsHeadInst(MinorDynInstPtr inst)
Returns true if the given instruction is at the head of the inFlightInsts instruction queue.
const ForwardInstData * getInput(ThreadID tid)
Get a piece of data to work on from the inputBuffer, or 0 if there is no data.
Latch< BranchData >::Input out
Input port carrying stream changes to Fetch1.
bool isDrained()
After thread suspension, has Execute been drained of in-flight instructions and memory accesses.
ThreadID getCommittingThread()
Use the current threading policy to determine the next thread to decode from.
bool tryPCEvents(ThreadID thread_id)
Try to act on PC-related events.
A functional unit configured from a MinorFU object.
void advance()
Step the pipeline.
Forward flowing data between Fetch2,Decode,Execute carrying a packet of instructions of a width appro...
bool isBubble() const
BubbleIF interface.
MinorDynInstPtr insts[MAX_FORWARD_INSTS]
Array of carried insts, ref counted.
unsigned int width() const
Number of instructions carried by this object.
Derived SenderState to carry data access info.
bool needsToBeSentToStoreBuffer()
This request, once processed by the requests/transfers queues, will need to go to the store buffer.
bool needsToTick()
May need to be ticked next cycle as one of the queues contains an actionable transfers or address tra...
void issuedMemBarrierInst(MinorDynInstPtr inst)
A memory barrier instruction has been issued, remember its execSeqNum that we can avoid issuing memor...
void sendStoreToStoreBuffer(LSQRequestPtr request)
A store has been committed, please move it to the store buffer.
void pushFailedRequest(MinorDynInstPtr inst)
Push a predicate failed-representing request into the queues just to maintain commit order.
bool canPushIntoStoreBuffer() const
Must check this before trying to insert into the store buffer.
bool accessesInFlight() const
Are there any accesses other than normal cached loads in the memory system or having received respons...
MinorCPU::MinorCPUPort & getDcachePort()
Return the raw-bindable port.
void step()
Step checks the queues to see if their are issuable transfers which were not otherwise picked up by t...
InstSeqNum getLastMemBarrier(ThreadID thread_id) const
Get the execSeqNum of the last issued memory barrier.
void completeMemBarrierInst(MinorDynInstPtr inst, bool committed)
Complete a barrier instruction.
void popResponse(LSQRequestPtr response)
Sanity check and pop the head response.
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...
bool isDrained()
Is there nothing left in the LSQ.
bool canRequest()
Is their space in the request queue to be able to push a request by issuing an isMemRef instruction.
static MinorDynInstPtr bubble()
There is a single bubble inst.
Wrapper for a queue type to act as a pipeline stage input queue.
Container class to box instructions in the FUs to make those queues have correct bubble behaviour whe...
...ReportTraits are trait classes with the same functionality as ReportIF, but with elements explicit...
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.
#define panic(...)
This implements a cprintf based panic() function.
#define fatal(...)
This implements a cprintf based fatal() function.
ExecContext bears the exec_context interface for Minor.
A load/store queue that allows outstanding reads and writes.
unsigned int cyclicIndexInc(unsigned int index, unsigned int cycle_size)
Increment a cyclic buffer index for indices [0, cycle_size-1].
unsigned int cyclicIndexDec(unsigned int index, unsigned int cycle_size)
Decrement a cyclic buffer index for indices [0, cycle_size-1].
std::ostream & operator<<(std::ostream &os, const InstId &id)
Print this id in the usual slash-separated format expected by MinorTrace.
void minorTrace(const char *fmt, Args ...args)
DPRINTFN for MinorTrace reporting.
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
std::shared_ptr< FaultBase > Fault
int16_t ThreadID
Thread index/ID type.
const ThreadID InvalidThreadID
static const OpClass Num_OpClasses
Tick curTick()
The universal simulation clock.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
constexpr decltype(nullptr) NoFault
Minor contains all the definitions within the MinorCPU apart from the CPU class itself.
statistics::Scalar numInsts
statistics::Scalar numOps
Stat for number ops (including micro ops) committed.
statistics::Scalar numInsts
Stat for number instructions committed.
Counter numInst
Number of instructions committed.
Counter numOp
Number of ops (including micro ops) committed.
gem5::ThreadState::ThreadStateStats threadStats
unsigned int inputIndex
Index that we've completed upto in getInput data.
ForwardInstData instsBeingCommitted
Structure for reporting insts currently being processed/retired for MinorTrace.
bool lastCommitWasEndOfMacroop
The last commit was the end of a full instruction so an interrupt can safely happen.
Queue< QueuedInst, ReportTraitsAdaptor< QueuedInst > > * inFlightInsts
In-order instructions either in FUs or the LSQ.
DrainState drainState
State progression for draining NotDraining -> ... -> DrainAllInsts.
InstSeqNum lastPredictionSeqNum
A prediction number for use where one isn't available from an instruction.
InstSeqNum streamSeqNum
Source of sequence number for instuction streams.
Queue< QueuedInst, ReportTraitsAdaptor< QueuedInst > > * inFUMemInsts
Memory ref instructions still in the FUs.