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"
66 const BaseMinorCPUParams ¶ms,
73 issueLimit(params.executeIssueLimit),
74 memoryIssueLimit(params.executeMemoryIssueLimit),
75 commitLimit(params.executeCommitLimit),
76 memoryCommitLimit(params.executeMemoryCommitLimit),
77 processMoreThanOneInput(params.executeCycleInput),
78 fuDescriptions(*params.executeFuncUnits),
79 numFuncUnits(fuDescriptions.funcUnits.size()),
80 setTraceTimeOnCommit(params.executeSetTraceTimeOnCommit),
81 setTraceTimeOnIssue(params.executeSetTraceTimeOnIssue),
82 allowEarlyMemIssue(params.executeAllowEarlyMemoryIssue),
83 noCostFUIndex(fuDescriptions.funcUnits.size() + 1),
84 lsq(name_ +
".lsq", name_ +
".dcache_port",
86 params.executeMaxAccessesInMemory,
87 params.executeMemoryWidth,
88 params.executeLSQRequestsQueueSize,
89 params.executeLSQTransfersQueueSize,
90 params.executeLSQStoreBufferSize,
91 params.executeLSQMaxStoreBufferStoresPerCycle),
92 executeInfo(params.numThreads,
99 fatal(
"%s: executeCommitLimit must be >= 1 (%d)\n", name_,
104 fatal(
"%s: executeCommitLimit must be >= 1 (%d)\n", name_,
109 fatal(
"%s: executeMemoryIssueLimit must be >= 1 (%d)\n", name_,
114 fatal(
"%s: executeMemoryCommitLimit (%d) must be <="
115 " executeCommitLimit (%d)\n",
119 if (params.executeInputBufferSize < 1) {
120 fatal(
"%s: executeInputBufferSize must be >= 1 (%d)\n", name_,
121 params.executeInputBufferSize);
124 if (params.executeInputBufferSize < 1) {
125 fatal(
"%s: executeInputBufferSize must be >= 1 (%d)\n", name_,
126 params.executeInputBufferSize);
132 unsigned int total_slots = 0;
136 std::ostringstream fu_name;
142 total_slots += fu_description->
opLat;
144 fu_name << name_ <<
".fu." <<
i;
152 for (
int op_class = No_OpClass + 1; op_class <
Num_OpClasses; op_class++) {
153 bool found_fu =
false;
154 unsigned int fu_index = 0;
159 static_cast<OpClass
>(op_class)))
167 warn(
"No functional unit for OpClass %s\n",
168 enums::OpClassStrings[op_class]);
173 for (
ThreadID tid = 0; tid < params.numThreads; tid++) {
179 name_ +
".inputBuffer" + tid_str,
"insts",
180 params.executeInputBufferSize));
182 const auto ®Classes =
cpu.
threads[tid]->getIsaPtr()->regClasses();
185 scoreboard.emplace_back(name_ +
".scoreboard" + tid_str, regClasses);
190 name_ +
".inFlightInsts" + tid_str,
"insts", total_slots);
194 name_ +
".inFUMemInsts" + tid_str,
"insts", total_slots);
224 const std::unique_ptr<PCStateBase> pc_before(inst->pc->clone());
225 std::unique_ptr<PCStateBase> target(thread->
pcState().
clone());
231 inst->isLastOpInInst() &&
232 (inst->staticInst->isSerializeAfter() ||
233 inst->staticInst->isSquashAfter());
236 *pc_before, *target, (force_branch ?
" (forcing)" :
""));
239 bool must_branch = *pc_before != *target ||
247 inst->staticInst->advancePC(*target);
251 *pc_before, *target);
254 if (inst->predictedTaken && !force_branch) {
260 " none happened inst: %s\n",
261 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
265 }
else if (*inst->predictedTarget == *target) {
270 DPRINTF(
Branch,
"Predicted a branch from 0x%x to 0x%x correctly"
272 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
279 " but got the wrong target (actual: 0x%x) inst: %s\n",
280 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
281 target->instAddr(), *inst);
285 }
else if (must_branch) {
287 DPRINTF(
Branch,
"Unpredicted branch from 0x%x to 0x%x inst: %s\n",
288 inst->pc->instAddr(), target->instAddr(), *inst);
317 (inst->isBubble() ?
executeInfo[tid].lastPredictionSeqNum
318 : inst->id.predictionSeqNum),
329 ThreadID thread_id = inst->id.threadId;
336 bool is_load = inst->staticInst->isLoad();
337 bool is_store = inst->staticInst->isStore();
338 bool is_atomic = inst->staticInst->isAtomic();
339 bool is_prefetch = inst->staticInst->isDataPrefetch();
343 bool use_context_predicate =
true;
345 if (inst->translationFault !=
NoFault) {
347 DPRINTF(MinorMem,
"Completing fault from DTLB access: %s\n",
348 inst->translationFault->name());
350 if (inst->staticInst->isPrefetch()) {
351 DPRINTF(MinorMem,
"Not taking fault on prefetch: %s\n",
352 inst->translationFault->name());
357 fault = inst->translationFault;
359 fault->invoke(thread, inst->staticInst);
361 }
else if (!packet) {
362 DPRINTF(MinorMem,
"Completing failed request inst: %s\n",
364 use_context_predicate =
false;
366 inst->staticInst->completeAcc(
nullptr, &context, inst->traceData);
367 }
else if (packet->
isError()) {
368 DPRINTF(MinorMem,
"Trying to commit error response: %s\n",
371 fatal(
"Received error response packet for inst: %s\n", *inst);
372 }
else if (is_store || is_load || is_prefetch || is_atomic) {
375 DPRINTF(MinorMem,
"Memory response inst: %s addr: 0x%x size: %d\n",
378 if (is_load && packet->
getSize() > 0) {
379 DPRINTF(MinorMem,
"Memory data[0]: 0x%x\n",
380 static_cast<unsigned int>(packet->
getConstPtr<uint8_t>()[0]));
384 fault = inst->staticInst->completeAcc(packet, &context,
389 DPRINTF(MinorMem,
"Fault in memory completeAcc: %s\n",
391 fault->invoke(thread, inst->staticInst);
399 fatal(
"There should only ever be reads, "
400 "writes or faults at this point\n");
405 if (inst->traceData) {
406 inst->traceData->setPredicate((use_context_predicate ?
425 DPRINTF(MinorInterrupt,
"Considering interrupt status from PC: %s\n",
437 DPRINTF(MinorInterrupt,
"Invoking interrupt: %s to PC: %s\n",
452 bool &passed_predicate,
Fault &fault)
457 passed_predicate =
false;
465 std::unique_ptr<PCStateBase> old_pc(thread->
pcState().
clone());
469 DPRINTF(MinorExecute,
"Initiating memRef inst: %s\n", *inst);
471 Fault init_fault = inst->staticInst->initiateAcc(&context,
476 assert(inst->translationFault !=
NoFault);
482 inst->translationFault =
NoFault;
487 DPRINTF(MinorExecute,
"Fault on memory inst: %s"
488 " initiateAcc: %s\n", *inst, init_fault->name());
494 DPRINTF(MinorMem,
"No memory access for inst: %s\n", *inst);
501 inst->traceData->setPredicate(passed_predicate);
527 unsigned int ret =
index + 1;
529 if (ret == cycle_size)
542 ret = cycle_size - 1;
558 unsigned int fu_index = 0;
567 unsigned num_insts_issued = 0;
570 unsigned num_mem_insts_issued = 0;
574 unsigned num_insts_discarded = 0;
578 Fault fault = inst->fault;
579 bool discarded =
false;
580 bool issued_mem_ref =
false;
582 if (inst->isBubble()) {
588 DPRINTF(MinorExecute,
"Discarding inst: %s from suspended"
593 }
else if (inst->id.streamSeqNum != thread.
streamSeqNum) {
594 DPRINTF(MinorExecute,
"Discarding inst: %s as its stream"
595 " state was unexpected, expected: %d\n",
612 DPRINTF(MinorExecute,
"Trying to issue inst: %s to FU: %d\n",
619 bool fu_is_capable = (!inst->isFault() ?
620 fu->provides(inst->staticInst->opClass()) :
true);
622 if (inst->isNoCostInst()) {
637 inst->extraCommitDelay =
Cycles(0);
638 inst->extraCommitDelayExpr = NULL;
647 }
else if (!fu_is_capable ||
fu->alreadyPushed()) {
649 if (!fu_is_capable) {
650 DPRINTF(MinorExecute,
"Can't issue as FU: %d isn't"
651 " capable\n", fu_index);
653 DPRINTF(MinorExecute,
"Can't issue as FU: %d is"
654 " already busy\n", fu_index);
656 }
else if (
fu->stalled) {
657 DPRINTF(MinorExecute,
"Can't issue inst: %s into FU: %d,"
660 }
else if (!
fu->canInsert()) {
661 DPRINTF(MinorExecute,
"Can't issue inst: %s to busy FU"
662 " for another: %d cycles\n",
663 *inst,
fu->cyclesBeforeInsert());
666 fu->findTiming(inst->staticInst) : NULL);
673 &(
fu->cantForwardFromFUIndices);
676 DPRINTF(MinorExecute,
"Can't issue inst: %s as extra"
677 " decoding is suppressing it\n",
679 }
else if (!
scoreboard[thread_id].canInstIssue(inst,
680 src_latencies, cant_forward_from_fu_indices,
683 DPRINTF(MinorExecute,
"Can't issue inst: %s yet\n",
687 DPRINTF(MinorExecute,
"Issuing inst: %s"
688 " into FU %d\n", *inst,
692 TimingExpr *extra_dest_retire_lat_expr = NULL;
698 extra_dest_retire_lat =
700 extra_dest_retire_lat_expr =
706 issued_mem_ref = inst->isMemRef();
711 inst->fuIndex = fu_index;
712 inst->extraCommitDelay = extra_dest_retire_lat;
713 inst->extraCommitDelayExpr =
714 extra_dest_retire_lat_expr;
716 if (issued_mem_ref) {
721 inst->instToWaitFor =
722 scoreboard[thread_id].execSeqNumToWaitFor(inst,
728 DPRINTF(MinorExecute,
"A barrier will"
729 " cause a delay in mem ref issue of"
730 " inst: %s until after inst"
731 " %d(exec)\n", *inst,
734 inst->instToWaitFor =
737 DPRINTF(MinorExecute,
"Memory ref inst:"
738 " %s must wait for inst %d(exec)"
740 *inst, inst->instToWaitFor);
743 inst->canEarlyIssue =
true;
747 DPRINTF(MinorExecute,
"Pushing mem inst: %s\n",
761 fu->description.opLat +
762 extra_dest_retire_lat +
765 issued_mem_ref && extra_assumed_lat ==
Cycles(0));
779 DPRINTF(MinorExecute,
"Didn't issue inst: %s\n", *inst);
785 if (debug::MinorTrace && !inst->isBubble()) {
786 inst->minorTraceInst(*
this);
790 if (!discarded && inst->isInst() &&
791 inst->staticInst->isFullMemBarrier())
793 DPRINTF(MinorMem,
"Issuing memory barrier inst: %s\n", *inst);
798 inst->traceData->setWhen(
curTick());
802 num_mem_insts_issued++;
805 num_insts_discarded++;
806 }
else if (!inst->isBubble()) {
810 DPRINTF(MinorExecute,
"Reached inst issue limit\n");
814 DPRINTF(MinorExecute,
"Stepping to next inst inputIndex: %d\n",
826 DPRINTF(MinorExecute,
"Wrapping\n");
837 return num_insts_issued;
844 unsigned int num_pc_event_checks = 0;
850 cpu.
threads[thread_id]->pcEventQueue.service(oldPC, thread);
851 num_pc_event_checks++;
854 if (num_pc_event_checks > 1) {
859 return num_pc_event_checks > 1;
865 assert(!inst->isFault());
871 if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop())
884 [inst->staticInst->opClass()]++;
887 if (inst->staticInst->isControl()) {
888 if (inst->staticInst->isReturn()) {
890 [gem5::StaticInstFlags::Flags::IsReturn]++;
892 if (inst->staticInst->isCall()) {
894 [gem5::StaticInstFlags::Flags::IsCall]++;
896 if (inst->staticInst->isDirectCtrl()) {
898 [gem5::StaticInstFlags::Flags::IsDirectControl]++;
900 if (inst->staticInst->isIndirectCtrl()) {
902 [gem5::StaticInstFlags::Flags::IsIndirectControl]++;
904 if (inst->staticInst->isCondCtrl()) {
906 [gem5::StaticInstFlags::Flags::IsCondControl]++;
908 if (inst->staticInst->isUncondCtrl()) {
910 [gem5::StaticInstFlags::Flags::IsUncondControl]++;
914 [gem5::StaticInstFlags::Flags::IsControl]++;
921 inst->traceData->setCPSeq(thread->
numOp);
929 bool &completed_mem_issue)
931 ThreadID thread_id = inst->id.threadId;
934 bool completed_inst =
true;
942 panic(
"We should never hit the case where we try to commit from a "
943 "suspended thread as the streamSeqNum should not match");
944 }
else if (inst->isFault()) {
947 DPRINTF(MinorExecute,
"Fault inst reached Execute: %s\n",
948 inst->fault->name());
951 inst->fault->invoke(thread, NULL);
954 }
else if (inst->staticInst->isMemRef()) {
967 bool predicate_passed =
false;
969 predicate_passed, fault);
971 if (completed_mem_inst && fault !=
NoFault) {
972 if (early_memory_issue) {
973 DPRINTF(MinorExecute,
"Fault in early executing inst: %s\n",
977 inst->canEarlyIssue =
false;
980 completed_inst =
false;
982 DPRINTF(MinorExecute,
"Fault in execute: %s\n",
984 fault->invoke(thread, NULL);
987 completed_inst =
true;
990 completed_inst = completed_mem_inst;
992 completed_mem_issue = completed_inst;
993 }
else if (inst->isInst() && inst->staticInst->isFullMemBarrier() &&
996 DPRINTF(MinorExecute,
"Can't commit data barrier inst: %s yet as"
997 " there isn't space in the store buffer\n", *inst);
999 completed_inst =
false;
1000 }
else if (inst->isInst() && inst->staticInst->isQuiesce()
1004 completed_inst =
false;
1008 DPRINTF(MinorExecute,
"Committing inst: %s\n", *inst);
1010 fault = inst->staticInst->execute(&context,
1014 if (inst->traceData)
1020 if (inst->traceData) {
1021 if (debug::ExecFaulting) {
1022 inst->traceData->setFaulting(
true);
1024 delete inst->traceData;
1025 inst->traceData = NULL;
1029 DPRINTF(MinorExecute,
"Fault in execute of inst: %s fault: %s\n",
1030 *inst, fault->name());
1031 fault->invoke(thread, inst->staticInst);
1038 if (completed_inst) {
1042 executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum;
1045 if (!inst->isFault() &&
1053 assert(resume_pc.microPC() == 0);
1055 DPRINTF(MinorInterrupt,
"Suspending thread: %d from Execute"
1056 " inst: %s\n", thread_id, *inst);
1065 return completed_inst;
1103 bool completed_inst =
true;
1106 unsigned int num_insts_committed = 0;
1110 unsigned int num_mem_refs_committed = 0;
1112 if (only_commit_microops && !ex_info.
inFlightInsts->empty()) {
1113 DPRINTF(MinorInterrupt,
"Only commit microops %s %d\n",
1125 if (only_commit_microops) {
1126 DPRINTF(MinorInterrupt,
"Committing tail of insts before"
1134 head_inflight_inst->
inst->id.execSeqNum;
1141 bool committed_inst =
false;
1142 bool discard_inst =
false;
1143 bool completed_mem_ref =
false;
1144 bool issued_mem_ref =
false;
1145 bool early_memory_issue =
false;
1148 completed_inst =
false;
1160 DPRINTF(MinorExecute,
"Trying to commit canCommitInsts: %d\n",
1170 }
else if (mem_response &&
1174 discard_inst = inst->id.streamSeqNum !=
1177 DPRINTF(MinorExecute,
"Trying to commit mem response: %s\n",
1182 DPRINTF(MinorExecute,
"Discarding mem inst: %s as its"
1183 " stream state was unexpected, expected: %d\n",
1189 committed_inst =
true;
1192 completed_mem_ref =
true;
1193 completed_inst =
true;
1194 }
else if (can_commit_insts) {
1199 bool try_to_commit =
false;
1211 DPRINTF(MinorExecute,
"Trying to commit from mem FUs\n");
1220 if (!fu_inst->isBubble() &&
1222 fu_inst->canEarlyIssue &&
1224 head_exec_seq_num > fu_inst->instToWaitFor)
1226 DPRINTF(MinorExecute,
"Issuing mem ref early"
1227 " inst: %s instToWaitFor: %d\n",
1228 *(fu_inst), fu_inst->instToWaitFor);
1231 try_to_commit =
true;
1232 early_memory_issue =
true;
1233 completed_inst =
true;
1238 if (!completed_inst && inst->isNoCostInst()) {
1239 DPRINTF(MinorExecute,
"Committing no cost inst: %s", *inst);
1241 try_to_commit =
true;
1242 completed_inst =
true;
1247 if (!completed_inst && !inst->inLSQ) {
1248 DPRINTF(MinorExecute,
"Trying to commit from FUs\n");
1257 if (fu_inst.
inst->isBubble()) {
1259 completed_inst =
false;
1260 }
else if (fu_inst_seq_num != head_exec_seq_num) {
1266 }
else if (fu_inst.
inst->id == inst->id) {
1270 try_to_commit =
true;
1271 completed_inst =
true;
1275 if (try_to_commit) {
1276 discard_inst = inst->id.streamSeqNum !=
1281 if (!discard_inst) {
1287 if (inst->extraCommitDelayExpr) {
1288 DPRINTF(MinorExecute,
"Evaluating expression for"
1289 " extra commit delay inst: %s\n", *inst);
1296 uint64_t extra_delay = inst->extraCommitDelayExpr->
1299 DPRINTF(MinorExecute,
"Extra commit delay expr"
1300 " result: %d\n", extra_delay);
1302 if (extra_delay < 128) {
1303 inst->extraCommitDelay +=
Cycles(extra_delay);
1305 DPRINTF(MinorExecute,
"Extra commit delay was"
1306 " very long: %d\n", extra_delay);
1308 inst->extraCommitDelayExpr = NULL;
1313 if (inst->extraCommitDelay !=
Cycles(0)) {
1315 inst->extraCommitDelay;
1316 inst->extraCommitDelay =
Cycles(0);
1321 if (!inst->isFault() && inst->isMemRef() &&
1323 inst->id.execSeqNum &&
1326 DPRINTF(MinorExecute,
"Not committing inst: %s yet"
1327 " as there are incomplete barriers in flight\n",
1329 completed_inst =
false;
1330 }
else if (inst->minimumCommitCycle > now) {
1331 DPRINTF(MinorExecute,
"Not committing inst: %s yet"
1332 " as it wants to be stalled for %d more cycles\n",
1333 *inst, inst->minimumCommitCycle - now);
1334 completed_inst =
false;
1337 early_memory_issue, branch, fault,
1338 committed_inst, issued_mem_ref);
1342 completed_inst =
true;
1345 if (completed_inst) {
1351 DPRINTF(MinorExecute,
"Unstalling %d for inst %s\n", inst->fuIndex, inst->id);
1352 funcUnits[inst->fuIndex]->stalled =
false;
1357 DPRINTF(MinorExecute,
"No instructions to commit\n");
1358 completed_inst =
false;
1362 assert(!(discard_inst && !completed_inst));
1367 DPRINTF(MinorExecute,
"Discarding inst: %s as its stream"
1368 " state was unexpected, expected: %d\n",
1376 if (issued_mem_ref) {
1383 if (completed_inst && inst->isMemRef()) {
1393 if (completed_inst && !(issued_mem_ref && fault ==
NoFault)) {
1395 DPRINTF(MinorExecute,
"Completed inst: %s\n", *inst);
1399 inst->isLastOpInInst();
1410 if (inst->isInst() && inst->staticInst->isFullMemBarrier()) {
1411 DPRINTF(MinorMem,
"Completing memory barrier"
1412 " inst: %s committed: %d\n", *inst, committed_inst);
1416 scoreboard[thread_id].clearInstDests(inst, inst->isMemRef());
1420 if (committed_inst) {
1421 bool is_no_cost_inst = inst->isNoCostInst();
1425 if (debug::MinorTrace && !is_no_cost_inst)
1428 if (!is_no_cost_inst)
1429 num_insts_committed++;
1432 DPRINTF(MinorExecute,
"Reached inst commit limit\n");
1436 if (inst->traceData) {
1438 inst->traceData->setWhen(
curTick());
1439 inst->traceData->dump();
1442 if (completed_mem_ref)
1443 num_mem_refs_committed++;
1446 DPRINTF(MinorExecute,
"Reached mem ref commit limit\n");
1454 return executeInfo[thread_id].lastCommitWasEndOfMacroop &&
1461 if (!
inp.outputWire->isBubble())
1466 unsigned int num_issued = 0;
1473 bool interrupted =
false;
1482 DPRINTF(MinorInterrupt,
"Execute skipping a cycle to allow old"
1483 " branch to complete\n");
1490 DPRINTF(MinorExecute,
"Attempting to commit [tid:%d]\n",
1497 commit(commit_tid,
true,
false, branch);
1508 commit(commit_tid,
false,
true, branch);
1513 DPRINTF(MinorExecute,
"Committing micro-ops for interrupt[tid:%d]\n",
1515 bool only_commit_microops = interrupted &&
1517 commit(commit_tid, only_commit_microops,
false, branch);
1535 DPRINTF(MinorExecute,
"Attempting to issue [tid:%d]\n",
1537 num_issued =
issue(issue_tid);
1545 bool can_issue_next =
false;
1551 unsigned int input_index =
executeInfo[tid].inputIndex;
1553 if (inst->isFault()) {
1554 can_issue_next =
true;
1555 }
else if (!inst->isBubble()) {
1556 next_issuable_insts.push_back(inst);
1561 bool becoming_stalled =
true;
1571 if (
fu->occupancy !=0 && !
fu->stalled)
1572 becoming_stalled =
false;
1578 for (
auto inst : next_issuable_insts) {
1579 if (!
fu->stalled &&
fu->provides(inst->staticInst->opClass()) &&
1580 scoreboard[inst->id.threadId].canInstIssue(inst,
1583 can_issue_next =
true;
1589 bool head_inst_might_commit =
false;
1593 if (!info.inFlightInsts->empty()) {
1594 const QueuedInst &head_inst = info.inFlightInsts->front();
1596 if (head_inst.
inst->isNoCostInst()) {
1597 head_inst_might_commit =
true;
1601 fu->front().inst->id == head_inst.
inst->id) ||
1604 head_inst_might_commit =
true;
1611 DPRINTF(Activity,
"Need to tick num issued insts: %s%s%s%s%s%s\n",
1612 (num_issued != 0 ?
" (issued some insts)" :
""),
1613 (becoming_stalled ?
"(becoming stalled)" :
"(not becoming stalled)"),
1614 (can_issue_next ?
" (can issued next inst)" :
""),
1615 (head_inst_might_commit ?
"(head inst might commit)" :
""),
1617 (interrupted ?
" (interrupted)" :
""));
1621 !becoming_stalled ||
1623 head_inst_might_commit ||
1627 if (!need_to_tick) {
1628 DPRINTF(Activity,
"The next cycle might be skippable as there are no"
1629 " advanceable FUs\n");
1641 if (!
inp.outputWire->isBubble())
1653 bool thread_interrupted =
false;
1660 interrupted = interrupted || thread_interrupted;
1662 DPRINTF(MinorInterrupt,
"No interrupt controller\n");
1664 DPRINTF(MinorInterrupt,
"[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n",
1694 std::ostringstream insts;
1695 std::ostringstream stalled;
1697 executeInfo[0].instsBeingCommitted.reportData(insts);
1706 stalled << (
funcUnits[
i]->stalled ?
'1' :
'E');
1713 " stalled=%s drainState=%d isInbetweenInsts=%d\n",
1730 case enums::SingleThreaded:
1732 case enums::RoundRobin:
1739 panic(
"Invalid thread policy");
1742 for (
auto tid : priority_list) {
1745 if (can_commit_insts) {
1749 can_commit_insts = can_commit_insts &&
1753 bool can_transfer_mem_inst =
false;
1759 can_transfer_mem_inst =
1760 !fu_inst->isBubble() &&
1761 fu_inst->id.threadId == tid &&
1763 fu_inst->canEarlyIssue &&
1764 inst->id.execSeqNum > fu_inst->instToWaitFor;
1768 if (can_commit_insts && !can_transfer_mem_inst &&
1772 can_execute_fu_inst = !fu_inst.
inst->isBubble() &&
1773 fu_inst.
inst->id == inst->id;
1776 can_commit_insts = can_commit_insts &&
1777 (can_transfer_mem_inst || can_execute_fu_inst);
1782 if (can_commit_insts) {
1797 case enums::SingleThreaded:
1799 case enums::RoundRobin:
1806 panic(
"Invalid thread scheduling policy.");
1809 for (
auto tid : priority_list) {
1822 DPRINTF(Drain,
"MinorExecute drainResume\n");
1836 os <<
"NotDraining";
1839 os <<
"DrainCurrentInst";
1842 os <<
"DrainHaltFetch";
1845 os <<
"DrainAllInsts";
1848 os <<
"Drain-" <<
static_cast<int>(
state);
1858 DPRINTF(Drain,
"setDrainState[%d]: %s\n", thread_id,
state);
1865 DPRINTF(Drain,
"MinorExecute drain\n");
1913 return inst->id.streamSeqNum ==
executeInfo[inst->id.threadId].streamSeqNum;
1921 if (!
executeInfo[inst->id.threadId].inFlightInsts->empty())
1922 ret =
executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id;
void activity()
Records that there is activity this cycle.
virtual ThreadContext * getContext(int tn)
Given a thread num get tho thread context for it.
ThreadID numThreads
Number of threads we're actually simulating (<= SMT_MAX_THREADS).
bool checkInterrupts(ThreadID tid) const
BaseInterrupts * getInterruptController(ThreadID tid)
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::MinorStats stats
Processor-specific statistics.
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 > roundRobinPriority(ThreadID priority)
Thread scheduling utility functions.
std::vector< ThreadID > randomPriority()
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.
virtual const PCStateBase & pcState() const =0
@ Suspended
Temporarily inactive.
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.
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...
void step()
Step checks the queues to see if their are issuable transfers which were not otherwise picked up by t...
MinorCPU::MinorCPUPort & getDcachePort()
Return the raw-bindable port.
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.
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.
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.
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
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
GEM5_DEPRECATED_NAMESPACE(GuestABI, guest_abi)
Minor contains all the definitions within the MinorCPU apart from the CPU class itself.
const std::string to_string(sc_enc enc)
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 -> ...
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.
statistics::Vector2d committedControl
Number of branches commited.
statistics::Scalar numFetchSuspends
Number of times fetch was asked to suspend by Execute.
statistics::Vector2d committedInstType
Number of instructions by type (OpClass)
statistics::Scalar numOps
Number of simulated insts and microops.
statistics::Scalar numInsts
Number of simulated instructions.
statistics::Scalar numDiscardedOps
Number of ops discarded before committing.