* Authors: Kevin Lim
*/
+#include "arch/types.hh"
+#include "base/trace.hh"
+#include "config/full_system.hh"
+#include "config/the_isa.hh"
#include "cpu/o3/decode.hh"
+#include "cpu/inst_seq.hh"
+#include "debug/Activity.hh"
+#include "debug/Decode.hh"
+#include "params/DerivO3CPU.hh"
using namespace std;
template<class Impl>
-DefaultDecode<Impl>::DefaultDecode(Params *params)
- : renameToDecodeDelay(params->renameToDecodeDelay),
+DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params)
+ : cpu(_cpu),
+ renameToDecodeDelay(params->renameToDecodeDelay),
iewToDecodeDelay(params->iewToDecodeDelay),
commitToDecodeDelay(params->commitToDecodeDelay),
fetchToDecodeDelay(params->fetchToDecodeDelay),
decodeWidth(params->decodeWidth),
- numThreads(params->numberOfThreads)
+ numThreads(params->numThreads)
{
_status = Inactive;
// Setup status, make sure stall signals are clear.
- for (int i = 0; i < numThreads; ++i) {
- decodeStatus[i] = Idle;
+ for (ThreadID tid = 0; tid < numThreads; ++tid) {
+ decodeStatus[tid] = Idle;
- stalls[i].rename = false;
- stalls[i].iew = false;
- stalls[i].commit = false;
+ stalls[tid].rename = false;
+ stalls[tid].iew = false;
+ stalls[tid].commit = false;
}
// @todo: Make into a parameter
DefaultDecode<Impl>::regStats()
{
decodeIdleCycles
- .name(name() + ".DECODE:IdleCycles")
+ .name(name() + ".IdleCycles")
.desc("Number of cycles decode is idle")
.prereq(decodeIdleCycles);
decodeBlockedCycles
- .name(name() + ".DECODE:BlockedCycles")
+ .name(name() + ".BlockedCycles")
.desc("Number of cycles decode is blocked")
.prereq(decodeBlockedCycles);
decodeRunCycles
- .name(name() + ".DECODE:RunCycles")
+ .name(name() + ".RunCycles")
.desc("Number of cycles decode is running")
.prereq(decodeRunCycles);
decodeUnblockCycles
- .name(name() + ".DECODE:UnblockCycles")
+ .name(name() + ".UnblockCycles")
.desc("Number of cycles decode is unblocking")
.prereq(decodeUnblockCycles);
decodeSquashCycles
- .name(name() + ".DECODE:SquashCycles")
+ .name(name() + ".SquashCycles")
.desc("Number of cycles decode is squashing")
.prereq(decodeSquashCycles);
decodeBranchResolved
- .name(name() + ".DECODE:BranchResolved")
+ .name(name() + ".BranchResolved")
.desc("Number of times decode resolved a branch")
.prereq(decodeBranchResolved);
decodeBranchMispred
- .name(name() + ".DECODE:BranchMispred")
+ .name(name() + ".BranchMispred")
.desc("Number of times decode detected a branch misprediction")
.prereq(decodeBranchMispred);
decodeControlMispred
- .name(name() + ".DECODE:ControlMispred")
+ .name(name() + ".ControlMispred")
.desc("Number of times decode detected an instruction incorrectly"
" predicted as a control")
.prereq(decodeControlMispred);
decodeDecodedInsts
- .name(name() + ".DECODE:DecodedInsts")
+ .name(name() + ".DecodedInsts")
.desc("Number of instructions handled by decode")
.prereq(decodeDecodedInsts);
decodeSquashedInsts
- .name(name() + ".DECODE:SquashedInsts")
+ .name(name() + ".SquashedInsts")
.desc("Number of squashed instructions handled by decode")
.prereq(decodeSquashedInsts);
}
-template<class Impl>
-void
-DefaultDecode<Impl>::setCPU(O3CPU *cpu_ptr)
-{
- DPRINTF(Decode, "Setting CPU pointer.\n");
- cpu = cpu_ptr;
-}
-
template<class Impl>
void
DefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
{
- DPRINTF(Decode, "Setting time buffer pointer.\n");
timeBuffer = tb_ptr;
// Setup wire to write information back to fetch.
void
DefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
{
- DPRINTF(Decode, "Setting decode queue pointer.\n");
decodeQueue = dq_ptr;
// Setup wire to write information to proper place in decode queue.
void
DefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
{
- DPRINTF(Decode, "Setting fetch queue pointer.\n");
fetchQueue = fq_ptr;
// Setup wire to read information from fetch queue.
template<class Impl>
void
-DefaultDecode<Impl>::setActiveThreads(list<unsigned> *at_ptr)
+DefaultDecode<Impl>::setActiveThreads(std::list<ThreadID> *at_ptr)
{
- DPRINTF(Decode, "Setting active threads list pointer.\n");
activeThreads = at_ptr;
}
template <class Impl>
-void
+bool
DefaultDecode<Impl>::drain()
{
// Decode is done draining at any time.
cpu->signalDrained();
+ return true;
}
template <class Impl>
_status = Inactive;
// Be sure to reset state and clear out any old instructions.
- for (int i = 0; i < numThreads; ++i) {
- decodeStatus[i] = Idle;
-
- stalls[i].rename = false;
- stalls[i].iew = false;
- stalls[i].commit = false;
- while (!insts[i].empty())
- insts[i].pop();
- while (!skidBuffer[i].empty())
- skidBuffer[i].pop();
- branchCount[i] = 0;
+ for (ThreadID tid = 0; tid < numThreads; ++tid) {
+ decodeStatus[tid] = Idle;
+
+ stalls[tid].rename = false;
+ stalls[tid].iew = false;
+ stalls[tid].commit = false;
+ while (!insts[tid].empty())
+ insts[tid].pop();
+ while (!skidBuffer[tid].empty())
+ skidBuffer[tid].pop();
+ branchCount[tid] = 0;
}
wroteToTimeBuffer = false;
}
template<class Impl>
bool
-DefaultDecode<Impl>::checkStall(unsigned tid) const
+DefaultDecode<Impl>::checkStall(ThreadID tid) const
{
bool ret_val = false;
template<class Impl>
bool
-DefaultDecode<Impl>::block(unsigned tid)
+DefaultDecode<Impl>::block(ThreadID tid)
{
DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid);
template<class Impl>
bool
-DefaultDecode<Impl>::unblock(unsigned tid)
+DefaultDecode<Impl>::unblock(ThreadID tid)
{
// Decode is done unblocking only if the skid buffer is empty.
if (skidBuffer[tid].empty()) {
template<class Impl>
void
-DefaultDecode<Impl>::squash(DynInstPtr &inst, unsigned tid)
+DefaultDecode<Impl>::squash(DynInstPtr &inst, ThreadID tid)
{
- DPRINTF(Decode, "[tid:%i]: Squashing due to incorrect branch prediction "
- "detected at decode.\n", tid);
+ DPRINTF(Decode, "[tid:%i]: [sn:%i] Squashing due to incorrect branch "
+ "prediction detected at decode.\n", tid, inst->seqNum);
// Send back mispredict information.
toFetch->decodeInfo[tid].branchMispredict = true;
- toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum;
toFetch->decodeInfo[tid].predIncorrect = true;
toFetch->decodeInfo[tid].squash = true;
+ toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum;
toFetch->decodeInfo[tid].nextPC = inst->branchTarget();
- toFetch->decodeInfo[tid].branchTaken =
- inst->readNextPC() != (inst->readPC() + sizeof(TheISA::MachInst));
+ toFetch->decodeInfo[tid].branchTaken = inst->pcState().branching();
+ toFetch->decodeInfo[tid].squashInst = inst;
+
+ InstSeqNum squash_seq_num = inst->seqNum;
// Might have to tell fetch to unblock.
if (decodeStatus[tid] == Blocked ||
for (int i=0; i<fromFetch->size; i++) {
if (fromFetch->insts[i]->threadNumber == tid &&
- fromFetch->insts[i]->seqNum > inst->seqNum) {
+ fromFetch->insts[i]->seqNum > squash_seq_num) {
fromFetch->insts[i]->setSquashed();
}
}
}
// Squash instructions up until this one
- cpu->removeInstsUntil(inst->seqNum, tid);
+ cpu->removeInstsUntil(squash_seq_num, tid);
}
template<class Impl>
unsigned
-DefaultDecode<Impl>::squash(unsigned tid)
+DefaultDecode<Impl>::squash(ThreadID tid)
{
DPRINTF(Decode, "[tid:%i]: Squashing.\n",tid);
template<class Impl>
void
-DefaultDecode<Impl>::skidInsert(unsigned tid)
+DefaultDecode<Impl>::skidInsert(ThreadID tid)
{
DynInstPtr inst = NULL;
assert(tid == inst->threadNumber);
- DPRINTF(Decode,"Inserting [sn:%lli] PC:%#x into decode skidBuffer %i\n",
- inst->seqNum, inst->readPC(), inst->threadNumber);
+ DPRINTF(Decode,"Inserting [sn:%lli] PC: %s into decode skidBuffer %i\n",
+ inst->seqNum, inst->pcState(), inst->threadNumber);
skidBuffer[tid].push(inst);
}
bool
DefaultDecode<Impl>::skidsEmpty()
{
- list<unsigned>::iterator threads = (*activeThreads).begin();
+ list<ThreadID>::iterator threads = activeThreads->begin();
+ list<ThreadID>::iterator end = activeThreads->end();
- while (threads != (*activeThreads).end()) {
- if (!skidBuffer[*threads++].empty())
+ while (threads != end) {
+ ThreadID tid = *threads++;
+ if (!skidBuffer[tid].empty())
return false;
}
{
bool any_unblocking = false;
- list<unsigned>::iterator threads = (*activeThreads).begin();
-
- threads = (*activeThreads).begin();
+ list<ThreadID>::iterator threads = activeThreads->begin();
+ list<ThreadID>::iterator end = activeThreads->end();
- while (threads != (*activeThreads).end()) {
- unsigned tid = *threads++;
+ while (threads != end) {
+ ThreadID tid = *threads++;
if (decodeStatus[tid] == Unblocking) {
any_unblocking = true;
DefaultDecode<Impl>::sortInsts()
{
int insts_from_fetch = fromFetch->size;
-#ifdef DEBUG
- for (int i=0; i < numThreads; i++)
- assert(insts[i].empty());
-#endif
for (int i = 0; i < insts_from_fetch; ++i) {
insts[fromFetch->insts[i]->threadNumber].push(fromFetch->insts[i]);
}
template<class Impl>
void
-DefaultDecode<Impl>::readStallSignals(unsigned tid)
+DefaultDecode<Impl>::readStallSignals(ThreadID tid)
{
if (fromRename->renameBlock[tid]) {
stalls[tid].rename = true;
template <class Impl>
bool
-DefaultDecode<Impl>::checkSignalsAndUpdate(unsigned tid)
+DefaultDecode<Impl>::checkSignalsAndUpdate(ThreadID tid)
{
// Check if there's a squash signal, squash if there is.
// Check stall signals, block if necessary.
toRenameIndex = 0;
- list<unsigned>::iterator threads = (*activeThreads).begin();
+ list<ThreadID>::iterator threads = activeThreads->begin();
+ list<ThreadID>::iterator end = activeThreads->end();
sortInsts();
//Check stall and squash signals.
- while (threads != (*activeThreads).end()) {
- unsigned tid = *threads++;
+ while (threads != end) {
+ ThreadID tid = *threads++;
DPRINTF(Decode,"Processing [tid:%i]\n",tid);
status_change = checkSignalsAndUpdate(tid) || status_change;
template<class Impl>
void
-DefaultDecode<Impl>::decode(bool &status_change, unsigned tid)
+DefaultDecode<Impl>::decode(bool &status_change, ThreadID tid)
{
// If status is Running or idle,
// call decodeInsts()
// will allow, as long as it is not currently blocked.
if (decodeStatus[tid] == Running ||
decodeStatus[tid] == Idle) {
- DPRINTF(Decode, "[tid:%u] Not blocked, so attempting to run "
+ DPRINTF(Decode, "[tid:%u]: Not blocked, so attempting to run "
"stage.\n",tid);
decodeInsts(tid);
template <class Impl>
void
-DefaultDecode<Impl>::decodeInsts(unsigned tid)
+DefaultDecode<Impl>::decodeInsts(ThreadID tid)
{
// Instructions can come either from the skid buffer or the list of
// instructions coming from fetch, depending on decode's status.
insts_to_decode.pop();
DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with "
- "PC %#x\n",
- tid, inst->seqNum, inst->readPC());
+ "PC %s\n", tid, inst->seqNum, inst->pcState());
if (inst->isSquashed()) {
- DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %#x is "
+ DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %s is "
"squashed, skipping.\n",
- tid, inst->seqNum, inst->readPC());
+ tid, inst->seqNum, inst->pcState());
++decodeSquashedInsts;
++decodeDecodedInsts;
--insts_available;
+#if TRACING_ON
+ inst->decodeTick = curTick();
+#endif
+
// Ensure that if it was predicted as a branch, it really is a
// branch.
- if (inst->predTaken() && !inst->isControl()) {
+ if (inst->readPredTaken() && !inst->isControl()) {
panic("Instruction predicted as a branch!");
++decodeControlMispred;
if (inst->isDirectCtrl() && inst->isUncondCtrl()) {
++decodeBranchResolved;
- if (inst->branchTarget() != inst->readPredTarg()) {
+ if (!(inst->branchTarget() == inst->readPredTarg())) {
++decodeBranchMispred;
// Might want to set some sort of boolean and just do
// a check at the end
squash(inst, inst->threadNumber);
- inst->setPredTarg(inst->branchTarget());
+ TheISA::PCState target = inst->branchTarget();
+ DPRINTF(Decode, "[sn:%i]: Updating predictions: PredPC: %s\n",
+ inst->seqNum, target);
+ //The micro pc after an instruction level branch should be 0
+ inst->setPredTarg(target);
break;
}
}