inorder: implement trap handling

This commit is contained in:
Korey Sewell 2011-06-19 21:43:36 -04:00
parent 061b369d28
commit 7dea79535c
19 changed files with 205 additions and 139 deletions

View file

@ -142,7 +142,8 @@ InOrderCPU::CPUEvent::process()
case Trap: case Trap:
DPRINTF(InOrderCPU, "Trapping CPU\n"); DPRINTF(InOrderCPU, "Trapping CPU\n");
cpu->trapCPU(fault, tid, inst); cpu->trap(fault, tid, inst);
cpu->resPool->trap(fault, tid, inst);
break; break;
default: default:
@ -451,8 +452,8 @@ InOrderCPU::createBackEndSked(DynInstPtr inst)
if (inst->splitInst) if (inst->splitInst)
M.needs(DCache, CacheUnit::InitSecondSplitRead); M.needs(DCache, CacheUnit::InitSecondSplitRead);
} else if ( inst->isStore() ) { } else if ( inst->isStore() ) {
if ( inst->numSrcRegs() >= 2 ) { for (int i = 1; i < inst->numSrcRegs(); i++ ) {
M.needs(RegManager, UseDefUnit::ReadSrcReg, 1); M.needs(RegManager, UseDefUnit::ReadSrcReg, i);
} }
M.needs(AGEN, AGENUnit::GenerateAddr); M.needs(AGEN, AGENUnit::GenerateAddr);
M.needs(DCache, CacheUnit::InitiateWriteData); M.needs(DCache, CacheUnit::InitiateWriteData);
@ -795,14 +796,13 @@ InOrderCPU::updateMemPorts()
#endif #endif
void void
InOrderCPU::trap(Fault fault, ThreadID tid, DynInstPtr inst, int delay) InOrderCPU::trapContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay)
{ {
//@ Squash Pipeline during TRAP
scheduleCpuEvent(Trap, fault, tid, inst, delay); scheduleCpuEvent(Trap, fault, tid, inst, delay);
} }
void void
InOrderCPU::trapCPU(Fault fault, ThreadID tid, DynInstPtr inst) InOrderCPU::trap(Fault fault, ThreadID tid, DynInstPtr inst)
{ {
fault->invoke(tcBase(tid), inst->staticInst); fault->invoke(tcBase(tid), inst->staticInst);
} }
@ -1302,11 +1302,18 @@ InOrderCPU::updateContextSwitchStats()
void void
InOrderCPU::instDone(DynInstPtr inst, ThreadID tid) InOrderCPU::instDone(DynInstPtr inst, ThreadID tid)
{ {
// Set the CPU's PCs - This contributes to the precise state of the CPU // Set the nextPC to be fetched if this is the last instruction
// committed
// ========
// This contributes to the precise state of the CPU
// which can be used when restoring a thread to the CPU after after any // which can be used when restoring a thread to the CPU after after any
// type of context switching activity (fork, exception, etc.) // type of context switching activity (fork, exception, etc.)
pcState(inst->pcState(), tid); TheISA::PCState comm_pc = inst->pcState();
lastCommittedPC[tid] = comm_pc;
TheISA::advancePC(comm_pc, inst->staticInst);
pcState(comm_pc, tid);
//@todo: may be unnecessary with new-ISA-specific branch handling code
if (inst->isControl()) { if (inst->isControl()) {
thread[tid]->lastGradIsBranch = true; thread[tid]->lastGradIsBranch = true;
thread[tid]->lastBranchPC = inst->pcState(); thread[tid]->lastBranchPC = inst->pcState();

View file

@ -275,6 +275,9 @@ class InOrderCPU : public BaseCPU
/** Program Counters */ /** Program Counters */
TheISA::PCState pc[ThePipeline::MaxThreads]; TheISA::PCState pc[ThePipeline::MaxThreads];
/** Last Committed PC */
TheISA::PCState lastCommittedPC[ThePipeline::MaxThreads];
/** The Register File for the CPU */ /** The Register File for the CPU */
union { union {
FloatReg f[ThePipeline::MaxThreads][TheISA::NumFloatRegs]; FloatReg f[ThePipeline::MaxThreads][TheISA::NumFloatRegs];
@ -430,33 +433,45 @@ class InOrderCPU : public BaseCPU
bool validDataAddr(Addr addr) { return true; } bool validDataAddr(Addr addr) { return true; }
#endif #endif
/** trap() - sets up a trap event on the cpuTraps to handle given fault. /** Schedule a trap on the CPU */
* trapCPU() - Traps to handle given fault void trapContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay = 0);
*/
void trap(Fault fault, ThreadID tid, DynInstPtr inst, int delay = 0); /** Perform trap to Handle Given Fault */
void trapCPU(Fault fault, ThreadID tid, DynInstPtr inst); void trap(Fault fault, ThreadID tid, DynInstPtr inst);
/** Schedule thread activation on the CPU */
void activateContext(ThreadID tid, int delay = 0);
/** Add Thread to Active Threads List. */ /** Add Thread to Active Threads List. */
void activateContext(ThreadID tid, int delay = 0);
void activateThread(ThreadID tid); void activateThread(ThreadID tid);
/** Activate Thread In Each Pipeline Stage */
void activateThreadInPipeline(ThreadID tid); void activateThreadInPipeline(ThreadID tid);
/** Add Thread to Active Threads List. */ /** Schedule Thread Activation from Ready List */
void activateNextReadyContext(int delay = 0); void activateNextReadyContext(int delay = 0);
/** Add Thread From Ready List to Active Threads List. */
void activateNextReadyThread(); void activateNextReadyThread();
/** Remove from Active Thread List */ /** Schedule a thread deactivation on the CPU */
void deactivateContext(ThreadID tid, int delay = 0); void deactivateContext(ThreadID tid, int delay = 0);
/** Remove from Active Thread List */
void deactivateThread(ThreadID tid); void deactivateThread(ThreadID tid);
/** Suspend Thread, Remove from Active Threads List, Add to Suspend List */ /** Schedule a thread suspension on the CPU */
void suspendContext(ThreadID tid, int delay = 0); void suspendContext(ThreadID tid, int delay = 0);
/** Suspend Thread, Remove from Active Threads List, Add to Suspend List */
void suspendThread(ThreadID tid); void suspendThread(ThreadID tid);
/** Schedule a thread halt on the CPU */
void haltContext(ThreadID tid, int delay = 0);
/** Halt Thread, Remove from Active Thread List, Place Thread on Halted /** Halt Thread, Remove from Active Thread List, Place Thread on Halted
* Threads List * Threads List
*/ */
void haltContext(ThreadID tid, int delay = 0);
void haltThread(ThreadID tid); void haltThread(ThreadID tid);
/** squashFromMemStall() - sets up a squash event /** squashFromMemStall() - sets up a squash event

View file

@ -54,7 +54,7 @@ InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
InstSeqNum seq_num, InstSeqNum seq_num,
ThreadID tid, ThreadID tid,
unsigned _asid) unsigned _asid)
: seqNum(seq_num), bdelaySeqNum(0), threadNumber(tid), asid(_asid), : seqNum(seq_num), squashSeqNum(0), threadNumber(tid), asid(_asid),
virtProcNumber(0), staticInst(NULL), traceData(NULL), cpu(cpu), virtProcNumber(0), staticInst(NULL), traceData(NULL), cpu(cpu),
thread(state), fault(NoFault), memData(NULL), loadData(0), thread(state), fault(NoFault), memData(NULL), loadData(0),
storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0), storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0),
@ -319,7 +319,15 @@ void
InOrderDynInst::setSquashInfo(unsigned stage_num) InOrderDynInst::setSquashInfo(unsigned stage_num)
{ {
squashingStage = stage_num; squashingStage = stage_num;
bdelaySeqNum = seqNum;
// If it's a fault, then we need to squash
// the faulting instruction too. Squash
// functions squash above a seqNum, so we
// decrement here for that case
if (fault != NoFault)
squashSeqNum = seqNum - 1;
else
squashSeqNum = seqNum;
#if ISA_HAS_DELAY_SLOT #if ISA_HAS_DELAY_SLOT
if (isControl()) { if (isControl()) {
@ -329,10 +337,9 @@ InOrderDynInst::setSquashInfo(unsigned stage_num)
// Check to see if we should squash after the // Check to see if we should squash after the
// branch or after a branch delay slot. // branch or after a branch delay slot.
if (pc.nextInstAddr() == pc.instAddr() + sizeof(MachInst)) if (pc.nextInstAddr() == pc.instAddr() + sizeof(MachInst))
bdelaySeqNum = seqNum + 1; squashSeqNum = seqNum + 1;
else else
bdelaySeqNum = seqNum; squashSeqNum = seqNum;
} }
#endif #endif
} }

View file

@ -122,8 +122,8 @@ class InOrderDynInst : public FastAlloc, public RefCounted
/** The sequence number of the instruction. */ /** The sequence number of the instruction. */
InstSeqNum seqNum; InstSeqNum seqNum;
/** The sequence number of the instruction. */ /** If this instruction is squashing, the number should we squash behind. */
InstSeqNum bdelaySeqNum; InstSeqNum squashSeqNum;
enum Status { enum Status {
RegDepMapEntry, /// Instruction is entered onto the RegDepMap RegDepMapEntry, /// Instruction is entered onto the RegDepMap

View file

@ -342,43 +342,27 @@ PipelineStage::unblock(ThreadID tid)
} }
void void
PipelineStage::squashDueToBranch(DynInstPtr &inst, ThreadID tid) PipelineStage::setupSquash(DynInstPtr inst, ThreadID tid)
{ {
if (cpu->squashSeqNum[tid] < inst->seqNum && if (cpu->lastSquashCycle[tid] == curTick() &&
cpu->lastSquashCycle[tid] == curTick()){ cpu->squashSeqNum[tid] < inst->seqNum){
DPRINTF(Resource, "Ignoring [sn:%i] branch squash signal due to " DPRINTF(Resource, "Ignoring [sn:%i] branch squash signal due to "
"another stage's squash signal for after [sn:%i].\n", "another stage's squash signal for after [sn:%i].\n",
inst->seqNum, cpu->squashSeqNum[tid]); inst->seqNum, cpu->squashSeqNum[tid]);
} else { } else {
// Send back mispredict information. InstSeqNum squash_seq_num = inst->squashSeqNum;
toPrevStages->stageInfo[stageNum][tid].branchMispredict = true;
toPrevStages->stageInfo[stageNum][tid].predIncorrect = true;
toPrevStages->stageInfo[stageNum][tid].doneSeqNum = inst->seqNum;
toPrevStages->stageInfo[stageNum][tid].squash = true; toPrevStages->stageInfo[stageNum][tid].squash = true;
toPrevStages->stageInfo[stageNum][tid].nextPC = inst->readPredTarg(); toPrevStages->stageInfo[stageNum][tid].doneSeqNum =
squash_seq_num;
toPrevStages->stageInfo[stageNum][tid].branchTaken =
inst->pcState().branching();
#if ISA_HAS_DELAY_SLOT
toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum =
inst->bdelaySeqNum;
InstSeqNum squash_seq_num = inst->bdelaySeqNum;
#else
toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->seqNum;
InstSeqNum squash_seq_num = inst->seqNum;
#endif
DPRINTF(InOrderStage, "Target being re-set to %08p\n",
inst->predInstAddr());
DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], " DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], "
"due to [sn:%i] branch.\n", tid, squash_seq_num, "due to [sn:%i] %s.\n", tid, squash_seq_num,
inst->seqNum); inst->seqNum, inst->instName());
// Save squash num for later stage use // Save squash num for later stage use
cpu->squashSeqNum[tid] = squash_seq_num;
cpu->lastSquashCycle[tid] = curTick(); cpu->lastSquashCycle[tid] = curTick();
cpu->squashSeqNum[tid] = squash_seq_num;
} }
} }
@ -398,7 +382,6 @@ PipelineStage::squashPrevStageInsts(InstSeqNum squash_seq_num, ThreadID tid)
for (int i=0; i < insts_from_prev_stage; i++) { for (int i=0; i < insts_from_prev_stage; i++) {
if (prevStage->insts[i]->threadNumber == tid && if (prevStage->insts[i]->threadNumber == tid &&
prevStage->insts[i]->seqNum > squash_seq_num) { prevStage->insts[i]->seqNum > squash_seq_num) {
// Change Comment to Annulling previous instruction
DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, " DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, "
"[sn:%i] PC %s.\n", "[sn:%i] PC %s.\n",
tid, tid,
@ -676,7 +659,7 @@ PipelineStage::checkSignalsAndUpdate(ThreadID tid)
DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to " DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to "
"squash from stage %u.\n", tid, stage_idx); "squash from stage %u.\n", tid, stage_idx);
InstSeqNum squash_seq_num = fromNextStages-> InstSeqNum squash_seq_num = fromNextStages->
stageInfo[stage_idx][tid].bdelayDoneSeqNum; stageInfo[stage_idx][tid].doneSeqNum;
squash(squash_seq_num, tid); squash(squash_seq_num, tid);
break; //return true; break; //return true;
} }
@ -989,7 +972,7 @@ PipelineStage::processInstSchedule(DynInstPtr inst,int &reqs_processed)
// Remove Thread From Pipeline & Resource Pool // Remove Thread From Pipeline & Resource Pool
inst->squashingStage = stageNum; inst->squashingStage = stageNum;
inst->bdelaySeqNum = inst->seqNum; inst->squashSeqNum = inst->seqNum;
cpu->squashFromMemStall(inst, tid); cpu->squashFromMemStall(inst, tid);
// Switch On Cache Miss // Switch On Cache Miss

View file

@ -227,21 +227,17 @@ class PipelineStage
public: public:
void activateThread(ThreadID tid); void activateThread(ThreadID tid);
/** Squashes if there is a PC-relative branch that was predicted /** Setup Squashing Information to be passed back thru the pipeline */
* incorrectly. Sends squash information back to fetch. void setupSquash(DynInstPtr inst, ThreadID tid);
*/
void squashDueToBranch(DynInstPtr &inst, ThreadID tid);
virtual void squashDueToMemStall(InstSeqNum seq_num, ThreadID tid); virtual void squashDueToMemStall(InstSeqNum seq_num, ThreadID tid);
/** Perform squash of instructions above seq_num */
virtual void squash(InstSeqNum squash_num, ThreadID tid);
/** Squash instructions from stage buffer */ /** Squash instructions from stage buffer */
void squashPrevStageInsts(InstSeqNum squash_seq_num, ThreadID tid); void squashPrevStageInsts(InstSeqNum squash_seq_num, ThreadID tid);
/** Squashes due to commit signalling a squash. Changes status to
* squashing and clears block/unblock signals as needed.
*/
virtual void squash(InstSeqNum squash_num, ThreadID tid);
void dumpInsts(); void dumpInsts();
protected: protected:

View file

@ -290,10 +290,8 @@ Resource::deactivateThread(ThreadID tid)
void void
Resource::setupSquash(DynInstPtr inst, int stage_num, ThreadID tid) Resource::setupSquash(DynInstPtr inst, int stage_num, ThreadID tid)
{ {
assert(inst->isControl() && "Function Assumes Squash From A Branch");
// Squash In Pipeline Stage // Squash In Pipeline Stage
cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid); cpu->pipelineStage[stage_num]->setupSquash(inst, tid);
// Schedule Squash Through-out Resource Pool // Schedule Squash Through-out Resource Pool
cpu->resPool->scheduleEvent( cpu->resPool->scheduleEvent(

View file

@ -106,6 +106,9 @@ class Resource {
*/ */
virtual void instGraduated(InstSeqNum seq_num, ThreadID tid) { } virtual void instGraduated(InstSeqNum seq_num, ThreadID tid) { }
/** Post-processsing for Trap Generated from this instruction */
virtual void trap(Fault fault, ThreadID tid, DynInstPtr inst) { }
/** Request usage of this resource. Returns a ResourceRequest object /** Request usage of this resource. Returns a ResourceRequest object
* with all the necessary resource information * with all the necessary resource information
*/ */

View file

@ -192,7 +192,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
res_pool_event->setEvent(e_type, res_pool_event->setEvent(e_type,
inst, inst,
inst->squashingStage, inst->squashingStage,
inst->bdelaySeqNum, inst->squashSeqNum,
inst->readTid()); inst->readTid());
res_pool_event->schedule(curTick() + cpu->cycles(delay)); res_pool_event->schedule(curTick() + cpu->cycles(delay));
@ -208,7 +208,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
res_pool_event->setEvent(e_type, res_pool_event->setEvent(e_type,
inst, inst,
inst->squashingStage, inst->squashingStage,
inst->bdelaySeqNum, inst->squashSeqNum,
tid); tid);
res_pool_event->schedule(curTick() + cpu->cycles(delay)); res_pool_event->schedule(curTick() + cpu->cycles(delay));
@ -238,7 +238,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
res_pool_event->setEvent(e_type, res_pool_event->setEvent(e_type,
inst, inst,
inst->squashingStage, inst->squashingStage,
inst->bdelaySeqNum, inst->squashSeqNum,
inst->readTid()); inst->readTid());
res_pool_event->schedule(curTick() + cpu->cycles(delay)); res_pool_event->schedule(curTick() + cpu->cycles(delay));

View file

@ -234,6 +234,18 @@ ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num,
tid); tid);
} }
void
ResourcePool::trap(Fault fault, ThreadID tid, DynInstPtr inst)
{
DPRINTF(Resource, "[tid:%i] Broadcasting Trap to all "
"resources.\n", tid);
int num_resources = resources.size();
for (int idx = 0; idx < num_resources; idx++)
resources[idx]->trap(fault, tid, inst);
}
int int
ResourcePool::slotsAvail(int res_idx) ResourcePool::slotsAvail(int res_idx)
{ {
@ -272,7 +284,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
e_type, e_type,
inst, inst,
inst->squashingStage, inst->squashingStage,
inst->bdelaySeqNum, inst->squashSeqNum,
inst->readTid()); inst->readTid());
cpu->schedule(res_pool_event, when); cpu->schedule(res_pool_event, when);
} }
@ -289,7 +301,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
e_type, e_type,
inst, inst,
inst->squashingStage, inst->squashingStage,
inst->bdelaySeqNum, inst->squashSeqNum,
tid); tid);
cpu->schedule(res_pool_event, when); cpu->schedule(res_pool_event, when);
@ -308,7 +320,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
e_type, e_type,
inst, inst,
inst->squashingStage, inst->squashingStage,
inst->bdelaySeqNum, inst->squashSeqNum,
tid); tid);
cpu->schedule(res_pool_event, sked_tick); cpu->schedule(res_pool_event, sked_tick);
@ -337,7 +349,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
new ResPoolEvent(this,e_type, new ResPoolEvent(this,e_type,
inst, inst,
inst->squashingStage, inst->squashingStage,
inst->bdelaySeqNum, inst->squashSeqNum,
inst->readTid()); inst->readTid());
cpu->schedule(res_pool_event, when); cpu->schedule(res_pool_event, when);
} }

