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"
64 const BaseMinorCPUParams ¶ms,
82 lsq(name_ +
".lsq", name_ +
".dcache_port", cpu_, *this,
83 params.executeMaxAccessesInMemory, params.executeMemoryWidth,
84 params.executeLSQRequestsQueueSize,
85 params.executeLSQTransfersQueueSize,
86 params.executeLSQStoreBufferSize,
87 params.executeLSQMaxStoreBufferStoresPerCycle),
96 fatal(
"%s: executeCommitLimit must be >= 1 (%d)\n", name_,
101 fatal(
"%s: executeCommitLimit must be >= 1 (%d)\n", name_,
106 fatal(
"%s: executeMemoryIssueLimit must be >= 1 (%d)\n", name_,
111 fatal(
"%s: executeMemoryCommitLimit (%d) must be <="
112 " executeCommitLimit (%d)\n",
116 if (params.executeInputBufferSize < 1) {
117 fatal(
"%s: executeInputBufferSize must be >= 1 (%d)\n", name_,
118 params.executeInputBufferSize);
121 if (params.executeInputBufferSize < 1) {
122 fatal(
"%s: executeInputBufferSize must be >= 1 (%d)\n", name_,
123 params.executeInputBufferSize);
129 unsigned int total_slots = 0;
133 std::ostringstream fu_name;
139 total_slots += fu_description->
opLat;
141 fu_name << name_ <<
".fu." <<
i;
149 for (
int op_class = No_OpClass + 1; op_class <
Num_OpClasses; op_class++) {
150 bool found_fu =
false;
151 unsigned int fu_index = 0;
156 static_cast<OpClass
>(op_class)))
164 warn(
"No functional unit for OpClass %s\n",
165 enums::OpClassStrings[op_class]);
170 for (
ThreadID tid = 0; tid < params.numThreads; tid++) {
171 std::string tid_str = std::to_string(tid);
176 name_ +
".inputBuffer" + tid_str,
"insts",
177 params.executeInputBufferSize));
179 const auto ®Classes =
cpu.threads[tid]->getIsaPtr()->regClasses();
182 scoreboard.emplace_back(name_ +
".scoreboard" + tid_str, regClasses);
187 name_ +
".inFlightInsts" + tid_str,
"insts", total_slots);
191 name_ +
".inFUMemInsts" + tid_str,
"insts", total_slots);
221 const std::unique_ptr<PCStateBase> pc_before(inst->pc->clone());
222 std::unique_ptr<PCStateBase> target(thread->
pcState().
clone());
228 inst->isLastOpInInst() &&
229 (inst->staticInst->isSerializeAfter() ||
230 inst->staticInst->isSquashAfter());
233 *pc_before, *target, (force_branch ?
" (forcing)" :
""));
236 bool must_branch = *pc_before != *target ||
244 inst->staticInst->advancePC(*target);
248 *pc_before, *target);
251 if (inst->predictedTaken && !force_branch) {
257 " none happened inst: %s\n",
258 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
262 }
else if (*inst->predictedTarget == *target) {
267 DPRINTF(
Branch,
"Predicted a branch from 0x%x to 0x%x correctly"
269 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
276 " but got the wrong target (actual: 0x%x) inst: %s\n",
277 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
278 target->instAddr(), *inst);
282 }
else if (must_branch) {
284 DPRINTF(
Branch,
"Unpredicted branch from 0x%x to 0x%x inst: %s\n",
285 inst->pc->instAddr(), target->instAddr(), *inst);
314 (inst->isBubble() ?
executeInfo[tid].lastPredictionSeqNum
315 : inst->id.predictionSeqNum),
326 ThreadID thread_id = inst->id.threadId;
333 bool is_load = inst->staticInst->isLoad();
334 bool is_store = inst->staticInst->isStore();
335 bool is_atomic = inst->staticInst->isAtomic();
336 bool is_prefetch = inst->staticInst->isDataPrefetch();
340 bool use_context_predicate =
true;
342 if (inst->translationFault !=
NoFault) {
344 DPRINTF(MinorMem,
"Completing fault from DTLB access: %s\n",
345 inst->translationFault->name());
347 if (inst->staticInst->isPrefetch()) {
348 DPRINTF(MinorMem,
"Not taking fault on prefetch: %s\n",
349 inst->translationFault->name());
354 fault = inst->translationFault;
356 fault->invoke(thread, inst->staticInst);
358 }
else if (!packet) {
359 DPRINTF(MinorMem,
"Completing failed request inst: %s\n",
361 use_context_predicate =
false;
363 inst->staticInst->completeAcc(
nullptr, &context, inst->traceData);
364 }
else if (packet->
isError()) {
365 DPRINTF(MinorMem,
"Trying to commit error response: %s\n",
368 fatal(
"Received error response packet for inst: %s\n", *inst);
369 }
else if (is_store || is_load || is_prefetch || is_atomic) {
372 DPRINTF(MinorMem,
"Memory response inst: %s addr: 0x%x size: %d\n",
375 if (is_load && packet->
getSize() > 0) {
376 DPRINTF(MinorMem,
"Memory data[0]: 0x%x\n",
377 static_cast<unsigned int>(packet->
getConstPtr<uint8_t>()[0]));
381 fault = inst->staticInst->completeAcc(packet, &context,
386 DPRINTF(MinorMem,
"Fault in memory completeAcc: %s\n",
388 fault->invoke(thread, inst->staticInst);
393 lsq.sendStoreToStoreBuffer(response);
396 fatal(
"There should only ever be reads, "
397 "writes or faults at this point\n");
400 lsq.popResponse(response);
402 if (inst->traceData) {
403 inst->traceData->setPredicate((use_context_predicate ?
414 return cpu.checkInterrupts(thread_id);
420 DPRINTF(MinorInterrupt,
"Considering interrupt status from PC: %s\n",
421 cpu.getContext(thread_id)->pcState());
423 Fault interrupt =
cpu.getInterruptController(thread_id)->getInterrupt();
427 cpu.getInterruptController(thread_id)->updateIntrInfo();
428 interrupt->invoke(
cpu.getContext(thread_id));
430 assert(!
lsq.accessesInFlight());
432 DPRINTF(MinorInterrupt,
"Invoking interrupt: %s to PC: %s\n",
433 interrupt->name(),
cpu.getContext(thread_id)->pcState());
447 bool &passed_predicate,
Fault &fault)
452 passed_predicate =
false;
454 if (!
lsq.canRequest()) {
460 std::unique_ptr<PCStateBase> old_pc(thread->
pcState().
clone());
464 DPRINTF(MinorExecute,
"Initiating memRef inst: %s\n", *inst);
466 Fault init_fault = inst->staticInst->initiateAcc(&context,
471 assert(inst->translationFault !=
NoFault);
477 inst->translationFault =
NoFault;
482 DPRINTF(MinorExecute,
"Fault on memory inst: %s"
483 " initiateAcc: %s\n", *inst, init_fault->name());
489 DPRINTF(MinorMem,
"No memory access for inst: %s\n", *inst);
496 inst->traceData->setPredicate(passed_predicate);
505 lsq.pushFailedRequest(inst);
522 unsigned int ret =
index + 1;
524 if (ret == cycle_size)
537 ret = cycle_size - 1;
553 unsigned int fu_index = 0;
562 unsigned num_insts_issued = 0;
565 unsigned num_mem_insts_issued = 0;
569 Fault fault = inst->fault;
570 bool discarded =
false;
571 bool issued_mem_ref =
false;
573 if (inst->isBubble()) {
576 }
else if (
cpu.getContext(thread_id)->status() ==
579 DPRINTF(MinorExecute,
"Discarding inst: %s from suspended"
584 }
else if (inst->id.streamSeqNum != thread.
streamSeqNum) {
585 DPRINTF(MinorExecute,
"Discarding inst: %s as its stream"
586 " state was unexpected, expected: %d\n",
603 DPRINTF(MinorExecute,
"Trying to issue inst: %s to FU: %d\n",
610 bool fu_is_capable = (!inst->isFault() ?
611 fu->provides(inst->staticInst->opClass()) :
true);
613 if (inst->isNoCostInst()) {
619 cpu.activityRecorder->activity();
624 Cycles(0),
cpu.getContext(thread_id),
false);
628 inst->extraCommitDelay =
Cycles(0);
629 inst->extraCommitDelayExpr = NULL;
638 }
else if (!fu_is_capable ||
fu->alreadyPushed()) {
640 if (!fu_is_capable) {
641 DPRINTF(MinorExecute,
"Can't issue as FU: %d isn't"
642 " capable\n", fu_index);
644 DPRINTF(MinorExecute,
"Can't issue as FU: %d is"
645 " already busy\n", fu_index);
647 }
else if (
fu->stalled) {
648 DPRINTF(MinorExecute,
"Can't issue inst: %s into FU: %d,"
651 }
else if (!
fu->canInsert()) {
652 DPRINTF(MinorExecute,
"Can't issue inst: %s to busy FU"
653 " for another: %d cycles\n",
654 *inst,
fu->cyclesBeforeInsert());
657 fu->findTiming(inst->staticInst) : NULL);
664 &(
fu->cantForwardFromFUIndices);
667 DPRINTF(MinorExecute,
"Can't issue inst: %s as extra"
668 " decoding is suppressing it\n",
670 }
else if (!
scoreboard[thread_id].canInstIssue(inst,
671 src_latencies, cant_forward_from_fu_indices,
672 cpu.curCycle(),
cpu.getContext(thread_id)))
674 DPRINTF(MinorExecute,
"Can't issue inst: %s yet\n",
678 DPRINTF(MinorExecute,
"Issuing inst: %s"
679 " into FU %d\n", *inst,
682 if (!inst->isFault()) {
683 auto tid = thread_id;
684 if (inst->staticInst->isInteger()) {
685 cpu.executeStats[tid]->numIntAluAccesses++;
687 if (inst->staticInst->isFloating()) {
688 cpu.executeStats[tid]->numFpAluAccesses++;
690 if (inst->staticInst->isVector()) {
691 cpu.executeStats[tid]->numVecAluAccesses++;
695 TimingExpr *extra_dest_retire_lat_expr = NULL;
701 extra_dest_retire_lat =
703 extra_dest_retire_lat_expr =
709 issued_mem_ref = inst->isMemRef();
714 inst->fuIndex = fu_index;
715 inst->extraCommitDelay = extra_dest_retire_lat;
716 inst->extraCommitDelayExpr =
717 extra_dest_retire_lat_expr;
719 if (issued_mem_ref) {
724 inst->instToWaitFor =
725 scoreboard[thread_id].execSeqNumToWaitFor(inst,
726 cpu.getContext(thread_id));
728 if (
lsq.getLastMemBarrier(thread_id) >
731 DPRINTF(MinorExecute,
"A barrier will"
732 " cause a delay in mem ref issue of"
733 " inst: %s until after inst"
734 " %d(exec)\n", *inst,
735 lsq.getLastMemBarrier(thread_id));
737 inst->instToWaitFor =
738 lsq.getLastMemBarrier(thread_id);
740 DPRINTF(MinorExecute,
"Memory ref inst:"
741 " %s must wait for inst %d(exec)"
743 *inst, inst->instToWaitFor);
746 inst->canEarlyIssue =
true;
750 DPRINTF(MinorExecute,
"Pushing mem inst: %s\n",
756 if (!inst->isFault()) {
757 auto opclass = inst->staticInst->opClass();
758 issueStats.issuedInstType[thread_id][opclass]++;
765 cpu.activityRecorder->activity();
770 fu->description.opLat +
771 extra_dest_retire_lat +
773 cpu.getContext(thread_id),
774 issued_mem_ref && extra_assumed_lat ==
Cycles(0));
788 DPRINTF(MinorExecute,
"Didn't issue inst: %s\n", *inst);
794 if (debug::MinorTrace && !inst->isBubble()) {
795 inst->minorTraceInst(*
this);
799 if (!discarded && inst->isInst() &&
800 inst->staticInst->isFullMemBarrier())
802 DPRINTF(MinorMem,
"Issuing memory barrier inst: %s\n", *inst);
803 lsq.issuedMemBarrierInst(inst);
807 inst->traceData->setWhen(
curTick());
811 num_mem_insts_issued++;
813 if (!discarded && !inst->isBubble()) {
817 DPRINTF(MinorExecute,
"Reached inst issue limit\n");
821 DPRINTF(MinorExecute,
"Stepping to next inst inputIndex: %d\n",
833 DPRINTF(MinorExecute,
"Wrapping\n");
844 return num_insts_issued;
851 unsigned int num_pc_event_checks = 0;
857 cpu.threads[thread_id]->pcEventQueue.service(oldPC, thread);
858 num_pc_event_checks++;
861 if (num_pc_event_checks > 1) {
866 return num_pc_event_checks > 1;
872 assert(!inst->isFault());
873 bool is_nop = inst->staticInst->isNop();
874 const ThreadID tid = inst->id.threadId;
880 if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop())
884 cpu.commitStats[tid]->numInsts++;
885 cpu.executeStats[tid]->numInsts++;
886 cpu.baseStats.numInsts++;
888 cpu.commitStats[tid]->numUserInsts++;
892 cpu.commitStats[inst->id.threadId]->numInstsNotNOP++;
902 cpu.commitStats[tid]->numOpsNotNOP++;
905 if (inst->staticInst->isMemRef()) {
906 cpu.executeStats[tid]->numMemRefs++;
907 cpu.commitStats[tid]->numMemRefs++;
910 if (inst->staticInst->isLoad()) {
911 cpu.executeStats[tid]->numLoadInsts++;
912 cpu.commitStats[tid]->numLoadInsts++;
915 if (inst->staticInst->isStore() || inst->staticInst->isAtomic()) {
916 cpu.commitStats[tid]->numStoreInsts++;
918 if (inst->staticInst->isInteger()) {
919 cpu.commitStats[tid]->numIntInsts++;
922 if (inst->staticInst->isFloating()) {
923 cpu.commitStats[tid]->numFpInsts++;
926 if (inst->staticInst->isVector()) {
927 cpu.commitStats[tid]->numVecInsts++;
929 if (inst->staticInst->isControl()) {
930 cpu.executeStats[tid]->numBranches++;
932 if (inst->staticInst->isCall() || inst->staticInst->isReturn()) {
933 cpu.commitStats[tid]->numCallsReturns++;
935 if (inst->staticInst->isCall()) {
936 cpu.commitStats[tid]->functionCalls++;
939 cpu.commitStats[tid]->numOps++;
941 ->committedInstType[inst->staticInst->opClass()]++;
942 cpu.commitStats[tid]->updateComCtrlStats(inst->staticInst);
944 cpu.commitStats[tid]->numUserOps++;
949 inst->traceData->setCPSeq(thread->
numOp);
951 cpu.probeInstCommit(inst->staticInst, inst->pc->instAddr());
957 bool &completed_mem_issue)
959 ThreadID thread_id = inst->id.threadId;
962 bool completed_inst =
true;
970 panic(
"We should never hit the case where we try to commit from a "
971 "suspended thread as the streamSeqNum should not match");
972 }
else if (inst->isFault()) {
975 DPRINTF(MinorExecute,
"Fault inst reached Execute: %s\n",
976 inst->fault->name());
979 inst->fault->invoke(thread, NULL);
982 }
else if (inst->staticInst->isMemRef()) {
995 bool predicate_passed =
false;
997 predicate_passed, fault);
999 if (completed_mem_inst && fault !=
NoFault) {
1000 if (early_memory_issue) {
1001 DPRINTF(MinorExecute,
"Fault in early executing inst: %s\n",
1005 inst->canEarlyIssue =
false;
1008 completed_inst =
false;
1010 DPRINTF(MinorExecute,
"Fault in execute: %s\n",
1012 fault->invoke(thread, NULL);
1015 completed_inst =
true;
1018 completed_inst = completed_mem_inst;
1020 completed_mem_issue = completed_inst;
1021 }
else if (inst->isInst() && inst->staticInst->isFullMemBarrier() &&
1022 !
lsq.canPushIntoStoreBuffer())
1024 DPRINTF(MinorExecute,
"Can't commit data barrier inst: %s yet as"
1025 " there isn't space in the store buffer\n", *inst);
1027 completed_inst =
false;
1028 }
else if (inst->isInst() && inst->staticInst->isQuiesce()
1032 completed_inst =
false;
1036 DPRINTF(MinorExecute,
"Committing inst: %s\n", *inst);
1038 fault = inst->staticInst->execute(&context,
1042 if (inst->traceData)
1048 if (inst->traceData) {
1049 if (debug::ExecFaulting) {
1050 inst->traceData->setFaulting(
true);
1052 delete inst->traceData;
1053 inst->traceData = NULL;
1057 DPRINTF(MinorExecute,
"Fault in execute of inst: %s fault: %s\n",
1058 *inst, fault->name());
1059 fault->invoke(thread, inst->staticInst);
1065 if (completed_inst) {
1069 executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum;
1072 if (!inst->isFault() &&
1078 auto &resume_pc =
cpu.getContext(thread_id)->pcState();
1080 assert(resume_pc.microPC() == 0);
1082 DPRINTF(MinorInterrupt,
"Suspending thread: %d from Execute"
1083 " inst: %s\n", thread_id, *inst);
1085 cpu.fetchStats[thread_id]->numFetchSuspends++;
1092 return completed_inst;
1130 bool completed_inst =
true;
1133 unsigned int num_insts_committed = 0;
1137 unsigned int num_mem_refs_committed = 0;
1139 if (only_commit_microops && !ex_info.
inFlightInsts->empty()) {
1140 DPRINTF(MinorInterrupt,
"Only commit microops %s %d\n",
1152 if (only_commit_microops) {
1153 DPRINTF(MinorInterrupt,
"Committing tail of insts before"
1161 head_inflight_inst->
inst->id.execSeqNum;
1168 bool committed_inst =
false;
1169 bool discard_inst =
false;
1170 bool completed_mem_ref =
false;
1171 bool issued_mem_ref =
false;
1172 bool early_memory_issue =
false;
1175 completed_inst =
false;
1185 (inst->inLSQ ?
lsq.findResponse(inst) : NULL);
1187 DPRINTF(MinorExecute,
"Trying to commit canCommitInsts: %d\n",
1197 }
else if (mem_response &&
1201 discard_inst = inst->id.streamSeqNum !=
1204 DPRINTF(MinorExecute,
"Trying to commit mem response: %s\n",
1209 DPRINTF(MinorExecute,
"Discarding mem inst: %s as its"
1210 " stream state was unexpected, expected: %d\n",
1213 lsq.popResponse(mem_response);
1216 committed_inst =
true;
1219 completed_mem_ref =
true;
1220 completed_inst =
true;
1221 }
else if (can_commit_insts) {
1226 bool try_to_commit =
false;
1238 DPRINTF(MinorExecute,
"Trying to commit from mem FUs\n");
1247 if (!fu_inst->isBubble() &&
1249 fu_inst->canEarlyIssue &&
1251 head_exec_seq_num > fu_inst->instToWaitFor)
1253 DPRINTF(MinorExecute,
"Issuing mem ref early"
1254 " inst: %s instToWaitFor: %d\n",
1255 *(fu_inst), fu_inst->instToWaitFor);
1258 try_to_commit =
true;
1259 early_memory_issue =
true;
1260 completed_inst =
true;
1265 if (!completed_inst && inst->isNoCostInst()) {
1266 DPRINTF(MinorExecute,
"Committing no cost inst: %s", *inst);
1268 try_to_commit =
true;
1269 completed_inst =
true;
1274 if (!completed_inst && !inst->inLSQ) {
1275 DPRINTF(MinorExecute,
"Trying to commit from FUs\n");
1284 if (fu_inst.
inst->isBubble()) {
1286 completed_inst =
false;
1287 }
else if (fu_inst_seq_num != head_exec_seq_num) {
1293 }
else if (fu_inst.
inst->id == inst->id) {
1297 try_to_commit =
true;
1298 completed_inst =
true;
1302 if (try_to_commit) {
1303 discard_inst = inst->id.streamSeqNum !=
1308 if (!discard_inst) {
1314 if (inst->extraCommitDelayExpr) {
1315 DPRINTF(MinorExecute,
"Evaluating expression for"
1316 " extra commit delay inst: %s\n", *inst);
1323 uint64_t extra_delay = inst->extraCommitDelayExpr->
1326 DPRINTF(MinorExecute,
"Extra commit delay expr"
1327 " result: %d\n", extra_delay);
1329 if (extra_delay < 128) {
1330 inst->extraCommitDelay +=
Cycles(extra_delay);
1332 DPRINTF(MinorExecute,
"Extra commit delay was"
1333 " very long: %d\n", extra_delay);
1335 inst->extraCommitDelayExpr = NULL;
1340 if (inst->extraCommitDelay !=
Cycles(0)) {
1341 inst->minimumCommitCycle =
cpu.curCycle() +
1342 inst->extraCommitDelay;
1343 inst->extraCommitDelay =
Cycles(0);
1348 if (!inst->isFault() && inst->isMemRef() &&
1349 lsq.getLastMemBarrier(thread_id) <
1350 inst->id.execSeqNum &&
1351 lsq.getLastMemBarrier(thread_id) != 0)
1353 DPRINTF(MinorExecute,
"Not committing inst: %s yet"
1354 " as there are incomplete barriers in flight\n",
1356 completed_inst =
false;
1357 }
else if (inst->minimumCommitCycle > now) {
1358 DPRINTF(MinorExecute,
"Not committing inst: %s yet"
1359 " as it wants to be stalled for %d more cycles\n",
1360 *inst, inst->minimumCommitCycle - now);
1361 completed_inst =
false;
1364 early_memory_issue, branch, fault,
1365 committed_inst, issued_mem_ref);
1369 completed_inst =
true;
1372 if (completed_inst) {
1378 DPRINTF(MinorExecute,
"Unstalling %d for inst %s\n", inst->fuIndex, inst->id);
1379 funcUnits[inst->fuIndex]->stalled =
false;
1384 DPRINTF(MinorExecute,
"No instructions to commit\n");
1385 completed_inst =
false;
1389 assert(!(discard_inst && !completed_inst));
1394 DPRINTF(MinorExecute,
"Discarding inst: %s as its stream"
1395 " state was unexpected, expected: %d\n",
1399 cpu.executeStats[thread_id]->numDiscardedOps++;
1404 if (issued_mem_ref) {
1411 if (completed_inst && inst->isMemRef()) {
1421 if (completed_inst && !(issued_mem_ref && fault ==
NoFault)) {
1423 DPRINTF(MinorExecute,
"Completed inst: %s\n", *inst);
1427 inst->isLastOpInInst();
1438 if (inst->isInst() && inst->staticInst->isFullMemBarrier()) {
1439 DPRINTF(MinorMem,
"Completing memory barrier"
1440 " inst: %s committed: %d\n", *inst, committed_inst);
1441 lsq.completeMemBarrierInst(inst, committed_inst);
1444 scoreboard[thread_id].clearInstDests(inst, inst->isMemRef());
1448 if (committed_inst) {
1449 bool is_no_cost_inst = inst->isNoCostInst();
1453 if (debug::MinorTrace && !is_no_cost_inst)
1456 if (!is_no_cost_inst)
1457 num_insts_committed++;
1460 DPRINTF(MinorExecute,
"Reached inst commit limit\n");
1464 if (inst->traceData) {
1466 inst->traceData->setWhen(
curTick());
1467 inst->traceData->dump();
1470 if (completed_mem_ref)
1471 num_mem_refs_committed++;
1474 DPRINTF(MinorExecute,
"Reached mem ref commit limit\n");
1486 return executeInfo[thread_id].lastCommitWasEndOfMacroop &&
1487 !
lsq.accessesInFlight();
1493 if (!
inp.outputWire->isBubble())
1498 unsigned int num_issued = 0;
1505 bool interrupted =
false;
1514 DPRINTF(MinorInterrupt,
"Execute skipping a cycle to allow old"
1515 " branch to complete\n");
1522 DPRINTF(MinorExecute,
"Attempting to commit [tid:%d]\n",
1529 commit(commit_tid,
true,
false, branch);
1540 commit(commit_tid,
false,
true, branch);
1545 DPRINTF(MinorExecute,
"Committing micro-ops for interrupt[tid:%d]\n",
1547 bool only_commit_microops = interrupted &&
1549 commit(commit_tid, only_commit_microops,
false, branch);
1557 cpu.getContext(commit_tid)->pcState(), branch);
1567 DPRINTF(MinorExecute,
"Attempting to issue [tid:%d]\n",
1569 num_issued =
issue(issue_tid);
1577 bool can_issue_next =
false;
1579 for (
ThreadID tid = 0; tid <
cpu.numThreads; tid++) {
1583 unsigned int input_index =
executeInfo[tid].inputIndex;
1585 if (inst->isFault()) {
1586 can_issue_next =
true;
1587 }
else if (!inst->isBubble()) {
1588 next_issuable_insts.push_back(inst);
1593 bool becoming_stalled =
true;
1603 if (
fu->occupancy !=0 && !
fu->stalled)
1604 becoming_stalled =
false;
1610 for (
auto inst : next_issuable_insts) {
1611 if (!
fu->stalled &&
fu->provides(inst->staticInst->opClass()) &&
1612 scoreboard[inst->id.threadId].canInstIssue(inst,
1614 cpu.getContext(inst->id.threadId))) {
1615 can_issue_next =
true;
1621 bool head_inst_might_commit =
false;
1625 if (!info.inFlightInsts->empty()) {
1626 const QueuedInst &head_inst = info.inFlightInsts->front();
1628 if (head_inst.
inst->isNoCostInst()) {
1629 head_inst_might_commit =
true;
1633 fu->front().inst->id == head_inst.
inst->id) ||
1634 lsq.findResponse(head_inst.
inst))
1636 head_inst_might_commit =
true;
1643 DPRINTF(Activity,
"Need to tick num issued insts: %s%s%s%s%s%s\n",
1644 (num_issued != 0 ?
" (issued some insts)" :
""),
1645 (becoming_stalled ?
"(becoming stalled)" :
"(not becoming stalled)"),
1646 (can_issue_next ?
" (can issued next inst)" :
""),
1647 (head_inst_might_commit ?
"(head inst might commit)" :
""),
1648 (
lsq.needsToTick() ?
" (LSQ needs to tick)" :
""),
1649 (interrupted ?
" (interrupted)" :
""));
1653 !becoming_stalled ||
1655 head_inst_might_commit ||
1656 lsq.needsToTick() ||
1659 if (!need_to_tick) {
1660 DPRINTF(Activity,
"The next cycle might be skippable as there are no"
1661 " advanceable FUs\n");
1670 cpu.activityRecorder->activity();
1673 if (!
inp.outputWire->isBubble())
1685 bool thread_interrupted =
false;
1692 interrupted = interrupted || thread_interrupted;
1694 DPRINTF(MinorInterrupt,
"No interrupt controller\n");
1696 DPRINTF(MinorInterrupt,
"[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n",
1705 tid = (tid + 1) %
cpu.numThreads;
1726 std::ostringstream insts;
1727 std::ostringstream stalled;
1729 executeInfo[0].instsBeingCommitted.reportData(insts);
1738 stalled << (
funcUnits[
i]->stalled ?
'1' :
'E');
1745 " stalled=%s drainState=%d isInbetweenInsts=%d\n",
1761 switch (
cpu.threadPolicy) {
1762 case enums::SingleThreaded:
1764 case enums::RoundRobin:
1768 priority_list =
cpu.randomPriority();
1771 panic(
"Invalid thread policy");
1774 for (
auto tid : priority_list) {
1777 if (can_commit_insts) {
1781 can_commit_insts = can_commit_insts &&
1782 (!inst->inLSQ || (
lsq.findResponse(inst) != NULL));
1785 bool can_transfer_mem_inst =
false;
1791 can_transfer_mem_inst =
1792 !fu_inst->isBubble() &&
1793 fu_inst->id.threadId == tid &&
1795 fu_inst->canEarlyIssue &&
1796 inst->id.execSeqNum > fu_inst->instToWaitFor;
1800 if (can_commit_insts && !can_transfer_mem_inst &&
1804 can_execute_fu_inst = !fu_inst.
inst->isBubble() &&
1805 fu_inst.
inst->id == inst->id;
1808 can_commit_insts = can_commit_insts &&
1809 (can_transfer_mem_inst || can_execute_fu_inst);
1814 if (can_commit_insts) {
1828 switch (
cpu.threadPolicy) {
1829 case enums::SingleThreaded:
1831 case enums::RoundRobin:
1835 priority_list =
cpu.randomPriority();
1838 panic(
"Invalid thread scheduling policy.");
1841 for (
auto tid : priority_list) {
1854 DPRINTF(Drain,
"MinorExecute drainResume\n");
1856 for (
ThreadID tid = 0; tid <
cpu.numThreads; tid++) {
1868 os <<
"NotDraining";
1871 os <<
"DrainCurrentInst";
1874 os <<
"DrainHaltFetch";
1877 os <<
"DrainAllInsts";
1880 os <<
"Drain-" <<
static_cast<int>(state);
1890 DPRINTF(Drain,
"setDrainState[%d]: %s\n", thread_id, state);
1897 DPRINTF(Drain,
"MinorExecute drain\n");
1899 for (
ThreadID tid = 0; tid <
cpu.numThreads; tid++) {
1919 if (!
lsq.isDrained())
1922 for (
ThreadID tid = 0; tid <
cpu.numThreads; tid++) {
1938 for (
ThreadID tid = 0; tid <
cpu.numThreads; tid++)
1945 return inst->id.streamSeqNum ==
executeInfo[inst->id.threadId].streamSeqNum;
1953 if (!
executeInfo[inst->id.threadId].inFlightInsts->empty())
1954 ret =
executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id;
1962 return lsq.getDcachePort();
1968 "Number of instructions issued per FU type, per thread")
virtual bool inUserMode() const =0
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:
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.
Named(std::string_view name_)
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
virtual PCStateBase * clone() const =0
const T * getConstPtr() const
EventQueue comInstEventQueue
An instruction-based event queue.
BaseISA * getIsaPtr() const override
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
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?
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.
gem5::minor::Execute::IssueStats issueStats
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.
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.
bool needsToBeSentToStoreBuffer()
This request, once processed by the requests/transfers queues, will need to go to the store buffer.
LSQRequest * LSQRequestPtr
void minorTrace() const
Report buffer states from 'slot' 'from' to 'to'.
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.
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
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].
RefCountingPtr< MinorDynInst > MinorDynInstPtr
MinorDynInsts are currently reference counted.
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.
SimpleThread MinorThread
Minor will use the SimpleThread state for now.
const FlagsType pdf
Print the percent of the total that this entry represents.
const FlagsType total
Print the total.
const FlagsType dist
Print the distribution.
Copyright (c) 2024 Arm Limited 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
statistics::Scalar numOps
Stat for number ops (including micro ops) committed.
statistics::Scalar numMemRefs
Stat for number of memory references.
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.
IssueStats(MinorCPU *cpu)
statistics::Vector2d issuedInstType