43 #ifndef __CPU_O3_DECODE_IMPL_HH__
44 #define __CPU_O3_DECODE_IMPL_HH__
46 #include "arch/types.hh"
48 #include "config/the_isa.hh"
51 #include "debug/Activity.hh"
52 #include "debug/Decode.hh"
53 #include "debug/O3PipeView.hh"
54 #include "params/DerivO3CPU.hh"
64 renameToDecodeDelay(params->renameToDecodeDelay),
65 iewToDecodeDelay(params->iewToDecodeDelay),
66 commitToDecodeDelay(params->commitToDecodeDelay),
67 fetchToDecodeDelay(params->fetchToDecodeDelay),
68 decodeWidth(params->decodeWidth),
69 numThreads(params->numThreads)
72 fatal(
"decodeWidth (%d) is larger than compiled limit (%d),\n"
73 "\tincrease MaxWidth in src/cpu/o3/impl.hh\n",
94 for (
ThreadID tid = 0; tid < numThreads; ++tid) {
95 decodeStatus[tid] = Idle;
97 stalls[tid].rename =
false;
101 template <
class Impl>
105 return cpu->name() +
".decode";
108 template <
class Impl>
113 .name(
name() +
".IdleCycles")
114 .desc(
"Number of cycles decode is idle")
115 .prereq(decodeIdleCycles);
117 .name(
name() +
".BlockedCycles")
118 .desc(
"Number of cycles decode is blocked")
119 .prereq(decodeBlockedCycles);
121 .name(
name() +
".RunCycles")
122 .desc(
"Number of cycles decode is running")
123 .prereq(decodeRunCycles);
125 .name(
name() +
".UnblockCycles")
126 .desc(
"Number of cycles decode is unblocking")
127 .prereq(decodeUnblockCycles);
129 .name(
name() +
".SquashCycles")
130 .desc(
"Number of cycles decode is squashing")
131 .prereq(decodeSquashCycles);
133 .name(
name() +
".BranchResolved")
134 .desc(
"Number of times decode resolved a branch")
135 .prereq(decodeBranchResolved);
137 .name(
name() +
".BranchMispred")
138 .desc(
"Number of times decode detected a branch misprediction")
139 .prereq(decodeBranchMispred);
141 .name(
name() +
".ControlMispred")
142 .desc(
"Number of times decode detected an instruction incorrectly"
143 " predicted as a control")
144 .prereq(decodeControlMispred);
146 .name(
name() +
".DecodedInsts")
147 .desc(
"Number of instructions handled by decode")
148 .prereq(decodeDecodedInsts);
150 .name(
name() +
".SquashedInsts")
151 .desc(
"Number of squashed instructions handled by decode")
152 .prereq(decodeSquashedInsts);
162 toFetch = timeBuffer->
getWire(0);
165 fromRename = timeBuffer->getWire(-renameToDecodeDelay);
166 fromIEW = timeBuffer->getWire(-iewToDecodeDelay);
167 fromCommit = timeBuffer->getWire(-commitToDecodeDelay);
174 decodeQueue = dq_ptr;
177 toRename = decodeQueue->
getWire(0);
187 fromFetch = fetchQueue->
getWire(-fetchToDecodeDelay);
194 activeThreads = at_ptr;
197 template <
class Impl>
201 for (
ThreadID tid = 0; tid < numThreads; ++tid) {
202 assert(insts[tid].empty());
203 assert(skidBuffer[tid].empty());
207 template <
class Impl>
211 for (
ThreadID tid = 0; tid < numThreads; ++tid) {
212 if (!insts[tid].empty() || !skidBuffer[tid].empty() ||
213 (decodeStatus[tid] !=
Running && decodeStatus[tid] != Idle))
223 bool ret_val =
false;
225 if (stalls[tid].rename) {
226 DPRINTF(Decode,
"[tid:%i]: Stall fom Rename stage detected.\n", tid);
237 return fromFetch->size > 0;
244 DPRINTF(Decode,
"[tid:%u]: Blocking.\n", tid);
253 if (decodeStatus[tid] != Blocked) {
255 decodeStatus[tid] = Blocked;
257 if (toFetch->decodeUnblock[tid]) {
258 toFetch->decodeUnblock[tid] =
false;
260 toFetch->decodeBlock[tid] =
true;
261 wroteToTimeBuffer =
true;
275 if (skidBuffer[tid].empty()) {
276 DPRINTF(Decode,
"[tid:%u]: Done unblocking.\n", tid);
277 toFetch->decodeUnblock[tid] =
true;
278 wroteToTimeBuffer =
true;
284 DPRINTF(Decode,
"[tid:%u]: Currently unblocking.\n", tid);
293 DPRINTF(Decode,
"[tid:%i]: [sn:%i] Squashing due to incorrect branch "
294 "prediction detected at decode.\n", tid, inst->seqNum);
297 toFetch->decodeInfo[tid].branchMispredict =
true;
298 toFetch->decodeInfo[tid].predIncorrect =
true;
299 toFetch->decodeInfo[tid].mispredictInst = inst;
300 toFetch->decodeInfo[tid].squash =
true;
301 toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum;
302 toFetch->decodeInfo[tid].nextPC = inst->branchTarget();
303 toFetch->decodeInfo[tid].branchTaken = inst->pcState().branching();
304 toFetch->decodeInfo[tid].squashInst = inst;
305 if (toFetch->decodeInfo[tid].mispredictInst->isUncondCtrl()) {
306 toFetch->decodeInfo[tid].branchTaken =
true;
312 if (decodeStatus[tid] == Blocked ||
313 decodeStatus[tid] == Unblocking) {
314 toFetch->decodeUnblock[tid] = 1;
318 decodeStatus[tid] = Squashing;
320 for (
int i=0;
i<fromFetch->size;
i++) {
321 if (fromFetch->insts[
i]->threadNumber == tid &&
322 fromFetch->insts[
i]->seqNum > squash_seq_num) {
323 fromFetch->insts[
i]->setSquashed();
329 while (!insts[tid].empty()) {
333 while (!skidBuffer[tid].empty()) {
334 skidBuffer[tid].pop();
338 cpu->removeInstsUntil(squash_seq_num, tid);
345 DPRINTF(Decode,
"[tid:%i]: Squashing.\n",tid);
347 if (decodeStatus[tid] == Blocked ||
348 decodeStatus[tid] == Unblocking) {
350 toFetch->decodeUnblock[tid] = 1;
356 if (toFetch->decodeBlock[tid])
357 toFetch->decodeBlock[tid] = 0;
359 toFetch->decodeUnblock[tid] = 1;
364 decodeStatus[tid] = Squashing;
367 unsigned squash_count = 0;
369 for (
int i=0;
i<fromFetch->size;
i++) {
370 if (fromFetch->insts[
i]->threadNumber == tid) {
371 fromFetch->insts[
i]->setSquashed();
378 while (!insts[tid].empty()) {
382 while (!skidBuffer[tid].empty()) {
383 skidBuffer[tid].pop();
395 while (!insts[tid].empty()) {
396 inst = insts[tid].front();
400 assert(tid == inst->threadNumber);
402 skidBuffer[tid].push(inst);
404 DPRINTF(Decode,
"Inserting [tid:%d][sn:%lli] PC: %s into decode skidBuffer %i\n",
405 inst->threadNumber, inst->seqNum, inst->pcState(), skidBuffer[tid].size());
410 assert(skidBuffer[tid].
size() <= skidBufferMax);
420 while (threads != end) {
422 if (!skidBuffer[tid].empty())
433 bool any_unblocking =
false;
438 while (threads != end) {
441 if (decodeStatus[tid] == Unblocking) {
442 any_unblocking =
true;
448 if (any_unblocking) {
449 if (_status == Inactive) {
452 DPRINTF(Activity,
"Activating stage.\n");
454 cpu->activateStage(O3CPU::DecodeIdx);
459 if (_status == Active) {
461 DPRINTF(Activity,
"Deactivating stage.\n");
463 cpu->deactivateStage(O3CPU::DecodeIdx);
468 template <
class Impl>
472 int insts_from_fetch = fromFetch->size;
473 for (
int i = 0;
i < insts_from_fetch; ++
i) {
474 insts[fromFetch->insts[
i]->threadNumber].push(fromFetch->insts[
i]);
482 if (fromRename->renameBlock[tid]) {
483 stalls[tid].rename =
true;
486 if (fromRename->renameUnblock[tid]) {
487 assert(stalls[tid].rename);
488 stalls[tid].rename =
false;
492 template <
class Impl>
505 readStallSignals(tid);
508 if (fromCommit->commitInfo[tid].squash) {
510 DPRINTF(Decode,
"[tid:%u]: Squashing instructions due to squash "
511 "from commit.\n", tid);
518 if (checkStall(tid)) {
522 if (decodeStatus[tid] == Blocked) {
523 DPRINTF(Decode,
"[tid:%u]: Done blocking, switching to unblocking.\n",
526 decodeStatus[tid] = Unblocking;
533 if (decodeStatus[tid] == Squashing) {
536 DPRINTF(Decode,
"[tid:%u]: Done squashing, switching to running.\n",
553 wroteToTimeBuffer =
false;
555 bool status_change =
false;
565 while (threads != end) {
568 DPRINTF(Decode,
"Processing [tid:%i]\n",tid);
569 status_change = checkSignalsAndUpdate(tid) || status_change;
571 decode(status_change, tid);
578 if (wroteToTimeBuffer) {
579 DPRINTF(Activity,
"Activity this cycle.\n");
581 cpu->activityThisCycle();
596 if (decodeStatus[tid] == Blocked) {
597 ++decodeBlockedCycles;
598 }
else if (decodeStatus[tid] == Squashing) {
599 ++decodeSquashCycles;
604 if (decodeStatus[tid] ==
Running ||
605 decodeStatus[tid] == Idle) {
606 DPRINTF(Decode,
"[tid:%u]: Not blocked, so attempting to run "
610 }
else if (decodeStatus[tid] == Unblocking) {
613 assert(!skidsEmpty());
620 if (fetchInstsValid()) {
626 status_change = unblock(tid) || status_change;
630 template <
class Impl>
636 int insts_available = decodeStatus[tid] == Unblocking ?
637 skidBuffer[tid].size() : insts[tid].size();
639 if (insts_available == 0) {
640 DPRINTF(Decode,
"[tid:%u] Nothing to do, breaking out"
645 }
else if (decodeStatus[tid] == Unblocking) {
646 DPRINTF(Decode,
"[tid:%u] Unblocking, removing insts from skid "
648 ++decodeUnblockCycles;
649 }
else if (decodeStatus[tid] ==
Running) {
655 std::queue<DynInstPtr>
656 &insts_to_decode = decodeStatus[tid] == Unblocking ?
657 skidBuffer[tid] : insts[tid];
659 DPRINTF(Decode,
"[tid:%u]: Sending instruction to rename.\n",tid);
661 while (insts_available > 0 && toRenameIndex < decodeWidth) {
662 assert(!insts_to_decode.empty());
664 inst = insts_to_decode.front();
666 insts_to_decode.pop();
668 DPRINTF(Decode,
"[tid:%u]: Processing instruction [sn:%lli] with "
669 "PC %s\n", tid, inst->seqNum, inst->pcState());
671 if (inst->isSquashed()) {
672 DPRINTF(Decode,
"[tid:%u]: Instruction %i with PC %s is "
673 "squashed, skipping.\n",
674 tid, inst->seqNum, inst->pcState());
676 ++decodeSquashedInsts;
687 if (inst->numSrcRegs() == 0) {
694 toRename->insts[toRenameIndex] = inst;
698 ++decodeDecodedInsts;
703 inst->decodeTick =
curTick() - inst->fetchTick;
709 if (inst->readPredTaken() && !inst->isControl()) {
710 panic(
"Instruction predicted as a branch!");
712 ++decodeControlMispred;
716 squash(inst, inst->threadNumber);
724 if (inst->isDirectCtrl() &&
725 (inst->isUncondCtrl() || inst->readPredTaken()))
727 ++decodeBranchResolved;
729 if (!(inst->branchTarget() == inst->readPredTarg())) {
730 ++decodeBranchMispred;
734 squash(inst, inst->threadNumber);
737 DPRINTF(Decode,
"[sn:%i]: Updating predictions: PredPC: %s\n",
738 inst->seqNum, target);
740 inst->setPredTarg(target);
748 if (!insts_to_decode.empty()) {
755 wroteToTimeBuffer =
true;
759 #endif//__CPU_O3_DECODE_IMPL_HH__
Cycles fetchToDecodeDelay
Fetch to decode delay.
void decode(bool &status_change, ThreadID tid)
Determines what to do based on decode's current status.
void setDecodeQueue(TimeBuffer< DecodeStruct > *dq_ptr)
Sets pointer to time buffer used to communicate to the next stage.
void sortInsts()
Separates instructions from fetch into individual lists of instructions sorted by thread...
const std::string & name()
bool isDrained() const
Has the stage drained?
void tick()
Ticks decode, processing all input signals and decoding as many instructions as possible.
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params)
DefaultDecode constructor.
bool skidsEmpty()
Returns if all of the skid buffers are empty.
void skidInsert(ThreadID tid)
Inserts a thread's instructions into the skid buffer, to be decoded once decode unblocks.
unsigned decodeWidth
The width of decode, in instructions.
void regStats()
Registers statistics.
unsigned skidBufferMax
Maximum size of the skid buffer.
Tick curTick()
The current simulated tick.
std::string name() const
Returns the name of decode.
void drainSanityCheck() const
Perform sanity checks after a drain.
void squash(DynInstPtr &inst, ThreadID tid)
Squashes if there is a PC-relative branch that was predicted incorrectly.
bool checkStall(ThreadID tid) const
Checks all stall signals, and returns if any are true.
void readStallSignals(ThreadID tid)
Reads all stall signals from the backwards communication timebuffer.
Impl::DynInstPtr DynInstPtr
bool block(ThreadID tid)
Switches decode to blocking, and signals back that decode has become blocked.
void setActiveThreads(std::list< ThreadID > *at_ptr)
Sets pointer to list of active threads.
void decodeInsts(ThreadID tid)
Processes instructions from fetch and passes them on to rename.
int16_t ThreadID
Thread index/ID type.
GenericISA::SimplePCState< MachInst > PCState
bool checkSignalsAndUpdate(ThreadID tid)
Checks all input signals and updates decode's status appropriately.
void setFetchQueue(TimeBuffer< FetchStruct > *fq_ptr)
Sets pointer to time buffer coming from fetch.
bool unblock(ThreadID tid)
Switches decode to unblocking if the skid buffer is empty, and signals back that decode has unblocked...
void updateStatus()
Updates overall decode status based on all of the threads' statuses.
void setTimeBuffer(TimeBuffer< TimeStruct > *tb_ptr)
Sets the main backwards communication time buffer pointer.
bool fetchInstsValid()
Returns if there any instructions from fetch on this cycle.