View file

@ -182,6 +182,9 @@ class ResourcePool {
/** Broadcast graduation to all resources */ /** Broadcast graduation to all resources */
void instGraduated(InstSeqNum seq_num, ThreadID tid); void instGraduated(InstSeqNum seq_num, ThreadID tid);
/** Broadcast trap to all resources */
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
/** The number of instructions available that a resource can /** The number of instructions available that a resource can
* can still process. * can still process.
*/ */

View file

@ -78,8 +78,8 @@ AGENUnit::execute(int slot_num)
if (inst->fault == NoFault) { if (inst->fault == NoFault) {
agen_req->done(); agen_req->done();
} else { } else {
fatal("%s encountered while calculating address [sn:%i]", fatal("%s encountered while calculating address [sn:%i] %s",
inst->fault->name(), seq_num); inst->fault->name(), seq_num, inst->instName());
} }
agens++; agens++;

View file

@ -441,9 +441,10 @@ CacheUnit::doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size,
cache_req->tlbStall = true; cache_req->tlbStall = true;
// schedule a time to process the tlb miss.
// latency hardcoded to 1 (for now), but will be updated
// when timing translation gets added in
scheduleEvent(slot_idx, 1); scheduleEvent(slot_idx, 1);
cpu->trap(inst->fault, tid, inst);
} else { } else {
DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated " DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated "
"to phys. addr:%08p.\n", tid, inst->seqNum, "to phys. addr:%08p.\n", tid, inst->seqNum,
@ -1072,6 +1073,11 @@ CacheUnitEvent::process()
CacheUnit* tlb_res = dynamic_cast<CacheUnit*>(resource); CacheUnit* tlb_res = dynamic_cast<CacheUnit*>(resource);
assert(tlb_res); assert(tlb_res);
//@todo: eventually, we should do a timing translation w/
// hw page table walk on tlb miss
DPRINTF(Fault, "Handling Fault %s\n", inst->fault->name());
inst->fault->invoke(tlb_res->cpu->tcBase(tid), inst->staticInst);
tlb_res->tlbBlocked[tid] = false; tlb_res->tlbBlocked[tid] = false;
tlb_res->cpu->pipelineStage[stage_num]-> tlb_res->cpu->pipelineStage[stage_num]->

View file

@ -140,9 +140,10 @@ ExecutionUnit::execute(int slot_num)
// Evaluate Branch // Evaluate Branch
fault = inst->execute(); fault = inst->execute();
executions++; executions++;
inst->setExecuted();
if (fault == NoFault) { if (fault == NoFault) {
inst->setExecuted();
if (inst->mispredicted()) { if (inst->mispredicted()) {
assert(inst->isControl()); assert(inst->isControl());
@ -190,7 +191,8 @@ ExecutionUnit::execute(int slot_num)
exec_req->done(); exec_req->done();
} else { } else {
warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); DPRINTF(Fault, "[tid:%i]:[sn:%i]: Fault %s found\n",
inst->readTid(), inst->seqNum, fault->name());
inst->fault = fault; inst->fault = fault;
exec_req->done(); exec_req->done();
} }
@ -210,6 +212,8 @@ ExecutionUnit::execute(int slot_num)
} else { } else {
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: had a %s " DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: had a %s "
"fault.\n", inst->readTid(), seq_num, fault->name()); "fault.\n", inst->readTid(), seq_num, fault->name());
DPRINTF(Fault, "[tid:%i]:[sn:%i]: Fault %s found\n",
inst->readTid(), inst->seqNum, fault->name());
inst->fault = fault; inst->fault = fault;
} }

