cpu: Fix o3 front-end pipeline interlock behavior

The o3 pipeline interlock/stall logic is incorrect.  o3 unnecessicarily stalled
fetch and decode due to later stages in the pipeline.  In general, a stage
should usually only consider if it is stalled by the adjacent, downstream stage.
Forcing stalls due to later stages creates and results in bubbles in the
pipeline.  Additionally, o3 stalled the entire frontend (fetch, decode, rename)
on a branch mispredict while the ROB is being serially walked to update the
RAT (robSquashing). Only should have stalled at rename.
This commit is contained in:
Mitch Hayenga 2014-09-03 07:42:34 -04:00
parent 976f27487b
commit 1716749c8c
10 changed files with 26 additions and 212 deletions

View file

@ -229,8 +229,6 @@ struct TimeBufStruct {
bool renameUnblock[Impl::MaxThreads];
bool iewBlock[Impl::MaxThreads];
bool iewUnblock[Impl::MaxThreads];
bool commitBlock[Impl::MaxThreads];
bool commitUnblock[Impl::MaxThreads];
};
#endif //__CPU_O3_COMM_HH__

View file

@ -185,9 +185,6 @@ class DefaultCommit
/** Sets the pointer to the IEW stage. */
void setIEWStage(IEW *iew_stage);
/** Skid buffer between rename and commit. */
std::queue<DynInstPtr> skidBuffer;
/** The pointer to the IEW stage. Used solely to ensure that
* various events (traps, interrupts, syscalls) do not occur until
* all stores have written back.
@ -251,11 +248,6 @@ class DefaultCommit
*/
void setNextStatus();
/** Checks if the ROB is completed with squashing. This is for the case
* where the ROB can take multiple cycles to complete squashing.
*/
bool robDoneSquashing();
/** Returns if any of the threads have the number of ROB entries changed
* on this cycle. Used to determine if the number of free ROB entries needs
* to be sent back to previous stages.
@ -321,9 +313,6 @@ class DefaultCommit
/** Gets instructions from rename and inserts them into the ROB. */
void getInsts();
/** Insert all instructions from rename into skidBuffer */
void skidInsert();
/** Marks completed instructions using information sent from IEW. */
void markCompletedInsts();

View file

@ -1333,29 +1333,6 @@ DefaultCommit<Impl>::getInsts()
}
}
template <class Impl>
void
DefaultCommit<Impl>::skidInsert()
{
DPRINTF(Commit, "Attempting to any instructions from rename into "
"skidBuffer.\n");
for (int inst_num = 0; inst_num < fromRename->size; ++inst_num) {
DynInstPtr inst = fromRename->insts[inst_num];
if (!inst->isSquashed()) {
DPRINTF(Commit, "Inserting PC %s [sn:%i] [tid:%i] into ",
"skidBuffer.\n", inst->pcState(), inst->seqNum,
inst->threadNumber);
skidBuffer.push(inst);
} else {
DPRINTF(Commit, "Instruction PC %s [sn:%i] [tid:%i] was "
"squashed, skipping.\n",
inst->pcState(), inst->seqNum, inst->threadNumber);
}
}
}
template <class Impl>
void
DefaultCommit<Impl>::markCompletedInsts()
@ -1379,23 +1356,6 @@ DefaultCommit<Impl>::markCompletedInsts()
}
}
template <class Impl>
bool
DefaultCommit<Impl>::robDoneSquashing()
{
list<ThreadID>::iterator threads = activeThreads->begin();
list<ThreadID>::iterator end = activeThreads->end();
while (threads != end) {
ThreadID tid = *threads++;
if (!rob->isDoneSquashing(tid))
return false;
}
return true;
}
template <class Impl>
void
DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)

View file

