45 #ifndef __CPU_O3_FETCH_IMPL_HH__
46 #define __CPU_O3_FETCH_IMPL_HH__
54 #include "arch/isa_traits.hh"
55 #include "arch/tlb.hh"
56 #include "arch/utility.hh"
57 #include "arch/vtophys.hh"
60 #include "config/the_isa.hh"
65 #include "debug/Activity.hh"
66 #include "debug/Drain.hh"
67 #include "debug/Fetch.hh"
68 #include "debug/O3PipeView.hh"
70 #include "params/DerivO3CPU.hh"
83 decodeToFetchDelay(params->decodeToFetchDelay),
84 renameToFetchDelay(params->renameToFetchDelay),
85 iewToFetchDelay(params->iewToFetchDelay),
86 commitToFetchDelay(params->commitToFetchDelay),
87 fetchWidth(params->fetchWidth),
88 decodeWidth(params->decodeWidth),
91 cacheBlkSize(cpu->cacheLineSize()),
92 fetchBufferSize(params->fetchBufferSize),
93 fetchBufferMask(fetchBufferSize - 1),
94 fetchQueueSize(params->fetchQueueSize),
95 numThreads(params->numThreads),
96 numFetchingThreads(params->smtNumFetchingThreads),
97 finishTranslationEvent(this)
100 fatal(
"numThreads (%d) is larger than compiled limit (%d),\n"
101 "\tincrease MaxThreads in src/cpu/o3/impl.hh\n",
102 numThreads, static_cast<int>(Impl::MaxThreads));
104 fatal(
"fetchWidth (%d) is larger than compiled limit (%d),\n"
105 "\tincrease MaxWidth in src/cpu/o3/impl.hh\n",
106 fetchWidth, static_cast<int>(Impl::MaxWidth));
108 fatal(
"fetch buffer size (%u bytes) is greater than the cache "
111 fatal(
"cache block (%u bytes) is not a multiple of the "
112 "fetch buffer (%u bytes)\n",
cacheBlkSize, fetchBufferSize);
114 std::string policy = params->smtFetchPolicy;
117 std::transform(policy.begin(), policy.end(), policy.begin(),
118 (int(*)(int)) tolower);
121 if (policy ==
"singlethread") {
124 panic(
"Invalid Fetch Policy for a SMT workload.");
125 }
else if (policy ==
"roundrobin") {
127 DPRINTF(Fetch,
"Fetch policy set to Round Robin\n");
128 }
else if (policy ==
"branch") {
130 DPRINTF(Fetch,
"Fetch policy set to Branch Count\n");
131 }
else if (policy ==
"iqcount") {
133 DPRINTF(Fetch,
"Fetch policy set to IQ count\n");
134 }
else if (policy ==
"lsqcount") {
136 DPRINTF(Fetch,
"Fetch policy set to LSQ count\n");
138 fatal(
"Invalid Fetch Policy. Options Are: {SingleThread,"
139 " RoundRobin,LSQcount,IQcount}\n");
145 for (
int i = 0;
i < Impl::MaxThreads;
i++) {
155 decoder[tid] =
new TheISA::Decoder(params->isa[tid]);
162 template <
class Impl>
166 return cpu->name() +
".fetch";
169 template <
class Impl>
179 template <
class Impl>
184 .name(
name() +
".icacheStallCycles")
185 .desc(
"Number of cycles fetch is stalled on an Icache miss")
186 .prereq(icacheStallCycles);
189 .name(
name() +
".Insts")
190 .desc(
"Number of instructions fetch has processed")
191 .prereq(fetchedInsts);
194 .name(
name() +
".Branches")
195 .desc(
"Number of branches that fetch encountered")
196 .prereq(fetchedBranches);
199 .name(
name() +
".predictedBranches")
200 .desc(
"Number of branches that fetch has predicted taken")
201 .prereq(predictedBranches);
204 .name(
name() +
".Cycles")
205 .desc(
"Number of cycles fetch has run and was not squashing or"
207 .prereq(fetchCycles);
210 .name(
name() +
".SquashCycles")
211 .desc(
"Number of cycles fetch has spent squashing")
212 .prereq(fetchSquashCycles);
215 .name(
name() +
".TlbCycles")
216 .desc(
"Number of cycles fetch has spent waiting for tlb")
217 .prereq(fetchTlbCycles);
220 .name(
name() +
".IdleCycles")
221 .desc(
"Number of cycles fetch was idle")
222 .prereq(fetchIdleCycles);
225 .name(
name() +
".BlockedCycles")
226 .desc(
"Number of cycles fetch has spent blocked")
227 .prereq(fetchBlockedCycles);
230 .name(
name() +
".CacheLines")
231 .desc(
"Number of cache lines fetched")
232 .prereq(fetchedCacheLines);
235 .name(
name() +
".MiscStallCycles")
236 .desc(
"Number of cycles fetch has spent waiting on interrupts, or "
237 "bad addresses, or out of MSHRs")
238 .prereq(fetchMiscStallCycles);
240 fetchPendingDrainCycles
241 .name(
name() +
".PendingDrainCycles")
242 .desc(
"Number of cycles fetch has spent waiting on pipes to drain")
243 .prereq(fetchPendingDrainCycles);
245 fetchNoActiveThreadStallCycles
246 .name(
name() +
".NoActiveThreadStallCycles")
247 .desc(
"Number of stall cycles due to no active thread to fetch from")
248 .prereq(fetchNoActiveThreadStallCycles);
250 fetchPendingTrapStallCycles
251 .name(
name() +
".PendingTrapStallCycles")
252 .desc(
"Number of stall cycles due to pending traps")
253 .prereq(fetchPendingTrapStallCycles);
255 fetchPendingQuiesceStallCycles
256 .name(
name() +
".PendingQuiesceStallCycles")
257 .desc(
"Number of stall cycles due to pending quiesce instructions")
258 .prereq(fetchPendingQuiesceStallCycles);
260 fetchIcacheWaitRetryStallCycles
261 .name(
name() +
".IcacheWaitRetryStallCycles")
262 .desc(
"Number of stall cycles due to full MSHR")
263 .prereq(fetchIcacheWaitRetryStallCycles);
266 .name(
name() +
".IcacheSquashes")
267 .desc(
"Number of outstanding Icache misses that were squashed")
268 .prereq(fetchIcacheSquashes);
271 .name(
name() +
".ItlbSquashes")
272 .desc(
"Number of outstanding ITLB misses that were squashed")
273 .prereq(fetchTlbSquashes);
279 .name(
name() +
".rateDist")
280 .desc(
"Number of instructions fetched each cycle (Total)")
284 .name(
name() +
".idleRate")
285 .desc(
"Percent of cycles fetch was idle")
287 idleRate = fetchIdleCycles * 100 / cpu->numCycles;
290 .name(
name() +
".branchRate")
291 .desc(
"Number of branch fetches per cycle")
293 branchRate = fetchedBranches / cpu->numCycles;
296 .name(
name() +
".rate")
297 .desc(
"Number of inst fetches per cycle")
299 fetchRate = fetchedInsts / cpu->numCycles;
306 timeBuffer = time_buffer;
309 fromDecode = timeBuffer->
getWire(-decodeToFetchDelay);
310 fromRename = timeBuffer->getWire(-renameToFetchDelay);
311 fromIEW = timeBuffer->getWire(-iewToFetchDelay);
312 fromCommit = timeBuffer->getWire(-commitToFetchDelay);
319 activeThreads = at_ptr;
327 toDecode = ftb_ptr->
getWire(0);
334 assert(priorityList.empty());
347 interruptPending =
false;
348 cacheBlocked =
false;
350 priorityList.clear();
353 for (
ThreadID tid = 0; tid < numThreads; ++tid) {
355 pc[tid] = cpu->pcState(tid);
356 fetchOffset[tid] = 0;
359 delayedCommit[tid] =
false;
362 stalls[tid].decode =
false;
363 stalls[tid].drain =
false;
365 fetchBufferPC[tid] = 0;
366 fetchBufferValid[tid] =
false;
368 fetchQueue[tid].clear();
370 priorityList.push_back(tid);
373 wroteToTimeBuffer =
false;
383 DPRINTF(Fetch,
"[tid:%u] Waking up from cache miss.\n", tid);
384 assert(!cpu->switchedOut());
388 if (fetchStatus[tid] != IcacheWaitResponse ||
389 pkt->
req != memReq[tid]) {
390 ++fetchIcacheSquashes;
396 memcpy(fetchBuffer[tid], pkt->
getConstPtr<uint8_t>(), fetchBufferSize);
397 fetchBufferValid[tid] =
true;
403 DPRINTF(Activity,
"[tid:%u] Activating fetch due to cache completion\n",
409 if (checkStall(tid)) {
410 fetchStatus[tid] = Blocked;
412 fetchStatus[tid] = IcacheAccessComplete;
416 cpu->ppInstAccessComplete->notify(pkt);
423 template <
class Impl>
428 stalls[
i].decode =
false;
429 stalls[
i].drain =
false;
433 template <
class Impl>
438 assert(retryPkt == NULL);
440 assert(!cacheBlocked);
441 assert(!interruptPending);
445 assert(fetchStatus[i] == Idle || stalls[i].drain);
448 branchPred->drainSanityCheck();
451 template <
class Impl>
463 if (!fetchQueue[
i].empty())
467 if (fetchStatus[
i] != Idle) {
468 if (fetchStatus[
i] == Blocked && stalls[
i].drain)
479 return !finishTranslationEvent.scheduled();
482 template <
class Impl>
486 assert(cpu->getInstPort().isConnected());
491 template <
class Impl>
495 assert(cpu->isDraining());
496 assert(!stalls[tid].drain);
497 DPRINTF(Drain,
"%i: Thread drained.\n", tid);
498 stalls[tid].drain =
true;
501 template <
class Impl>
505 DPRINTF(Fetch,
"Waking up from quiesce\n");
511 template <
class Impl>
515 if (_status == Inactive) {
516 DPRINTF(Activity,
"Activating stage.\n");
518 cpu->activateStage(O3CPU::FetchIdx);
524 template <
class Impl>
528 if (_status == Active) {
529 DPRINTF(Activity,
"Deactivating stage.\n");
531 cpu->deactivateStage(O3CPU::FetchIdx);
537 template <
class Impl>
542 auto thread_it = std::find(priorityList.begin(), priorityList.end(), tid);
543 if (thread_it != priorityList.end()) {
544 priorityList.erase(thread_it);
548 template <
class Impl>
558 if (!inst->isControl()) {
560 inst->setPredTarg(nextPC);
561 inst->setPredTaken(
false);
566 predict_taken = branchPred->predict(inst->staticInst, inst->seqNum,
570 DPRINTF(Fetch,
"[tid:%i]: [sn:%i]: Branch predicted to be taken to %s.\n",
571 tid, inst->seqNum, nextPC);
573 DPRINTF(Fetch,
"[tid:%i]: [sn:%i]:Branch predicted to be not taken.\n",
577 DPRINTF(Fetch,
"[tid:%i]: [sn:%i] Branch predicted to go to %s.\n",
578 tid, inst->seqNum, nextPC);
579 inst->setPredTarg(nextPC);
580 inst->setPredTaken(predict_taken);
588 return predict_taken;
591 template <
class Impl>
597 assert(!cpu->switchedOut());
602 DPRINTF(Fetch,
"[tid:%i] Can't fetch cache line, cache blocked\n",
605 }
else if (checkInterrupt(pc) && !delayedCommit[tid]) {
610 DPRINTF(Fetch,
"[tid:%i] Can't fetch cache line, interrupt pending\n",
616 Addr fetchBufferBlockPC = fetchBufferAlignPC(vaddr);
618 DPRINTF(Fetch,
"[tid:%i] Fetching cache line %#x for addr %#x\n",
619 tid, fetchBufferBlockPC, vaddr);
625 new Request(tid, fetchBufferBlockPC, fetchBufferSize,
627 cpu->thread[tid]->contextId());
629 mem_req->
taskId(cpu->taskId());
631 memReq[tid] = mem_req;
634 fetchStatus[tid] = ItlbWait;
636 cpu->itb->translateTiming(mem_req, cpu->thread[tid]->getTC(),
641 template <
class Impl>
648 assert(!cpu->switchedOut());
653 if (fetchStatus[tid] != ItlbWait || mem_req != memReq[tid] ||
654 mem_req->
getVaddr() != memReq[tid]->getVaddr()) {
655 DPRINTF(Fetch,
"[tid:%i] Ignoring itlb completed after squash\n",
668 if (!cpu->system->isMemAddr(mem_req->
getPaddr())) {
669 warn(
"Address %#x is outside of physical memory, stopping fetch\n",
671 fetchStatus[tid] = NoGoodAddr;
679 data_pkt->
dataDynamic(
new uint8_t[fetchBufferSize]);
681 fetchBufferPC[tid] = fetchBufferBlockPC;
682 fetchBufferValid[tid] =
false;
683 DPRINTF(Fetch,
"Fetch: Doing instruction read.\n");
688 if (!cpu->getInstPort().sendTimingReq(data_pkt)) {
689 assert(retryPkt == NULL);
691 DPRINTF(Fetch,
"[tid:%i] Out of MSHRs!\n", tid);
693 fetchStatus[tid] = IcacheWaitRetry;
698 DPRINTF(Fetch,
"[tid:%i]: Doing Icache access.\n", tid);
699 DPRINTF(Activity,
"[tid:%i]: Activity: Waiting on I-cache "
701 lastIcacheStall[tid] =
curTick();
702 fetchStatus[tid] = IcacheWaitResponse;
705 ppFetchRequestSent->notify(mem_req);
709 if (!(numInst < fetchWidth) || !(fetchQueue[tid].
size() < fetchQueueSize)) {
710 assert(!finishTranslationEvent.scheduled());
711 finishTranslationEvent.setFault(fault);
712 finishTranslationEvent.setReq(mem_req);
713 cpu->schedule(finishTranslationEvent,
714 cpu->clockEdge(
Cycles(1)));
717 DPRINTF(Fetch,
"[tid:%i] Got back req with addr %#x but expected %#x\n",
718 tid, mem_req->
getVaddr(), memReq[tid]->getVaddr());
728 DPRINTF(Fetch,
"[tid:%i]: Translation faulted, building noop.\n", tid);
732 NULL, fetchPC, fetchPC,
false);
734 instruction->setPredTarg(fetchPC);
735 instruction->fault = fault;
736 wroteToTimeBuffer =
true;
738 DPRINTF(Activity,
"Activity this cycle.\n");
739 cpu->activityThisCycle();
741 fetchStatus[tid] = TrapPending;
743 DPRINTF(Fetch,
"[tid:%i]: Blocked, need to handle the trap.\n", tid);
744 DPRINTF(Fetch,
"[tid:%i]: fault (%s) detected @ PC %s.\n",
745 tid, fault->name(),
pc[tid]);
747 _status = updateFetchStatus();
750 template <
class Impl>
755 DPRINTF(Fetch,
"[tid:%i]: Squashing, setting PC to: %s.\n",
759 fetchOffset[tid] = 0;
760 if (squashInst && squashInst->pcState().instAddr() == newPC.instAddr())
761 macroop[tid] = squashInst->macroop;
764 decoder[tid]->reset();
767 if (fetchStatus[tid] == IcacheWaitResponse) {
768 DPRINTF(Fetch,
"[tid:%i]: Squashing outstanding Icache miss.\n",
771 }
else if (fetchStatus[tid] == ItlbWait) {
772 DPRINTF(Fetch,
"[tid:%i]: Squashing outstanding ITLB miss.\n",
778 if (retryTid == tid) {
779 assert(cacheBlocked);
781 delete retryPkt->req;
788 fetchStatus[tid] = Squashing;
791 fetchQueue[tid].clear();
798 delayedCommit[tid] =
true;
809 DPRINTF(Fetch,
"[tid:%i]: Squashing from decode.\n", tid);
811 doSquash(newPC, squashInst, tid);
815 cpu->removeInstsUntil(seq_num, tid);
822 bool ret_val =
false;
824 if (stalls[tid].drain) {
825 assert(cpu->isDraining());
826 DPRINTF(Fetch,
"[tid:%i]: Drain stall detected.\n",tid);
841 while (threads != end) {
844 if (fetchStatus[tid] ==
Running ||
845 fetchStatus[tid] == Squashing ||
846 fetchStatus[tid] == IcacheAccessComplete) {
848 if (_status == Inactive) {
849 DPRINTF(Activity,
"[tid:%i]: Activating stage.\n",tid);
851 if (fetchStatus[tid] == IcacheAccessComplete) {
852 DPRINTF(Activity,
"[tid:%i]: Activating fetch due to cache"
856 cpu->activateStage(O3CPU::FetchIdx);
864 if (_status == Active) {
865 DPRINTF(Activity,
"Deactivating stage.\n");
867 cpu->deactivateStage(O3CPU::FetchIdx);
873 template <
class Impl>
879 DPRINTF(Fetch,
"[tid:%u]: Squash from commit.\n", tid);
881 doSquash(newPC, squashInst, tid);
884 cpu->removeInstsNotInROB(tid);
887 template <
class Impl>
893 bool status_change =
false;
895 wroteToTimeBuffer =
false;
898 issuePipelinedIfetch[
i] =
false;
901 while (threads != end) {
906 bool updated_status = checkSignalsAndUpdate(tid);
907 status_change = status_change || updated_status;
910 DPRINTF(Fetch,
"Running stage.\n");
913 if (fromCommit->commitInfo[0].interruptPending) {
914 interruptPending =
true;
917 if (fromCommit->commitInfo[0].clearInterrupt) {
918 interruptPending =
false;
922 for (threadFetched = 0; threadFetched < numFetchingThreads;
925 fetch(status_change);
929 fetchNisnDist.sample(numInst);
933 _status = updateFetchStatus();
938 if (issuePipelinedIfetch[
i]) {
939 pipelineIcacheAccesses(i);
945 unsigned insts_to_decode = 0;
946 unsigned available_insts = 0;
948 for (
auto tid : *activeThreads) {
949 if (!stalls[tid].decode) {
950 available_insts += fetchQueue[tid].size();
955 auto tid_itr = activeThreads->begin();
956 std::advance(tid_itr,
random_mt.
random<uint8_t>(0, activeThreads->size() - 1));
958 while (available_insts != 0 && insts_to_decode < decodeWidth) {
960 if (!stalls[tid].decode && !fetchQueue[tid].empty()) {
961 auto inst = fetchQueue[tid].front();
962 toDecode->insts[toDecode->size++] = inst;
963 DPRINTF(Fetch,
"[tid:%i][sn:%i]: Sending instruction to decode from "
964 "fetch queue. Fetch queue size: %i.\n",
965 tid, inst->seqNum, fetchQueue[tid].size());
967 wroteToTimeBuffer =
true;
968 fetchQueue[tid].pop_front();
975 if (tid_itr == activeThreads->end())
976 tid_itr = activeThreads->begin();
980 if (wroteToTimeBuffer) {
981 DPRINTF(Activity,
"Activity this cycle.\n");
982 cpu->activityThisCycle();
989 template <
class Impl>
994 if (fromDecode->decodeBlock[tid]) {
995 stalls[tid].decode =
true;
998 if (fromDecode->decodeUnblock[tid]) {
999 assert(stalls[tid].decode);
1000 assert(!fromDecode->decodeBlock[tid]);
1001 stalls[tid].decode =
false;
1005 if (fromCommit->commitInfo[tid].squash) {
1007 DPRINTF(Fetch,
"[tid:%u]: Squashing instructions due to squash "
1008 "from commit.\n",tid);
1010 squash(fromCommit->commitInfo[tid].pc,
1011 fromCommit->commitInfo[tid].doneSeqNum,
1012 fromCommit->commitInfo[tid].squashInst, tid);
1017 if (fromCommit->commitInfo[tid].mispredictInst &&
1018 fromCommit->commitInfo[tid].mispredictInst->isControl()) {
1019 branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum,
1020 fromCommit->commitInfo[tid].pc,
1021 fromCommit->commitInfo[tid].branchTaken,
1024 branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum,
1029 }
else if (fromCommit->commitInfo[tid].doneSeqNum) {
1032 branchPred->update(fromCommit->commitInfo[tid].doneSeqNum, tid);
1036 if (fromDecode->decodeInfo[tid].squash) {
1037 DPRINTF(Fetch,
"[tid:%u]: Squashing instructions due to squash "
1038 "from decode.\n",tid);
1041 if (fromDecode->decodeInfo[tid].branchMispredict) {
1042 branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum,
1043 fromDecode->decodeInfo[tid].nextPC,
1044 fromDecode->decodeInfo[tid].branchTaken,
1047 branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum,
1051 if (fetchStatus[tid] != Squashing) {
1053 DPRINTF(Fetch,
"Squashing from decode with PC = %s\n",
1054 fromDecode->decodeInfo[tid].nextPC);
1056 squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
1057 fromDecode->decodeInfo[tid].squashInst,
1058 fromDecode->decodeInfo[tid].doneSeqNum,
1065 if (checkStall(tid) &&
1066 fetchStatus[tid] != IcacheWaitResponse &&
1067 fetchStatus[tid] != IcacheWaitRetry &&
1068 fetchStatus[tid] != ItlbWait &&
1069 fetchStatus[tid] != QuiescePending) {
1070 DPRINTF(Fetch,
"[tid:%i]: Setting to blocked\n",tid);
1072 fetchStatus[tid] = Blocked;
1077 if (fetchStatus[tid] == Blocked ||
1078 fetchStatus[tid] == Squashing) {
1081 DPRINTF(Fetch,
"[tid:%i]: Done squashing, switching to running.\n",
1094 template<
class Impl>
1095 typename Impl::DynInstPtr
1101 InstSeqNum seq = cpu->getAndIncrementInstSeq();
1105 new DynInst(staticInst, curMacroop, thisPC, nextPC, seq, cpu);
1106 instruction->setTid(tid);
1108 instruction->setASID(tid);
1110 instruction->setThreadState(cpu->thread[tid]);
1112 DPRINTF(Fetch,
"[tid:%i]: Instruction PC %#x (%d) created "
1113 "[sn:%lli].\n", tid, thisPC.instAddr(),
1114 thisPC.microPC(), seq);
1116 DPRINTF(Fetch,
"[tid:%i]: Instruction is: %s\n", tid,
1117 instruction->staticInst->
1118 disassemble(thisPC.instAddr()));
1122 instruction->traceData =
1123 cpu->getTracer()->getInstRecord(
curTick(), cpu->tcBase(tid),
1124 instruction->staticInst, thisPC, curMacroop);
1127 instruction->traceData = NULL;
1131 instruction->setInstListIt(cpu->addInst(instruction));
1135 assert(numInst < fetchWidth);
1136 fetchQueue[tid].push_back(instruction);
1137 assert(fetchQueue[tid].
size() <= fetchQueueSize);
1138 DPRINTF(Fetch,
"[tid:%i]: Fetch queue entry created (%i/%i).\n",
1139 tid, fetchQueue[tid].
size(), fetchQueueSize);
1143 delayedCommit[tid] = instruction->isDelayedCommit();
1148 template<
class Impl>
1155 ThreadID tid = getFetchingThread(fetchPolicy);
1157 assert(!cpu->switchedOut());
1161 threadFetched = numFetchingThreads;
1163 if (numThreads == 1) {
1170 DPRINTF(Fetch,
"Attempting to fetch from [tid:%i]\n", tid);
1175 Addr pcOffset = fetchOffset[tid];
1176 Addr fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1183 if (fetchStatus[tid] == IcacheAccessComplete) {
1184 DPRINTF(Fetch,
"[tid:%i]: Icache miss is complete.\n", tid);
1187 status_change =
true;
1188 }
else if (fetchStatus[tid] ==
Running) {
1190 Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1195 if (!(fetchBufferValid[tid] && fetchBufferBlockPC == fetchBufferPC[tid])
1196 && !inRom && !macroop[tid]) {
1197 DPRINTF(Fetch,
"[tid:%i]: Attempting to translate and read "
1198 "instruction, starting at PC %s.\n", tid, thisPC);
1200 fetchCacheLine(fetchAddr, tid, thisPC.instAddr());
1202 if (fetchStatus[tid] == IcacheWaitResponse)
1203 ++icacheStallCycles;
1204 else if (fetchStatus[tid] == ItlbWait)
1207 ++fetchMiscStallCycles;
1209 }
else if ((checkInterrupt(thisPC.instAddr()) && !delayedCommit[tid])) {
1213 ++fetchMiscStallCycles;
1214 DPRINTF(Fetch,
"[tid:%i]: Fetch is stalled!\n", tid);
1218 if (fetchStatus[tid] == Idle) {
1220 DPRINTF(Fetch,
"[tid:%i]: Fetch is idle!\n", tid);
1238 DPRINTF(Fetch,
"[tid:%i]: Adding instructions to queue to "
1243 bool predictedBranch =
false;
1251 const unsigned numInsts = fetchBufferSize / instSize;
1252 unsigned blkOffset = (fetchAddr - fetchBufferPC[tid]) / instSize;
1257 while (numInst < fetchWidth && fetchQueue[tid].
size() < fetchQueueSize
1258 && !predictedBranch && !
quiesce) {
1262 bool needMem = !inRom && !curMacroop &&
1263 !decoder[tid]->instReady();
1264 fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1265 Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1270 if (!fetchBufferValid[tid] ||
1271 fetchBufferBlockPC != fetchBufferPC[tid])
1274 if (blkOffset >= numInsts) {
1282 Addr pcAddr = thisPC.instAddr() & BaseCPU::PCMask;
1283 while (fetchAddr != pcAddr && blkOffset < numInsts) {
1285 fetchAddr += instSize;
1287 if (blkOffset >= numInsts)
1292 decoder[tid]->moreBytes(thisPC, fetchAddr, inst);
1294 if (decoder[tid]->needMoreBytes()) {
1296 fetchAddr += instSize;
1297 pcOffset += instSize;
1304 if (!(curMacroop || inRom)) {
1305 if (decoder[tid]->instReady()) {
1306 staticInst = decoder[tid]->decode(thisPC);
1312 curMacroop = staticInst;
1325 bool newMacro =
false;
1326 if (curMacroop || inRom) {
1329 thisPC.microPC(), curMacroop);
1331 staticInst = curMacroop->
fetchMicroop(thisPC.microPC());
1337 buildInst(tid, staticInst, curMacroop,
1338 thisPC, nextPC,
true);
1340 ppFetch->notify(instruction);
1344 if (
DTRACE(O3PipeView)) {
1345 instruction->fetchTick =
curTick();
1353 predictedBranch |= thisPC.branching();
1355 lookupAndUpdateNextPC(instruction, nextPC);
1356 if (predictedBranch) {
1357 DPRINTF(Fetch,
"Branch detected with PC = %s\n", thisPC);
1360 newMacro |= thisPC.instAddr() != nextPC.instAddr();
1367 fetchAddr = thisPC.instAddr() & BaseCPU::PCMask;
1368 blkOffset = (fetchAddr - fetchBufferPC[tid]) / instSize;
1373 if (instruction->isQuiesce()) {
1375 "Quiesce instruction encountered, halting fetch!\n");
1376 fetchStatus[tid] = QuiescePending;
1377 status_change =
true;
1381 }
while ((curMacroop || decoder[tid]->instReady()) &&
1382 numInst < fetchWidth &&
1383 fetchQueue[tid].
size() < fetchQueueSize);
1390 if (predictedBranch) {
1391 DPRINTF(Fetch,
"[tid:%i]: Done fetching, predicted branch "
1392 "instruction encountered.\n", tid);
1393 }
else if (numInst >= fetchWidth) {
1394 DPRINTF(Fetch,
"[tid:%i]: Done fetching, reached fetch bandwidth "
1395 "for this cycle.\n", tid);
1396 }
else if (blkOffset >= fetchBufferSize) {
1397 DPRINTF(Fetch,
"[tid:%i]: Done fetching, reached the end of the"
1398 "fetch buffer.\n", tid);
1401 macroop[tid] = curMacroop;
1402 fetchOffset[tid] = pcOffset;
1405 wroteToTimeBuffer =
true;
1412 fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1413 Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1414 issuePipelinedIfetch[tid] = fetchBufferBlockPC != fetchBufferPC[tid] &&
1415 fetchStatus[tid] != IcacheWaitResponse &&
1416 fetchStatus[tid] != ItlbWait &&
1417 fetchStatus[tid] != IcacheWaitRetry &&
1418 fetchStatus[tid] != QuiescePending &&
1422 template<
class Impl>
1426 if (retryPkt != NULL) {
1427 assert(cacheBlocked);
1429 assert(fetchStatus[retryTid] == IcacheWaitRetry);
1431 if (cpu->getInstPort().sendTimingReq(retryPkt)) {
1432 fetchStatus[retryTid] = IcacheWaitResponse;
1435 ppFetchRequestSent->notify(retryPkt->req);
1438 cacheBlocked =
false;
1444 cacheBlocked =
false;
1453 template<
class Impl>
1457 if (numThreads > 1) {
1458 switch (fetch_priority) {
1464 return roundRobin();
1473 return branchCount();
1480 if (thread == activeThreads->end()) {
1486 if (fetchStatus[tid] ==
Running ||
1487 fetchStatus[tid] == IcacheAccessComplete ||
1488 fetchStatus[tid] == Idle) {
1497 template<
class Impl>
1506 while (pri_iter != end) {
1507 high_pri = *pri_iter;
1509 assert(high_pri <= numThreads);
1511 if (fetchStatus[high_pri] ==
Running ||
1512 fetchStatus[high_pri] == IcacheAccessComplete ||
1513 fetchStatus[high_pri] == Idle) {
1515 priorityList.erase(pri_iter);
1516 priorityList.push_back(high_pri);
1527 template<
class Impl>
1532 std::priority_queue<unsigned,vector<unsigned>,
1533 std::greater<unsigned> > PQ;
1534 std::map<unsigned, ThreadID> threadMap;
1539 while (threads != end) {
1541 unsigned iqCount = fromIEW->iewInfo[tid].iqCount;
1546 threadMap[iqCount] = tid;
1549 while (!PQ.empty()) {
1550 ThreadID high_pri = threadMap[PQ.top()];
1552 if (fetchStatus[high_pri] ==
Running ||
1553 fetchStatus[high_pri] == IcacheAccessComplete ||
1554 fetchStatus[high_pri] == Idle)
1564 template<
class Impl>
1569 std::priority_queue<unsigned,vector<unsigned>,
1570 std::greater<unsigned> > PQ;
1571 std::map<unsigned, ThreadID> threadMap;
1576 while (threads != end) {
1578 unsigned ldstqCount = fromIEW->iewInfo[tid].ldstqCount;
1582 PQ.push(ldstqCount);
1583 threadMap[ldstqCount] = tid;
1586 while (!PQ.empty()) {
1587 ThreadID high_pri = threadMap[PQ.top()];
1589 if (fetchStatus[high_pri] ==
Running ||
1590 fetchStatus[high_pri] == IcacheAccessComplete ||
1591 fetchStatus[high_pri] == Idle)
1600 template<
class Impl>
1606 assert(thread != activeThreads->end());
1610 panic(
"Branch Count Fetch policy unimplemented\n");
1614 template<
class Impl>
1618 if (!issuePipelinedIfetch[tid]) {
1629 Addr pcOffset = fetchOffset[tid];
1630 Addr fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1633 Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1636 if (!(fetchBufferValid[tid] && fetchBufferBlockPC == fetchBufferPC[tid])) {
1637 DPRINTF(Fetch,
"[tid:%i]: Issuing a pipelined I-cache access, "
1638 "starting at PC %s.\n", tid, thisPC);
1640 fetchCacheLine(fetchAddr, tid, thisPC.instAddr());
1644 template<
class Impl>
1647 DPRINTF(Fetch,
"There are no more threads available to fetch from.\n");
1651 if (stalls[tid].drain) {
1652 ++fetchPendingDrainCycles;
1653 DPRINTF(Fetch,
"Fetch is waiting for a drain!\n");
1654 }
else if (activeThreads->empty()) {
1655 ++fetchNoActiveThreadStallCycles;
1656 DPRINTF(Fetch,
"Fetch has no active thread!\n");
1657 }
else if (fetchStatus[tid] == Blocked) {
1658 ++fetchBlockedCycles;
1659 DPRINTF(Fetch,
"[tid:%i]: Fetch is blocked!\n", tid);
1660 }
else if (fetchStatus[tid] == Squashing) {
1661 ++fetchSquashCycles;
1662 DPRINTF(Fetch,
"[tid:%i]: Fetch is squashing!\n", tid);
1663 }
else if (fetchStatus[tid] == IcacheWaitResponse) {
1664 ++icacheStallCycles;
1665 DPRINTF(Fetch,
"[tid:%i]: Fetch is waiting cache response!\n",
1667 }
else if (fetchStatus[tid] == ItlbWait) {
1669 DPRINTF(Fetch,
"[tid:%i]: Fetch is waiting ITLB walk to "
1671 }
else if (fetchStatus[tid] == TrapPending) {
1672 ++fetchPendingTrapStallCycles;
1673 DPRINTF(Fetch,
"[tid:%i]: Fetch is waiting for a pending trap!\n",
1675 }
else if (fetchStatus[tid] == QuiescePending) {
1676 ++fetchPendingQuiesceStallCycles;
1677 DPRINTF(Fetch,
"[tid:%i]: Fetch is waiting for a pending quiesce "
1678 "instruction!\n", tid);
1679 }
else if (fetchStatus[tid] == IcacheWaitRetry) {
1680 ++fetchIcacheWaitRetryStallCycles;
1681 DPRINTF(Fetch,
"[tid:%i]: Fetch is waiting for an I-cache retry!\n",
1683 }
else if (fetchStatus[tid] == NoGoodAddr) {
1684 DPRINTF(Fetch,
"[tid:%i]: Fetch predicted non-executable address\n",
1687 DPRINTF(Fetch,
"[tid:%i]: Unexpected fetch stall reason (Status: %i).\n",
1688 tid, fetchStatus[tid]);
1692 #endif//__CPU_O3_FETCH_IMPL_HH__
const FlagsType pdf
Print the percent of the total that this entry represents.
unsigned fetchWidth
The width of fetch in instructions.
ThreadID iqCount()
Returns the appropriate thread to fetch using the IQ count policy.
void profileStall(ThreadID tid)
Profile the reasons of fetch stall.
TheISA::Decoder * decoder[Impl::MaxThreads]
The decoder.
decltype(nullptr) constexpr NoFault
Cycles is a wrapper class for representing cycle counts, i.e.
const std::string & name()
void tick()
Ticks the fetch stage, processing all inputs signals and fetching as many instructions as possible...
FetchPriority fetchPolicy
Fetch policy.
void resetStage()
Reset this pipeline stage.
void squashFromDecode(const TheISA::PCState &newPC, const DynInstPtr squashInst, const InstSeqNum seq_num, ThreadID tid)
Squashes a specific thread and resets the PC.
ContextID contextId() const
Accessor function for context ID.
FetchPriority
Fetching Policy, Add new policies here.
void pipelineIcacheAccesses(ThreadID tid)
Pipeline the next I-cache access to the current one.
void drainSanityCheck() const
Perform sanity checks after a drain.
Addr fetchBufferPC[Impl::MaxThreads]
The PC of the first instruction loaded into the fetch buffer.
Impl::DynInstPtr DynInstPtr
bool lookupAndUpdateNextPC(DynInstPtr &inst, TheISA::PCState &pc)
Looks up in the branch predictor to see if the next PC should be either next PC+=MachInst or a branch...
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
void processCacheCompletion(PacketPtr pkt)
Processes cache completion event.
virtual StaticInstPtr fetchMicroop(MicroPC upc) const
Return the microop that goes with a particular micropc.
void setAccessLatency()
Set/Get the time taken to complete this request's access, not including the time to successfully tran...
ThreadID numThreads
Number of threads.
std::enable_if< std::is_integral< T >::value, T >::type random()
Use the SFINAE idiom to choose an implementation based on whether the type is integral or floating po...
#define ISA_HAS_DELAY_SLOT
FetchStatus
Overall fetch status.
void deactivateThread(ThreadID tid)
For priority-based fetch policies, need to keep update priorityList.
TheISA::MachInst MachInst
Typedefs from ISA.
void takeOverFrom()
Takes over from another CPU's thread.
void drainStall(ThreadID tid)
Stall the fetch stage after reaching a safe drain point.
ThreadID getFetchingThread(FetchPriority &fetch_priority)
Returns the appropriate thread to fetch, given the fetch policy.
Tick curTick()
The current simulated tick.
void quiesce(ThreadContext *tc)
void regStats()
Registers statistics.
bool isDrained() const
Has the stage drained?
ThreadID roundRobin()
Returns the appropriate thread to fetch using a round robin policy.
const ExtMachInst NoopMachInst
void switchToActive()
Changes the status of this stage to active, and indicates this to the CPU.
int instSize
Size of instructions.
bool checkStall(ThreadID tid) const
Checks if a thread is stalled.
void fetch(bool &status_change)
Does the actual fetching of instructions and passing them on to the next stage.
void finishTranslation(const Fault &fault, RequestPtr mem_req)
const RequestPtr req
A pointer to the original request.
bool fetchCacheLine(Addr vaddr, ThreadID tid, Addr pc)
Fetches the cache line that contains the fetch PC.
void recvReqRetry()
Handles retrying the fetch access.
DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
DefaultFetch constructor.
void setActiveThreads(std::list< ThreadID > *at_ptr)
Sets pointer to list of active threads.
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,16,32,64}_t.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
void regProbePoints()
Registers probes.
void advancePC(PCState &pc, const StaticInstPtr &inst)
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
uint8_t * fetchBuffer[Impl::MaxThreads]
The fetch data that is being fetched and buffered.
static bool isRomMicroPC(MicroPC upc)
ThreadID branchCount()
Returns the appropriate thread to fetch using the branch count policy.
const FlagsType total
Print the total.
const ThreadID InvalidThreadID
int16_t ThreadID
Thread index/ID type.
void setTimeBuffer(TimeBuffer< TimeStruct > *time_buffer)
Sets the main backwards communication time buffer pointer.
void setFetchQueue(TimeBuffer< FetchStruct > *fq_ptr)
Sets pointer to time buffer used to communicate to the next stage.
Declaration of the Packet class.
GenericISA::SimplePCState< MachInst > PCState
The request was an instruction fetch.
FetchStatus updateFetchStatus()
Updates overall fetch stage status; to be called at the end of each cycle.
void switchToInactive()
Changes the status of this stage to inactive, and indicates this to the CPU.
void startupStage()
Initialize stage.
void dataDynamic(T *p)
Set the data pointer to a value that should have delete [] called on it.
void squash(const TheISA::PCState &newPC, const InstSeqNum seq_num, DynInstPtr squashInst, ThreadID tid)
Squashes a specific thread and resets the PC.
unsigned fetchBufferSize
The size of the fetch buffer in bytes.
ThreadID lsqCount()
Returns the appropriate thread to fetch using the LSQ count policy.
void wakeFromQuiesce()
Tells fetch to wake up from a quiesce instruction.
const T * getConstPtr() const
void drainResume()
Resume after a drain.
bool checkSignalsAndUpdate(ThreadID tid)
Checks all input signals and updates the status as necessary.
std::string name() const
Returns the name of fetch.
DynInstPtr buildInst(ThreadID tid, StaticInstPtr staticInst, StaticInstPtr curMacroop, TheISA::PCState thisPC, TheISA::PCState nextPC, bool trace)
bool isLastMicroop() const
std::shared_ptr< FaultBase > Fault
BPredUnit * branchPred
BPredUnit.
void doSquash(const TheISA::PCState &newPC, const DynInstPtr squashInst, ThreadID tid)
Squashes a specific thread and resets the PC.
unsigned int cacheBlkSize
Cache block size.
bool fetchBufferValid[Impl::MaxThreads]
Whether or not the fetch buffer data is valid.
ProbePointArg< PacketInfo > Packet
Packet probe point.