summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Lim <ktlim@umich.edu>2006-05-17 14:25:10 -0400
committerKevin Lim <ktlim@umich.edu>2006-05-17 14:25:10 -0400
commit36581a534240c322e1fc28b8bd6e8f13f2b0fefd (patch)
tree591daea5b9133027c491e0f6a0dbfd15d4b01fb1
parent343bff3b7dadfe9f6e6062610a086dea0783722a (diff)
downloadgem5-36581a534240c322e1fc28b8bd6e8f13f2b0fefd.tar.xz
Faults generated at fetch are passed to the backend by creating a dummy nop instruction and giving it the fault. This unifies front end faults and normal instruction faults.
cpu/checker/cpu.cc: Fixups for fetch fault being sent with the instruction. cpu/o3/fetch_impl.hh: cpu/ozone/front_end_impl.hh: Send any faults generated at fetch along with a fake nop instruction to the back end. This avoids having to use direct communication to check if the entire front end has drained; it is naturally handled through the nop's fault being handled when it reaches the head of commit. cpu/ozone/front_end.hh: Add extra status TrapPending. cpu/ozone/lw_back_end_impl.hh: Fetch fault handled through a dummy nop carrying the fetch fault. Avoid putting Nops on the exeList. --HG-- extra : convert_revision : 8d9899748b34c204763a49c48a9b5113864f5789
-rw-r--r--cpu/checker/cpu.cc45
-rw-r--r--cpu/o3/fetch_impl.hh107
-rw-r--r--cpu/ozone/front_end.hh1
-rw-r--r--cpu/ozone/front_end_impl.hh36
-rw-r--r--cpu/ozone/lw_back_end_impl.hh10
5 files changed, 99 insertions, 100 deletions
diff --git a/cpu/checker/cpu.cc b/cpu/checker/cpu.cc
index f1b43f601..f76f1e063 100644
--- a/cpu/checker/cpu.cc
+++ b/cpu/checker/cpu.cc
@@ -607,41 +607,46 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
bool succeeded = translateInstReq(memReq);
if (!succeeded) {
- warn("Instruction PC %#x was not found in the ITB!",
- cpuXC->readPC());
- handleError();
+ if (inst->getFault() == NoFault) {
+ warn("Instruction PC %#x was not found in the ITB!",
+ cpuXC->readPC());
+ handleError();
- // go to the next instruction
- cpuXC->setPC(cpuXC->readNextPC());
- cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
+ // go to the next instruction
+ cpuXC->setPC(cpuXC->readNextPC());
+ cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
- return;
+ return;
+ } else {
+ fault = inst->getFault();
+ }
}
-// if (fault == NoFault)
+ if (fault == NoFault) {
// fault = cpuXC->mem->read(memReq, machInst);
- cpuXC->mem->read(memReq, machInst);
+ cpuXC->mem->read(memReq, machInst);
- // If we've got a valid instruction (i.e., no fault on instruction
- // fetch), then execute it.
+ // If we've got a valid instruction (i.e., no fault on instruction
+ // fetch), then execute it.
// keep an instruction count
- numInst++;
+ numInst++;
// numInsts++;
- // decode the instruction
- machInst = gtoh(machInst);
- // Checks that the instruction matches what we expected it to be.
- // Checks both the machine instruction and the PC.
- validateInst(inst);
+ // decode the instruction
+ machInst = gtoh(machInst);
+ // Checks that the instruction matches what we expected it to be.
+ // Checks both the machine instruction and the PC.
+ validateInst(inst);
- curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC()));
+ curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC()));
#if FULL_SYSTEM
- cpuXC->setInst(machInst);
+ cpuXC->setInst(machInst);
#endif // FULL_SYSTEM
- fault = inst->getFault();
+ fault = inst->getFault();
+ }
// Either the instruction was a fault and we should process the fault,
// or we should just go ahead execute the instruction. This assumes
diff --git a/cpu/o3/fetch_impl.hh b/cpu/o3/fetch_impl.hh
index b4ff69d89..523719945 100644
--- a/cpu/o3/fetch_impl.hh
+++ b/cpu/o3/fetch_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2004-2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,22 +27,21 @@
*/
#include "arch/isa_traits.hh"
-#include "sim/byteswap.hh"
#include "cpu/exetrace.hh"
#include "cpu/o3/fetch.hh"
#include "mem/base_mem.hh"
#include "mem/mem_interface.hh"
#include "mem/mem_req.hh"
-
+#include "sim/byteswap.hh"
#include "sim/root.hh"
#if FULL_SYSTEM
+#include "arch/tlb.hh"
+#include "arch/vtophys.hh"
#include "base/remote_gdb.hh"
#include "mem/functional/memory_control.hh"
#include "mem/functional/physical.hh"
#include "sim/system.hh"
-#include "arch/tlb.hh"
-#include "arch/vtophys.hh"
#else // !FULL_SYSTEM
#include "mem/functional/functional.hh"
#endif // FULL_SYSTEM
@@ -136,14 +135,7 @@ DefaultFetch<Impl>::DefaultFetch(Params *params)
// Create a new memory request.
memReq[tid] = NULL;
-// memReq[tid] = new MemReq();
-/*
- // Need a way of setting this correctly for parallel programs
- // @todo: Figure out how to properly set asid vs thread_num.
- memReq[tid]->asid = tid;
- memReq[tid]->thread_num = tid;
- memReq[tid]->data = new uint8_t[64];
-*/
+
// Create space to store a cache line.
cacheData[tid] = new uint8_t[cacheBlkSize];
@@ -261,10 +253,6 @@ DefaultFetch<Impl>::setCPU(FullCPU *cpu_ptr)
DPRINTF(Fetch, "Setting the CPU pointer.\n");
cpu = cpu_ptr;
- // Set ExecContexts for Memory Requests
-// for (int tid=0; tid < numThreads; tid++)
-// memReq[tid]->xc = cpu->xcBase(tid);
-
// Fetch needs to start fetching instructions at the very beginning,
// so it must start up in active state.
switchToActive();
@@ -362,9 +350,8 @@ DefaultFetch<Impl>::processCacheCompletion(MemReqPtr &req)
// memcpy(cacheData[tid], memReq[tid]->data, memReq[tid]->size);
- // Reset the completion event to NULL.
+ // Reset the mem req to NULL.
memReq[tid] = NULL;
-// memReq[tid]->completionEvent = NULL;
}
template <class Impl>
@@ -468,10 +455,6 @@ template <class Impl>
bool
DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid)
{
- // Check if the instruction exists within the cache.
- // If it does, then proceed on to read the instruction and the rest
- // of the instructions in the cache line until either the end of the
- // cache line or a predicted taken branch is encountered.
Fault fault = NoFault;
#if FULL_SYSTEM
@@ -509,7 +492,7 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
//#endif
// In the case of faults, the fetch stage may need to stall and wait
- // on what caused the fetch (ITB or Icache miss).
+ // for the ITB miss to be handled.
// If translation was successful, attempt to read the first
// instruction.
@@ -518,7 +501,7 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
if (cpu->system->memctrl->badaddr(memReq[tid]->paddr) ||
memReq[tid]->flags & UNCACHEABLE) {
DPRINTF(Fetch, "Fetch: Bad address %#x (hopefully on a "
- "misspeculating path!",
+ "misspeculating path)!",
memReq[tid]->paddr);
ret_fault = TheISA::genMachineCheckFault();
return false;
@@ -587,44 +570,9 @@ DefaultFetch<Impl>::doSquash(const Addr &new_PC, unsigned tid)
if (fetchStatus[tid] == IcacheMissStall && icacheInterface) {
DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n",
tid);
-// icacheInterface->squash(tid);
-/*
- if (memReq[tid]->completionEvent) {
- if (memReq[tid]->completionEvent->scheduled()) {
- memReq[tid]->completionEvent->squash();
- } else {
- delete memReq[tid]->completionEvent;
- memReq[tid]->completionEvent = NULL;
- }
- }
-*/
memReq[tid] = NULL;
}
- if (fetchStatus[tid] == TrapPending) {
- // @todo: Hardcoded number here
-
- // This is only effective if communication to and from commit
- // is identical. If it's faster to commit than it is from
- // commit to here, then it causes problems.
-
- bool found_fault = false;
- for (int i = 0; i > -5; --i) {
- if (fetchQueue->access(i)->fetchFault) {
- DPRINTF(Fetch, "[tid:%i]: Fetch used to be in a trap, "
- "clearing it.\n",
- tid);
- fetchQueue->access(i)->fetchFault = NoFault;
- found_fault = true;
- }
- }
- if (!found_fault) {
- warn("%lli Fault from fetch not found in time buffer!",
- curTick);
- }
- toDecode->clearFetchFault = true;
- }
-
fetchStatus[tid] = Squashing;
++fetchSquashCycles;
@@ -643,7 +591,6 @@ DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC,
// Tell the CPU to remove any instructions that are in flight between
// fetch and decode.
cpu->removeInstsUntil(seq_num, tid);
- youngestSN = seq_num;
}
template<class Impl>
@@ -829,7 +776,6 @@ DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid)
// In any case, squash.
squash(fromCommit->commitInfo[tid].nextPC,tid);
- youngestSN = fromCommit->commitInfo[tid].doneSeqNum;
// Also check if there's a mispredict that happened.
if (fromCommit->commitInfo[tid].branchMispredict) {
@@ -1009,8 +955,6 @@ DefaultFetch<Impl>::fetch(bool &status_change)
// Get a sequence number.
inst_seq = cpu->getAndIncrementInstSeq();
- youngestSN = inst_seq;
-
// Make sure this is a valid index.
assert(offset <= cacheBlkSize - instSize);
@@ -1095,14 +1039,37 @@ DefaultFetch<Impl>::fetch(bool &status_change)
// This stage will not be able to continue until all the ROB
// slots are empty, at which point the fault can be handled.
// The only other way it can wake up is if a squash comes along
- // and changes the PC. Not sure how to handle that case...perhaps
- // have it handled by the upper level CPU class which peeks into the
- // time buffer and sees if a squash comes along, in which case it
- // changes the status.
+ // and changes the PC.
#if FULL_SYSTEM
+ assert(numInst != fetchWidth);
+ // Get a sequence number.
+ inst_seq = cpu->getAndIncrementInstSeq();
+ // We will use a nop in order to carry the fault.
+ ext_inst = TheISA::NoopMachInst;
+
+ // Create a new DynInst from the dummy nop.
+ DynInstPtr instruction = new DynInst(ext_inst, fetch_PC,
+ next_PC,
+ inst_seq, cpu);
+ instruction->setPredTarg(next_PC + instSize);
+ instruction->setThread(tid);
+
+ instruction->setASID(tid);
+
+ instruction->setState(cpu->thread[tid]);
+
+ instruction->traceData = NULL;
+
+ instruction->setInstListIt(cpu->addInst(instruction));
+
+ instruction->fault = fault;
+
+ toDecode->insts[numInst] = instruction;
+ toDecode->size++;
+
// Tell the commit stage the fault we had.
- toDecode->fetchFault = fault;
- toDecode->fetchFaultSN = cpu->globalSeqNum;
+// toDecode->fetchFault = fault;
+// toDecode->fetchFaultSN = cpu->globalSeqNum;
DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n",tid);
diff --git a/cpu/ozone/front_end.hh b/cpu/ozone/front_end.hh
index f9db9ea5c..326f7d2c9 100644
--- a/cpu/ozone/front_end.hh
+++ b/cpu/ozone/front_end.hh
@@ -120,6 +120,7 @@ class FrontEnd
SerializeComplete,
RenameBlocked,
QuiescePending,
+ TrapPending,
BEBlocked
};
diff --git a/cpu/ozone/front_end_impl.hh b/cpu/ozone/front_end_impl.hh
index 8ae9ec696..cd57aeef4 100644
--- a/cpu/ozone/front_end_impl.hh
+++ b/cpu/ozone/front_end_impl.hh
@@ -268,11 +268,9 @@ FrontEnd<Impl>::tick()
}
if (status == RenameBlocked || status == SerializeBlocked ||
- status == BEBlocked) {
- // This might cause the front end to run even though it
- // shouldn't, but this should only be a problem for one cycle.
- // Also will cause a one cycle bubble between changing state
- // and restarting.
+ status == TrapPending || status == BEBlocked) {
+ // Will cause a one cycle bubble between changing state and
+ // restarting.
DPRINTF(FE, "In blocked status.\n");
fetchBlockedCycles++;
@@ -537,9 +535,32 @@ void
FrontEnd<Impl>::handleFault(Fault &fault)
{
DPRINTF(FE, "Fault at fetch, telling commit\n");
- backEnd->fetchFault(fault);
+// backEnd->fetchFault(fault);
// We're blocked on the back end until it handles this fault.
- status = BEBlocked;
+ status = TrapPending;
+
+ // Get a sequence number.
+ InstSeqNum inst_seq = getAndIncrementInstSeq();
+ // We will use a nop in order to carry the fault.
+ ExtMachInst ext_inst = TheISA::NoopMachInst;
+
+ // Create a new DynInst from the dummy nop.
+ DynInstPtr instruction = new DynInst(ext_inst, PC,
+ PC+sizeof(MachInst),
+ inst_seq, cpu);
+ instruction->setPredTarg(instruction->readNextPC());
+// instruction->setThread(tid);
+
+// instruction->setASID(tid);
+
+ instruction->setState(thread);
+
+ instruction->traceData = NULL;
+
+ instruction->fault = fault;
+ instruction->setCanIssue();
+ instBuffer.push_back(instruction);
+ ++instBufferSize;
}
template <class Impl>
@@ -881,7 +902,6 @@ FrontEnd<Impl>::dumpInsts()
(*buff_it)->isSquashed());
buff_it++;
}
-
}
template <class Impl>
diff --git a/cpu/ozone/lw_back_end_impl.hh b/cpu/ozone/lw_back_end_impl.hh
index a82dd5b70..db0872e52 100644
--- a/cpu/ozone/lw_back_end_impl.hh
+++ b/cpu/ozone/lw_back_end_impl.hh
@@ -652,7 +652,7 @@ LWBackEnd<Impl>::tick()
squashFromTrap();
} else if (xcSquash) {
squashFromXC();
- } else if (fetchHasFault && robEmpty() && frontEnd->isEmpty() && !LSQ.hasStoresToWB()) {
+ } /*else if (fetchHasFault && robEmpty() && frontEnd->isEmpty() && !LSQ.hasStoresToWB()) {
DPRINTF(BE, "ROB and front end empty, handling fetch fault\n");
Fault fetch_fault = frontEnd->getFault();
if (fetch_fault == NoFault) {
@@ -662,7 +662,7 @@ LWBackEnd<Impl>::tick()
handleFault(fetch_fault);
fetchHasFault = false;
}
- }
+ }*/
#endif
if (dispatchStatus != Blocked) {
@@ -777,6 +777,12 @@ LWBackEnd<Impl>::dispatchInsts()
inst->seqNum);
exeList.push(inst);
}
+ } else if (inst->isNop()) {
+ DPRINTF(BE, "Nop encountered [sn:%lli], skipping exeList.\n",
+ inst->seqNum);
+ inst->setIssued();
+ inst->setExecuted();
+ inst->setCanCommit();
} else {
DPRINTF(BE, "Instruction [sn:%lli] ready, addding to exeList.\n",
inst->seqNum);