@ -126,7 +126,7 @@ class DefaultDecode
void drainSanityCheck() const;
/** Has the stage drained? */
bool isDrained() const { return true; }
bool isDrained() const;
/** Takes over from another CPU's thread. */
void takeOverFrom() { resetStage(); }
@ -249,8 +249,6 @@ class DefaultDecode
/** Source of possible stalls. */
struct Stalls {
bool rename;
bool iew;
bool commit;
};
/** Tracks which stages are telling decode to stall. */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 ARM Limited
* Copyright (c) 2012, 2014 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@ -95,8 +95,6 @@ DefaultDecode<Impl>::resetStage()
decodeStatus[tid] = Idle;
stalls[tid].rename = false;
stalls[tid].iew = false;
stalls[tid].commit = false;
}
}
@ -206,6 +204,17 @@ DefaultDecode<Impl>::drainSanityCheck() const
}
}
template <class Impl>
bool
DefaultDecode<Impl>::isDrained() const
{
for (ThreadID tid = 0; tid < numThreads; ++tid) {
if (!insts[tid].empty() || !skidBuffer[tid].empty())
return false;
}
return true;
}
template<class Impl>
bool
DefaultDecode<Impl>::checkStall(ThreadID tid) const
@ -215,12 +224,6 @@ DefaultDecode<Impl>::checkStall(ThreadID tid) const
if (stalls[tid].rename) {
DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid);
ret_val = true;
} else if (stalls[tid].iew) {
DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid);
ret_val = true;
} else if (stalls[tid].commit) {
DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid);
ret_val = true;
}
return ret_val;
@ -395,10 +398,10 @@ DefaultDecode<Impl>::skidInsert(ThreadID tid)
assert(tid == inst->threadNumber);
DPRINTF(Decode,"Inserting [sn:%lli] PC: %s into decode skidBuffer %i\n",
inst->seqNum, inst->pcState(), inst->threadNumber);
skidBuffer[tid].push(inst);
DPRINTF(Decode,"Inserting [tid:%d][sn:%lli] PC: %s into decode skidBuffer %i\n",
inst->threadNumber, inst->seqNum, inst->pcState(), skidBuffer[tid].size());
}
// @todo: Eventually need to enforce this by not letting a thread
@ -483,24 +486,6 @@ DefaultDecode<Impl>::readStallSignals(ThreadID tid)
assert(stalls[tid].rename);
stalls[tid].rename = false;
}
if (fromIEW->iewBlock[tid]) {
stalls[tid].iew = true;
}
if (fromIEW->iewUnblock[tid]) {
assert(stalls[tid].iew);
stalls[tid].iew = false;
}
if (fromCommit->commitBlock[tid]) {
stalls[tid].commit = true;
}
if (fromCommit->commitUnblock[tid]) {
assert(stalls[tid].commit);
stalls[tid].commit = false;
}
}
template <class Impl>
@ -529,16 +514,6 @@ DefaultDecode<Impl>::checkSignalsAndUpdate(ThreadID tid)
return true;
}
// Check ROB squash signals from commit.
if (fromCommit->commitInfo[tid].robSquashing) {
DPRINTF(Decode, "[tid:%u]: ROB is still squashing.\n", tid);
// Continue to squash.
decodeStatus[tid] = Squashing;
return true;
}
if (checkStall(tid)) {
return block(tid);
}

View file

