}
template<class Impl>
-DefaultFetch<Impl>::DefaultFetch(Params *params)
- : branchPred(params),
+DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params)
+ : cpu(_cpu),
+ branchPred(params),
predecoder(NULL),
decodeToFetchDelay(params->decodeToFetchDelay),
renameToFetchDelay(params->renameToFetchDelay),
// Get the size of an instruction.
instSize = sizeof(TheISA::MachInst);
+
+ // Name is finally available, so create the port.
+ icachePort = new IcachePort(this);
+
+ icachePort->snoopRangeSent = false;
+
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->setIcachePort(icachePort);
+ }
+#endif
}
template <class Impl>
branchPred.regStats();
}
-template<class Impl>
-void
-DefaultFetch<Impl>::setCPU(O3CPU *cpu_ptr)
-{
- DPRINTF(Fetch, "Setting the CPU pointer.\n");
- cpu = cpu_ptr;
-
- // Name is finally available, so create the port.
- icachePort = new IcachePort(this);
-
- icachePort->snoopRangeSent = false;
-
-#if USE_CHECKER
- if (cpu->checker) {
- cpu->checker->setIcachePort(icachePort);
- }
-#endif
-
- // Schedule fetch to get the correct PC from the CPU
- // scheduleFetchStartupEvent(1);
-
- // Fetch needs to start fetching instructions at the very beginning,
- // so it must start up in active state.
- switchToActive();
-}
-
template<class Impl>
void
DefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
{
- DPRINTF(Fetch, "Setting the time buffer pointer.\n");
timeBuffer = time_buffer;
// Create wires to get information from proper places in time buffer.
void
DefaultFetch<Impl>::setActiveThreads(std::list<unsigned> *at_ptr)
{
- DPRINTF(Fetch, "Setting active threads list pointer.\n");
activeThreads = at_ptr;
}
void
DefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
{
- DPRINTF(Fetch, "Setting the fetch queue pointer.\n");
fetchQueue = fq_ptr;
// Create wire to write information to proper place in fetch queue.
for (int tid = 0; tid < numThreads; tid++) {
PC[tid] = cpu->readPC(tid);
nextPC[tid] = cpu->readNextPC(tid);
- nextNPC[tid] = cpu->readNextNPC(tid);
+ microPC[tid] = cpu->readMicroPC(tid);
}
for (int tid=0; tid < numThreads; tid++) {
stalls[tid].iew = false;
stalls[tid].commit = false;
}
+
+ // Schedule fetch to get the correct PC from the CPU
+ // scheduleFetchStartupEvent(1);
+
+ // Fetch needs to start fetching instructions at the very beginning,
+ // so it must start up in active state.
+ switchToActive();
}
template<class Impl>
stalls[i].commit = 0;
PC[i] = cpu->readPC(i);
nextPC[i] = cpu->readNextPC(i);
-#if ISA_HAS_DELAY_SLOT
- nextNPC[i] = cpu->readNextNPC(i);
-#else
- nextNPC[i] = nextPC[i] + sizeof(TheISA::MachInst);
-#endif
+ microPC[i] = cpu->readMicroPC(i);
fetchStatus[i] = Running;
}
numInst = 0;
template <class Impl>
bool
DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC,
- Addr &next_NPC)
+ Addr &next_NPC, Addr &next_MicroPC)
{
// Do branch prediction check here.
// A bit of a misnomer...next_PC is actually the current PC until
bool predict_taken;
if (!inst->isControl()) {
- next_PC = next_NPC;
- next_NPC = next_NPC + instSize;
- inst->setPredTarg(next_PC, next_NPC);
+ if (inst->isMicroOp() && !inst->isLastMicroOp()) {
+ next_MicroPC++;
+ } else {
+ next_PC = next_NPC;
+ next_NPC = next_NPC + instSize;
+ next_MicroPC = 0;
+ }
+ inst->setPredTarg(next_PC, next_NPC, next_MicroPC);
inst->setPredTaken(false);
return false;
}
+ //Assume for now that all control flow is to a different macroop which
+ //would reset the micro pc to 0.
+ next_MicroPC = 0;
+
int tid = inst->threadNumber;
Addr pred_PC = next_PC;
predict_taken = branchPred.predict(inst, pred_PC, tid);
#endif
/* DPRINTF(Fetch, "[tid:%i]: Branch predicted to go to %#x and then %#x.\n",
tid, next_PC, next_NPC);*/
- inst->setPredTarg(next_PC, next_NPC);
+ inst->setPredTarg(next_PC, next_NPC, next_MicroPC);
inst->setPredTaken(predict_taken);
++fetchedBranches;
template <class Impl>
inline void
DefaultFetch<Impl>::doSquash(const Addr &new_PC,
- const Addr &new_NPC, unsigned tid)
+ const Addr &new_NPC, const Addr &new_microPC, unsigned tid)
{
DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x, NPC to: %#x.\n",
tid, new_PC, new_NPC);
PC[tid] = new_PC;
nextPC[tid] = new_NPC;
- nextNPC[tid] = new_NPC + instSize;
+ microPC[tid] = new_microPC;
// Clear the icache miss if it's outstanding.
if (fetchStatus[tid] == IcacheWaitResponse) {
template<class Impl>
void
DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC, const Addr &new_NPC,
- const InstSeqNum &seq_num,
- unsigned tid)
+ const Addr &new_MicroPC,
+ const InstSeqNum &seq_num, unsigned tid)
{
DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid);
- doSquash(new_PC, new_NPC, tid);
+ doSquash(new_PC, new_NPC, new_MicroPC, tid);
// Tell the CPU to remove any instructions that are in flight between
// fetch and decode.
template <class Impl>
void
DefaultFetch<Impl>::squash(const Addr &new_PC, const Addr &new_NPC,
- const InstSeqNum &seq_num,
- bool squash_delay_slot, unsigned tid)
+ const Addr &new_MicroPC,
+ const InstSeqNum &seq_num, unsigned tid)
{
DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid);
- doSquash(new_PC, new_NPC, tid);
+ doSquash(new_PC, new_NPC, new_MicroPC, tid);
-#if ISA_HAS_DELAY_SLOT
// Tell the CPU to remove any instructions that are not in the ROB.
- cpu->removeInstsNotInROB(tid, squash_delay_slot, seq_num);
-#else
- // Tell the CPU to remove any instructions that are not in the ROB.
- cpu->removeInstsNotInROB(tid, true, 0);
-#endif
+ cpu->removeInstsNotInROB(tid);
}
template <class Impl>
DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
"from commit.\n",tid);
-
-#if ISA_HAS_DELAY_SLOT
- InstSeqNum doneSeqNum = fromCommit->commitInfo[tid].bdelayDoneSeqNum;
-#else
- InstSeqNum doneSeqNum = fromCommit->commitInfo[tid].doneSeqNum;
-#endif
// In any case, squash.
squash(fromCommit->commitInfo[tid].nextPC,
fromCommit->commitInfo[tid].nextNPC,
- doneSeqNum,
- fromCommit->commitInfo[tid].squashDelaySlot,
+ fromCommit->commitInfo[tid].nextMicroPC,
+ fromCommit->commitInfo[tid].doneSeqNum,
tid);
// Also check if there's a mispredict that happened.
if (fetchStatus[tid] != Squashing) {
-#if ISA_HAS_DELAY_SLOT
- InstSeqNum doneSeqNum = fromDecode->decodeInfo[tid].bdelayDoneSeqNum;
-#else
- InstSeqNum doneSeqNum = fromDecode->decodeInfo[tid].doneSeqNum;
-#endif
DPRINTF(Fetch, "Squashing from decode with PC = %#x, NPC = %#x\n",
fromDecode->decodeInfo[tid].nextPC,
fromDecode->decodeInfo[tid].nextNPC);
// Squash unless we're already squashing
squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
fromDecode->decodeInfo[tid].nextNPC,
- doneSeqNum,
+ fromDecode->decodeInfo[tid].nextMicroPC,
+ fromDecode->decodeInfo[tid].doneSeqNum,
tid);
return true;
DPRINTF(Fetch, "Attempting to fetch from [tid:%i]\n", tid);
// The current PC.
- Addr &fetch_PC = PC[tid];
-
- Addr &fetch_NPC = nextPC[tid];
+ Addr fetch_PC = PC[tid];
+ Addr fetch_NPC = nextPC[tid];
+ Addr fetch_MicroPC = microPC[tid];
// Fault code for memory access.
Fault fault = NoFault;
Addr next_PC = fetch_PC;
Addr next_NPC = fetch_NPC;
+ Addr next_MicroPC = fetch_MicroPC;
InstSeqNum inst_seq;
MachInst inst;
// @todo: Fix this hack.
unsigned offset = (fetch_PC & cacheBlkMask) & ~3;
+ StaticInstPtr staticInst = NULL;
+ StaticInstPtr macroop = NULL;
+
if (fault == NoFault) {
// If the read of the first instruction was successful, then grab the
// instructions from the rest of the cache line and put them into the
// ended this fetch block.
bool predicted_branch = false;
- for (;
- offset < cacheBlkSize &&
- numInst < fetchWidth &&
- !predicted_branch;
- ++numInst) {
+ while (offset < cacheBlkSize &&
+ numInst < fetchWidth &&
+ !predicted_branch) {
// If we're branching after this instruction, quite fetching
// from the same block then.
fetch_PC, fetch_NPC);
}
-
- // Get a sequence number.
- inst_seq = cpu->getAndIncrementInstSeq();
-
// Make sure this is a valid index.
assert(offset <= cacheBlkSize - instSize);
- // Get the instruction from the array of the cache line.
- inst = TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *>
- (&cacheData[tid][offset]));
+ if (!macroop) {
+ // Get the instruction from the array of the cache line.
+ inst = TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *>
+ (&cacheData[tid][offset]));
- predecoder.setTC(cpu->thread[tid]->getTC());
- predecoder.moreBytes(fetch_PC, 0, inst);
+ predecoder.setTC(cpu->thread[tid]->getTC());
+ predecoder.moreBytes(fetch_PC, 0, inst);
- ext_inst = predecoder.getExtMachInst();
+ ext_inst = predecoder.getExtMachInst();
+ staticInst = StaticInstPtr(ext_inst);
+ if (staticInst->isMacroOp())
+ macroop = staticInst;
+ }
+ do {
+ if (macroop) {
+ staticInst = macroop->fetchMicroOp(fetch_MicroPC);
+ if (staticInst->isLastMicroOp())
+ macroop = NULL;
+ }
- // Create a new DynInst from the instruction fetched.
- DynInstPtr instruction = new DynInst(ext_inst,
- fetch_PC, fetch_NPC,
- next_PC, next_NPC,
- inst_seq, cpu);
- instruction->setTid(tid);
+ // Get a sequence number.
+ inst_seq = cpu->getAndIncrementInstSeq();
- instruction->setASID(tid);
+ // Create a new DynInst from the instruction fetched.
+ DynInstPtr instruction = new DynInst(staticInst,
+ fetch_PC, fetch_NPC, fetch_MicroPC,
+ next_PC, next_NPC, next_MicroPC,
+ inst_seq, cpu);
+ instruction->setTid(tid);
- instruction->setThreadState(cpu->thread[tid]);
+ instruction->setASID(tid);
- DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x created "
- "[sn:%lli]\n",
- tid, instruction->readPC(), inst_seq);
+ instruction->setThreadState(cpu->thread[tid]);
- //DPRINTF(Fetch, "[tid:%i]: MachInst is %#x\n", tid, ext_inst);
+ DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x created "
+ "[sn:%lli]\n",
+ tid, instruction->readPC(), inst_seq);
- DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n",
- tid, instruction->staticInst->disassemble(fetch_PC));
+ //DPRINTF(Fetch, "[tid:%i]: MachInst is %#x\n", tid, ext_inst);
- instruction->traceData =
- Trace::getInstRecord(curTick, cpu->tcBase(tid),
- instruction->staticInst,
- instruction->readPC());
+ DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n",
+ tid, instruction->staticInst->disassemble(fetch_PC));
- ///FIXME This needs to be more robust in dealing with delay slots
-#if !ISA_HAS_DELAY_SLOT
-// predicted_branch |=
-#endif
- lookupAndUpdateNextPC(instruction, next_PC, next_NPC);
- predicted_branch |= (next_PC != fetch_NPC);
+ instruction->traceData =
+ Trace::getInstRecord(curTick, cpu->tcBase(tid),
+ instruction->staticInst,
+ instruction->readPC());
- // Add instruction to the CPU's list of instructions.
- instruction->setInstListIt(cpu->addInst(instruction));
+ ///FIXME This needs to be more robust in dealing with delay slots
+ predicted_branch |=
+ lookupAndUpdateNextPC(instruction, next_PC, next_NPC, next_MicroPC);
- // Write the instruction to the first slot in the queue
- // that heads to decode.
- toDecode->insts[numInst] = instruction;
+ // Add instruction to the CPU's list of instructions.
+ instruction->setInstListIt(cpu->addInst(instruction));
- toDecode->size++;
+ // Write the instruction to the first slot in the queue
+ // that heads to decode.
+ toDecode->insts[numInst] = instruction;
- // Increment stat of fetched instructions.
- ++fetchedInsts;
+ toDecode->size++;
- // Move to the next instruction, unless we have a branch.
- fetch_PC = next_PC;
- fetch_NPC = next_NPC;
+ // Increment stat of fetched instructions.
+ ++fetchedInsts;
- if (instruction->isQuiesce()) {
- DPRINTF(Fetch, "Quiesce instruction encountered, halting fetch!",
- curTick);
- fetchStatus[tid] = QuiescePending;
- ++numInst;
- status_change = true;
- break;
- }
+ // Move to the next instruction, unless we have a branch.
+ fetch_PC = next_PC;
+ fetch_NPC = next_NPC;
+ fetch_MicroPC = next_MicroPC;
+
+ if (instruction->isQuiesce()) {
+ DPRINTF(Fetch, "Quiesce instruction encountered, halting fetch!",
+ curTick);
+ fetchStatus[tid] = QuiescePending;
+ ++numInst;
+ status_change = true;
+ break;
+ }
+ ++numInst;
+ } while (staticInst->isMicroOp() &&
+ !staticInst->isLastMicroOp() &&
+ numInst < fetchWidth);
offset += instSize;
}
- if (offset >= cacheBlkSize) {
- DPRINTF(Fetch, "[tid:%i]: Done fetching, reached the end of cache "
- "block.\n", tid);
+ if (predicted_branch) {
+ DPRINTF(Fetch, "[tid:%i]: Done fetching, predicted branch "
+ "instruction encountered.\n", tid);
} else if (numInst >= fetchWidth) {
DPRINTF(Fetch, "[tid:%i]: Done fetching, reached fetch bandwidth "
"for this cycle.\n", tid);
- } else if (predicted_branch) {
- DPRINTF(Fetch, "[tid:%i]: Done fetching, predicted branch "
- "instruction encountered.\n", tid);
+ } else if (offset >= cacheBlkSize) {
+ DPRINTF(Fetch, "[tid:%i]: Done fetching, reached the end of cache "
+ "block.\n", tid);
}
}
if (fault == NoFault) {
PC[tid] = next_PC;
nextPC[tid] = next_NPC;
- nextNPC[tid] = next_NPC + instSize;
-#if ISA_HAS_DELAY_SLOT
- DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n", tid, PC[tid]);
-#else
+ microPC[tid] = next_MicroPC;
DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n", tid, next_PC);
-#endif
} else {
// We shouldn't be in an icache miss and also have a fault (an ITB
// miss)
// We will use a nop in order to carry the fault.
ext_inst = TheISA::NoopMachInst;
+ StaticInstPtr staticInst = new StaticInst(ext_inst);
// Create a new DynInst from the dummy nop.
- DynInstPtr instruction = new DynInst(ext_inst,
+ DynInstPtr instruction = new DynInst(staticInst,
fetch_PC, fetch_NPC,
next_PC, next_NPC,
inst_seq, cpu);