View file

@ -127,7 +127,7 @@ FetchSeqUnit::execute(int slot_num)
DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to " DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to "
"start from stage %i, after [sn:%i].\n", "start from stage %i, after [sn:%i].\n",
tid, stage_num, inst->bdelaySeqNum); tid, stage_num, inst->squashSeqNum);
} }
} else { } else {
DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Ignoring branch " DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Ignoring branch "
@ -152,8 +152,8 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
"stage %i.\n", tid, inst->instName(), inst->pcState(), "stage %i.\n", tid, inst->instName(), inst->pcState(),
squash_stage); squash_stage);
if (squashSeqNum[tid] <= squash_seq_num && if (lastSquashCycle[tid] == curTick() &&
lastSquashCycle[tid] == curTick()) { squashSeqNum[tid] <= squash_seq_num) {
DPRINTF(InOrderFetchSeq, "[tid:%i]: Ignoring squash from stage %i, " DPRINTF(InOrderFetchSeq, "[tid:%i]: Ignoring squash from stage %i, "
"since there is an outstanding squash that is older.\n", "since there is an outstanding squash that is older.\n",
tid, squash_stage); tid, squash_stage);
@ -161,57 +161,65 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
squashSeqNum[tid] = squash_seq_num; squashSeqNum[tid] = squash_seq_num;
lastSquashCycle[tid] = curTick(); lastSquashCycle[tid] = curTick();
TheISA::PCState nextPC; if (inst->fault != NoFault) {
assert(inst->staticInst); // A Trap Caused This Fault and will update the pc state
if (inst->isControl()) { // when done trapping
nextPC = inst->readPredTarg(); DPRINTF(InOrderFetchSeq, "[tid:%i] Blocking due to fault @ "
"[sn:%i].\n", inst->seqNum);
// If we are already fetching this PC then advance to next PC pcValid[tid] = false;
// =======
// This should handle ISAs w/delay slots and annulled delay
// slots to figure out which is the next PC to fetch after
// a mispredict
DynInstPtr bdelay_inst = NULL;
ListIt bdelay_it;
if (inst->onInstList) {
bdelay_it = inst->getInstListIt();
bdelay_it++;
} else {
InstSeqNum branch_delay_num = inst->seqNum + 1;
bdelay_it = cpu->findInst(branch_delay_num, tid);
}
if (bdelay_it != cpu->instList[tid].end()) {
bdelay_inst = (*bdelay_it);
}
if (bdelay_inst) {
DPRINTF(Resource, "Evaluating %s v. %s\n",
bdelay_inst->pc, nextPC);
if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
advancePC(nextPC, inst->staticInst);
DPRINTF(Resource, "Advanced PC to %s\n", nextPC);
}
}
} else { } else {
nextPC = inst->pcState(); TheISA::PCState nextPC;
advancePC(nextPC, inst->staticInst); assert(inst->staticInst);
if (inst->isControl()) {
nextPC = inst->readPredTarg();
// If we are already fetching this PC then advance to next PC
// =======
// This should handle ISAs w/delay slots and annulled delay
// slots to figure out which is the next PC to fetch after
// a mispredict
DynInstPtr bdelay_inst = NULL;
ListIt bdelay_it;
if (inst->onInstList) {
bdelay_it = inst->getInstListIt();
bdelay_it++;
} else {
InstSeqNum branch_delay_num = inst->seqNum + 1;
bdelay_it = cpu->findInst(branch_delay_num, tid);
}
if (bdelay_it != cpu->instList[tid].end()) {
bdelay_inst = (*bdelay_it);
}
if (bdelay_inst) {
DPRINTF(Resource, "Evaluating %s v. %s\n",
bdelay_inst->pc, nextPC);
if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
advancePC(nextPC, inst->staticInst);
DPRINTF(Resource, "Advanced PC to %s\n", nextPC);
}
}
} else {
nextPC = inst->pcState();
advancePC(nextPC, inst->staticInst);
}
DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %s.\n",
tid, nextPC);
pc[tid] = nextPC;
// Unblock Any Stages Waiting for this information to be updated ...
if (!pcValid[tid]) {
cpu->pipelineStage[pcBlockStage[tid]]->
toPrevStages->stageUnblock[pcBlockStage[tid]][tid] = true;
}
pcValid[tid] = true;
} }
}
DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %s.\n",
tid, nextPC);
pc[tid] = nextPC;
// Unblock Any Stages Waiting for this information to be updated ...
if (!pcValid[tid]) {
cpu->pipelineStage[pcBlockStage[tid]]->
toPrevStages->stageUnblock[pcBlockStage[tid]][tid] = true;
}
pcValid[tid] = true;
}
Resource::squash(inst, squash_stage, squash_seq_num, tid); Resource::squash(inst, squash_stage, squash_seq_num, tid);
} }
@ -272,6 +280,17 @@ FetchSeqUnit::suspendThread(ThreadID tid)
deactivateThread(tid); deactivateThread(tid);
} }
void
FetchSeqUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
{
pcValid[tid] = true;
pc[tid] = cpu->pcState(tid);
DPRINTF(Fault, "[tid:%i]: Trap updating to PC: "
"%s.\n", tid, pc[tid]);
DPRINTF(InOrderFetchSeq, "[tid:%i]: Trap updating to PC: "
"%s.\n", tid, pc[tid]);
}
void void
FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid) FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
{ {

View file

@ -65,15 +65,12 @@ class FetchSeqUnit : public Resource {
void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid); void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid);
/** Override default Resource squash sequence. This actually, /** Update to correct PC from a squash */
* looks in the global communication buffer to get squash
* info
*/
void squash(DynInstPtr inst, int squash_stage, void squash(DynInstPtr inst, int squash_stage,
InstSeqNum squash_seq_num, ThreadID tid); InstSeqNum squash_seq_num, ThreadID tid);
/** Update to correct PC from a trap */
inline void squashAfterInst(DynInstPtr inst, int stage_num, ThreadID tid); void trap(Fault fault, ThreadID tid, DynInstPtr inst);
protected: protected:
unsigned instSize; unsigned instSize;

View file

@ -111,6 +111,7 @@ FetchUnit::createMachInst(std::list<FetchBlock*>::iterator fetch_it,
predecoder.setTC(cpu->thread[tid]->getTC()); predecoder.setTC(cpu->thread[tid]->getTC());
predecoder.moreBytes(instPC, inst->instAddr(), mach_inst); predecoder.moreBytes(instPC, inst->instAddr(), mach_inst);
assert(predecoder.extMachInstReady());
ext_inst = predecoder.getExtMachInst(instPC); ext_inst = predecoder.getExtMachInst(instPC);
inst->pcState(instPC); inst->pcState(instPC);
@ -552,3 +553,9 @@ FetchUnit::squashCacheRequest(CacheReqPtr req_ptr)
CacheUnit::squashCacheRequest(req_ptr); CacheUnit::squashCacheRequest(req_ptr);
} }
void
FetchUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
{
//@todo: per thread?
predecoder.reset();
}

View file

@ -88,6 +88,8 @@ class FetchUnit : public CacheUnit
/** Executes one of the commands from the "Command" enum */ /** Executes one of the commands from the "Command" enum */
void execute(int slot_num); void execute(int slot_num);
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
private: private:
void squashCacheRequest(CacheReqPtr req_ptr); void squashCacheRequest(CacheReqPtr req_ptr);

View file

@ -67,7 +67,14 @@ GraduationUnit::execute(int slot_num)
// Handle Any Faults Before Graduating Instruction // Handle Any Faults Before Graduating Instruction
if (inst->fault != NoFault) { if (inst->fault != NoFault) {
cpu->trap(inst->fault, tid, inst); DPRINTF(Fault, "[sn:%i]: fault %s found for %s\n",
inst->seqNum, inst->fault->name(),
inst->instName());
inst->setSquashInfo(stage_num);
setupSquash(inst, stage_num, tid);
cpu->trapContext(inst->fault, tid, inst);
grad_req->done(false);
return;
} }
DPRINTF(InOrderGraduation, DPRINTF(InOrderGraduation,