@ -434,9 +434,6 @@ class DefaultFetch
/** Source of possible stalls. */
struct Stalls {
bool decode;
bool rename;
bool iew;
bool commit;
bool drain;
};

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2013 ARM Limited
* Copyright (c) 2010-2014 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@ -354,9 +354,6 @@ DefaultFetch<Impl>::resetStage()
memReq[tid] = NULL;
stalls[tid].decode = false;
stalls[tid].rename = false;
stalls[tid].iew = false;
stalls[tid].commit = false;
stalls[tid].drain = false;
fetchBufferPC[tid] = 0;
@ -435,10 +432,6 @@ DefaultFetch<Impl>::drainSanityCheck() const
for (ThreadID i = 0; i < numThreads; ++i) {
assert(!memReq[i]);
assert(!stalls[i].decode);
assert(!stalls[i].rename);
assert(!stalls[i].iew);
assert(!stalls[i].commit);
assert(fetchStatus[i] == Idle || stalls[i].drain);
}
@ -680,7 +673,11 @@ DefaultFetch<Impl>::finishTranslation(Fault fault, RequestPtr mem_req)
fetchStatus[tid] = IcacheWaitResponse;
}
} else {
if (!(numInst < fetchWidth)) {
// Don't send an instruction to decode if it can't handle it.
// Asynchronous nature of this function's calling means we have to
// check 2 signals to see if decode is stalled.
if (!(numInst < fetchWidth) || stalls[tid].decode ||
fromDecode->decodeBlock[tid]) {
assert(!finishTranslationEvent.scheduled());
finishTranslationEvent.setFault(fault);
finishTranslationEvent.setReq(mem_req);
@ -802,15 +799,6 @@ DefaultFetch<Impl>::checkStall(ThreadID tid) const
} else if (stalls[tid].decode) {
DPRINTF(Fetch,"[tid:%i]: Stall from Decode stage detected.\n",tid);
ret_val = true;
} else if (stalls[tid].rename) {
DPRINTF(Fetch,"[tid:%i]: Stall from Rename stage detected.\n",tid);
ret_val = true;
} else if (stalls[tid].iew) {
DPRINTF(Fetch,"[tid:%i]: Stall from IEW stage detected.\n",tid);
ret_val = true;
} else if (stalls[tid].commit) {
DPRINTF(Fetch,"[tid:%i]: Stall from Commit stage detected.\n",tid);
ret_val = true;
}
return ret_val;
@ -952,36 +940,6 @@ DefaultFetch<Impl>::checkSignalsAndUpdate(ThreadID tid)
stalls[tid].decode = false;
}
if (fromRename->renameBlock[tid]) {
stalls[tid].rename = true;
}
if (fromRename->renameUnblock[tid]) {
assert(stalls[tid].rename);
assert(!fromRename->renameBlock[tid]);
stalls[tid].rename = false;
}
if (fromIEW->iewBlock[tid]) {
stalls[tid].iew = true;
}
if (fromIEW->iewUnblock[tid]) {
assert(stalls[tid].iew);
assert(!fromIEW->iewBlock[tid]);
stalls[tid].iew = false;
}
if (fromCommit->commitBlock[tid]) {
stalls[tid].commit = true;
}
if (fromCommit->commitUnblock[tid]) {
assert(stalls[tid].commit);
assert(!fromCommit->commitBlock[tid]);
stalls[tid].commit = false;
}
// Check squash signals from commit.
if (fromCommit->commitInfo[tid].squash) {
@ -1013,16 +971,6 @@ DefaultFetch<Impl>::checkSignalsAndUpdate(ThreadID tid)
branchPred->update(fromCommit->commitInfo[tid].doneSeqNum, tid);
}
// Check ROB squash signals from commit.
if (fromCommit->commitInfo[tid].robSquashing) {
DPRINTF(Fetch, "[tid:%u]: ROB is still squashing.\n", tid);
// Continue to squash.
fetchStatus[tid] = Squashing;
return true;
}
// Check squash signals from decode.
if (fromDecode->decodeInfo[tid].squash) {
DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "

View file

@ -270,9 +270,6 @@ class DefaultIEW
*/
unsigned validInstsFromRename();
/** Reads the stall signals. */
void readStallSignals(ThreadID tid);
/** Checks if any of the stall conditions are currently true. */
bool checkStall(ThreadID tid);
@ -346,14 +343,6 @@ class DefaultIEW
*/
bool wroteToTimeBuffer;
/** Source of possible stalls. */
struct Stalls {
bool commit;
};
/** Stages that are telling IEW to stall. */
Stalls stalls[Impl::MaxThreads];
/** Debug function to print instructions that are issued this cycle. */
void printAvailableInsts();

View file

@ -104,13 +104,12 @@ DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params)
for (ThreadID tid = 0; tid < numThreads; tid++) {
dispatchStatus[tid] = Running;
stalls[tid].commit = false;
fetchRedirect[tid] = false;
}
updateLSQNextCycle = false;
skidBufferMax = (3 * (renameToIEWDelay * params->renameWidth)) + issueWidth;
skidBufferMax = (renameToIEWDelay + 1) * params->renameWidth;
}
template <class Impl>
@ -434,7 +433,6 @@ DefaultIEW<Impl>::takeOverFrom()
for (ThreadID tid = 0; tid < numThreads; tid++) {
dispatchStatus[tid] = Running;
stalls[tid].commit = false;
fetchRedirect[tid] = false;
}
@ -760,27 +758,13 @@ DefaultIEW<Impl>::resetEntries()
ldstQueue.resetEntries();
}
template <class Impl>
void
DefaultIEW<Impl>::readStallSignals(ThreadID tid)
{
if (fromCommit->commitBlock[tid]) {
stalls[tid].commit = true;
}
if (fromCommit->commitUnblock[tid]) {
assert(stalls[tid].commit);
stalls[tid].commit = false;
}
}
template <class Impl>
bool
DefaultIEW<Impl>::checkStall(ThreadID tid)
{
bool ret_val(false);
if (stalls[tid].commit) {
if (fromCommit->commitInfo[tid].robSquashing) {
DPRINTF(IEW,"[tid:%i]: Stall from Commit stage detected.\n",tid);
ret_val = true;
} else if (instQueue.isFull(tid)) {
@ -802,8 +786,6 @@ DefaultIEW<Impl>::checkSignalsAndUpdate(ThreadID tid)
// If status was Squashing
// check if squashing is not high. Switch to running this cycle.
readStallSignals(tid);
if (fromCommit->commitInfo[tid].squash) {
squash(tid);
@ -824,7 +806,6 @@ DefaultIEW<Impl>::checkSignalsAndUpdate(ThreadID tid)
dispatchStatus[tid] = Squashing;
emptyRenameInsts(tid);
wroteToTimeBuffer = true;
return;
}
if (checkStall(tid)) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2012 ARM Limited
* Copyright (c) 2010-2012, 2014 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved.
*
@ -77,7 +77,7 @@ DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params)
renameWidth, static_cast<int>(Impl::MaxWidth));
// @todo: Make into a parameter.
skidBufferMax = (2 * (decodeToRenameDelay * params->decodeWidth)) + renameWidth;
skidBufferMax = (decodeToRenameDelay + 1) * params->decodeWidth;
}
template <class Impl>
@ -247,7 +247,6 @@ DefaultRename<Impl>::resetStage()
emptyROB[tid] = true;
stalls[tid].iew = false;
stalls[tid].commit = false;
serializeInst[tid] = NULL;
instsInProgress[tid] = 0;
@ -1200,15 +1199,6 @@ DefaultRename<Impl>::readStallSignals(ThreadID tid)
assert(stalls[tid].iew);
stalls[tid].iew = false;
}
if (fromCommit->commitBlock[tid]) {
stalls[tid].commit = true;
}
if (fromCommit->commitUnblock[tid]) {
assert(stalls[tid].commit);
stalls[tid].commit = false;
}
}
template <class Impl>
@ -1220,9 +1210,6 @@ DefaultRename<Impl>::checkStall(ThreadID tid)
if (stalls[tid].iew) {
DPRINTF(Rename,"[tid:%i]: Stall from IEW stage detected.\n", tid);
ret_val = true;
} else if (stalls[tid].commit) {
DPRINTF(Rename,"[tid:%i]: Stall from Commit stage detected.\n", tid);
ret_val = true;
} else if (calcFreeROBEntries(tid) <= 0) {
DPRINTF(Rename,"[tid:%i]: Stall: ROB has 0 free entries.\n", tid);
ret_val = true;
@ -1302,14 +1289,6 @@ DefaultRename<Impl>::checkSignalsAndUpdate(ThreadID tid)
return true;
}
if (fromCommit->commitInfo[tid].robSquashing) {
DPRINTF(Rename, "[tid:%u]: ROB is still squashing.\n", tid);
renameStatus[tid] = Squashing;
return true;
}
if (checkStall(tid)) {
return block(tid);
}