From: Korey Sewell Date: Mon, 20 Jun 2011 01:43:36 +0000 (-0400) Subject: inorder: implement trap handling X-Git-Tag: stable_2012_02_02~248 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7dea79535c87b68b5fc6143190d09b8fc364f2aa;p=gem5.git inorder: implement trap handling --- diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index 2e3b0188b..e0e4d9a15 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -142,7 +142,8 @@ InOrderCPU::CPUEvent::process() case Trap: DPRINTF(InOrderCPU, "Trapping CPU\n"); - cpu->trapCPU(fault, tid, inst); + cpu->trap(fault, tid, inst); + cpu->resPool->trap(fault, tid, inst); break; default: @@ -451,8 +452,8 @@ InOrderCPU::createBackEndSked(DynInstPtr inst) if (inst->splitInst) M.needs(DCache, CacheUnit::InitSecondSplitRead); } else if ( inst->isStore() ) { - if ( inst->numSrcRegs() >= 2 ) { - M.needs(RegManager, UseDefUnit::ReadSrcReg, 1); + for (int i = 1; i < inst->numSrcRegs(); i++ ) { + M.needs(RegManager, UseDefUnit::ReadSrcReg, i); } M.needs(AGEN, AGENUnit::GenerateAddr); M.needs(DCache, CacheUnit::InitiateWriteData); @@ -795,14 +796,13 @@ InOrderCPU::updateMemPorts() #endif 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); } void -InOrderCPU::trapCPU(Fault fault, ThreadID tid, DynInstPtr inst) +InOrderCPU::trap(Fault fault, ThreadID tid, DynInstPtr inst) { fault->invoke(tcBase(tid), inst->staticInst); } @@ -1302,11 +1302,18 @@ InOrderCPU::updateContextSwitchStats() void 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 // 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()) { thread[tid]->lastGradIsBranch = true; thread[tid]->lastBranchPC = inst->pcState(); diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index aad701ff4..f60258c96 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -275,6 +275,9 @@ class InOrderCPU : public BaseCPU /** Program Counters */ TheISA::PCState pc[ThePipeline::MaxThreads]; + /** Last Committed PC */ + TheISA::PCState lastCommittedPC[ThePipeline::MaxThreads]; + /** The Register File for the CPU */ union { FloatReg f[ThePipeline::MaxThreads][TheISA::NumFloatRegs]; @@ -430,33 +433,45 @@ class InOrderCPU : public BaseCPU bool validDataAddr(Addr addr) { return true; } #endif - /** trap() - sets up a trap event on the cpuTraps to handle given fault. - * trapCPU() - Traps to handle given fault - */ - void trap(Fault fault, ThreadID tid, DynInstPtr inst, int delay = 0); - void trapCPU(Fault fault, ThreadID tid, DynInstPtr inst); + /** Schedule a trap on the CPU */ + void trapContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay = 0); - /** Add Thread to Active Threads List. */ + /** Perform trap to Handle Given Fault */ + 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. */ void activateThread(ThreadID tid); + + /** Activate Thread In Each Pipeline Stage */ void activateThreadInPipeline(ThreadID tid); - /** Add Thread to Active Threads List. */ + /** Schedule Thread Activation from Ready List */ void activateNextReadyContext(int delay = 0); + + /** Add Thread From Ready List to Active Threads List. */ void activateNextReadyThread(); - /** Remove from Active Thread List */ + /** Schedule a thread deactivation on the CPU */ void deactivateContext(ThreadID tid, int delay = 0); + + /** Remove from Active Thread List */ 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); + + /** Suspend Thread, Remove from Active Threads List, Add to Suspend List */ 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 * Threads List */ - void haltContext(ThreadID tid, int delay = 0); void haltThread(ThreadID tid); /** squashFromMemStall() - sets up a squash event diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc index d8bfbacc7..d42e84016 100644 --- a/src/cpu/inorder/inorder_dyn_inst.cc +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -54,7 +54,7 @@ InOrderDynInst::InOrderDynInst(InOrderCPU *cpu, InstSeqNum seq_num, ThreadID tid, 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), thread(state), fault(NoFault), memData(NULL), loadData(0), storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0), @@ -319,7 +319,15 @@ void InOrderDynInst::setSquashInfo(unsigned 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 (isControl()) { @@ -329,10 +337,9 @@ InOrderDynInst::setSquashInfo(unsigned stage_num) // Check to see if we should squash after the // branch or after a branch delay slot. if (pc.nextInstAddr() == pc.instAddr() + sizeof(MachInst)) - bdelaySeqNum = seqNum + 1; + squashSeqNum = seqNum + 1; else - bdelaySeqNum = seqNum; - + squashSeqNum = seqNum; } #endif } diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh index 73e723312..0776dc5aa 100644 --- a/src/cpu/inorder/inorder_dyn_inst.hh +++ b/src/cpu/inorder/inorder_dyn_inst.hh @@ -122,8 +122,8 @@ class InOrderDynInst : public FastAlloc, public RefCounted /** The sequence number of the instruction. */ InstSeqNum seqNum; - /** The sequence number of the instruction. */ - InstSeqNum bdelaySeqNum; + /** If this instruction is squashing, the number should we squash behind. */ + InstSeqNum squashSeqNum; enum Status { RegDepMapEntry, /// Instruction is entered onto the RegDepMap diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index 51e16b6c4..d37779ce8 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -342,43 +342,27 @@ PipelineStage::unblock(ThreadID tid) } void -PipelineStage::squashDueToBranch(DynInstPtr &inst, ThreadID tid) +PipelineStage::setupSquash(DynInstPtr inst, ThreadID tid) { - if (cpu->squashSeqNum[tid] < inst->seqNum && - cpu->lastSquashCycle[tid] == curTick()){ + if (cpu->lastSquashCycle[tid] == curTick() && + cpu->squashSeqNum[tid] < inst->seqNum){ DPRINTF(Resource, "Ignoring [sn:%i] branch squash signal due to " "another stage's squash signal for after [sn:%i].\n", inst->seqNum, cpu->squashSeqNum[tid]); } else { - // Send back mispredict information. - 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].nextPC = inst->readPredTarg(); - - 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->squashSeqNum; - InstSeqNum squash_seq_num = inst->bdelaySeqNum; -#else - toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->seqNum; - InstSeqNum squash_seq_num = inst->seqNum; -#endif + toPrevStages->stageInfo[stageNum][tid].squash = true; + toPrevStages->stageInfo[stageNum][tid].doneSeqNum = + squash_seq_num; - DPRINTF(InOrderStage, "Target being re-set to %08p\n", - inst->predInstAddr()); DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], " - "due to [sn:%i] branch.\n", tid, squash_seq_num, - inst->seqNum); + "due to [sn:%i] %s.\n", tid, squash_seq_num, + inst->seqNum, inst->instName()); // Save squash num for later stage use - cpu->squashSeqNum[tid] = squash_seq_num; 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++) { if (prevStage->insts[i]->threadNumber == tid && prevStage->insts[i]->seqNum > squash_seq_num) { - // Change Comment to Annulling previous instruction DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, " "[sn:%i] PC %s.\n", tid, @@ -676,7 +659,7 @@ PipelineStage::checkSignalsAndUpdate(ThreadID tid) DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to " "squash from stage %u.\n", tid, stage_idx); InstSeqNum squash_seq_num = fromNextStages-> - stageInfo[stage_idx][tid].bdelayDoneSeqNum; + stageInfo[stage_idx][tid].doneSeqNum; squash(squash_seq_num, tid); break; //return true; } @@ -989,7 +972,7 @@ PipelineStage::processInstSchedule(DynInstPtr inst,int &reqs_processed) // Remove Thread From Pipeline & Resource Pool inst->squashingStage = stageNum; - inst->bdelaySeqNum = inst->seqNum; + inst->squashSeqNum = inst->seqNum; cpu->squashFromMemStall(inst, tid); // Switch On Cache Miss diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh index d0d9112c0..963d96afb 100644 --- a/src/cpu/inorder/pipeline_stage.hh +++ b/src/cpu/inorder/pipeline_stage.hh @@ -227,21 +227,17 @@ class PipelineStage public: void activateThread(ThreadID tid); - /** Squashes if there is a PC-relative branch that was predicted - * incorrectly. Sends squash information back to fetch. - */ - void squashDueToBranch(DynInstPtr &inst, ThreadID tid); + /** Setup Squashing Information to be passed back thru the pipeline */ + void setupSquash(DynInstPtr inst, 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 */ 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(); protected: diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc index 23d33afbe..836335510 100644 --- a/src/cpu/inorder/resource.cc +++ b/src/cpu/inorder/resource.cc @@ -290,10 +290,8 @@ Resource::deactivateThread(ThreadID tid) void Resource::setupSquash(DynInstPtr inst, int stage_num, ThreadID tid) { - assert(inst->isControl() && "Function Assumes Squash From A Branch"); - // Squash In Pipeline Stage - cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid); + cpu->pipelineStage[stage_num]->setupSquash(inst, tid); // Schedule Squash Through-out Resource Pool cpu->resPool->scheduleEvent( diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh index 097497362..fcf01065a 100644 --- a/src/cpu/inorder/resource.hh +++ b/src/cpu/inorder/resource.hh @@ -106,6 +106,9 @@ class Resource { */ 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 * with all the necessary resource information */ diff --git a/src/cpu/inorder/resource_pool.9stage.cc b/src/cpu/inorder/resource_pool.9stage.cc index 78a7d4b88..e0a00ee0f 100644 --- a/src/cpu/inorder/resource_pool.9stage.cc +++ b/src/cpu/inorder/resource_pool.9stage.cc @@ -192,7 +192,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, res_pool_event->setEvent(e_type, inst, inst->squashingStage, - inst->bdelaySeqNum, + inst->squashSeqNum, inst->readTid()); 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, inst, inst->squashingStage, - inst->bdelaySeqNum, + inst->squashSeqNum, tid); 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, inst, inst->squashingStage, - inst->bdelaySeqNum, + inst->squashSeqNum, inst->readTid()); res_pool_event->schedule(curTick() + cpu->cycles(delay)); diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc index 1800aac37..d5b3a5115 100644 --- a/src/cpu/inorder/resource_pool.cc +++ b/src/cpu/inorder/resource_pool.cc @@ -234,6 +234,18 @@ ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, 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 ResourcePool::slotsAvail(int res_idx) { @@ -272,7 +284,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, e_type, inst, inst->squashingStage, - inst->bdelaySeqNum, + inst->squashSeqNum, inst->readTid()); cpu->schedule(res_pool_event, when); } @@ -289,7 +301,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, e_type, inst, inst->squashingStage, - inst->bdelaySeqNum, + inst->squashSeqNum, tid); cpu->schedule(res_pool_event, when); @@ -308,7 +320,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, e_type, inst, inst->squashingStage, - inst->bdelaySeqNum, + inst->squashSeqNum, tid); cpu->schedule(res_pool_event, sked_tick); @@ -337,7 +349,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, new ResPoolEvent(this,e_type, inst, inst->squashingStage, - inst->bdelaySeqNum, + inst->squashSeqNum, inst->readTid()); cpu->schedule(res_pool_event, when); } diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh index b42011091..85c0f70f6 100644 --- a/src/cpu/inorder/resource_pool.hh +++ b/src/cpu/inorder/resource_pool.hh @@ -182,6 +182,9 @@ class ResourcePool { /** Broadcast graduation to all resources */ 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 * can still process. */ diff --git a/src/cpu/inorder/resources/agen_unit.cc b/src/cpu/inorder/resources/agen_unit.cc index d87ca364d..64f6d7544 100644 --- a/src/cpu/inorder/resources/agen_unit.cc +++ b/src/cpu/inorder/resources/agen_unit.cc @@ -78,8 +78,8 @@ AGENUnit::execute(int slot_num) if (inst->fault == NoFault) { agen_req->done(); } else { - fatal("%s encountered while calculating address [sn:%i]", - inst->fault->name(), seq_num); + fatal("%s encountered while calculating address [sn:%i] %s", + inst->fault->name(), seq_num, inst->instName()); } agens++; diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc index c1a3590be..760fdb134 100644 --- a/src/cpu/inorder/resources/cache_unit.cc +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -441,9 +441,10 @@ CacheUnit::doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size, 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); - - cpu->trap(inst->fault, tid, inst); } else { DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated " "to phys. addr:%08p.\n", tid, inst->seqNum, @@ -1072,6 +1073,11 @@ CacheUnitEvent::process() CacheUnit* tlb_res = dynamic_cast(resource); 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->cpu->pipelineStage[stage_num]-> diff --git a/src/cpu/inorder/resources/execution_unit.cc b/src/cpu/inorder/resources/execution_unit.cc index 4363f125d..d7151add1 100644 --- a/src/cpu/inorder/resources/execution_unit.cc +++ b/src/cpu/inorder/resources/execution_unit.cc @@ -140,9 +140,10 @@ ExecutionUnit::execute(int slot_num) // Evaluate Branch fault = inst->execute(); executions++; - inst->setExecuted(); if (fault == NoFault) { + inst->setExecuted(); + if (inst->mispredicted()) { assert(inst->isControl()); @@ -190,7 +191,8 @@ ExecutionUnit::execute(int slot_num) exec_req->done(); } 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; exec_req->done(); } @@ -210,6 +212,8 @@ ExecutionUnit::execute(int slot_num) } else { DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: had a %s " "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; } diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc index 62dbb452a..024f38fdd 100644 --- a/src/cpu/inorder/resources/fetch_seq_unit.cc +++ b/src/cpu/inorder/resources/fetch_seq_unit.cc @@ -127,7 +127,7 @@ FetchSeqUnit::execute(int slot_num) DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to " "start from stage %i, after [sn:%i].\n", - tid, stage_num, inst->bdelaySeqNum); + tid, stage_num, inst->squashSeqNum); } } else { 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(), squash_stage); - if (squashSeqNum[tid] <= squash_seq_num && - lastSquashCycle[tid] == curTick()) { + if (lastSquashCycle[tid] == curTick() && + squashSeqNum[tid] <= squash_seq_num) { DPRINTF(InOrderFetchSeq, "[tid:%i]: Ignoring squash from stage %i, " "since there is an outstanding squash that is older.\n", tid, squash_stage); @@ -161,57 +161,65 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage, squashSeqNum[tid] = squash_seq_num; lastSquashCycle[tid] = curTick(); - TheISA::PCState nextPC; - 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 (inst->fault != NoFault) { + // A Trap Caused This Fault and will update the pc state + // when done trapping + DPRINTF(InOrderFetchSeq, "[tid:%i] Blocking due to fault @ " + "[sn:%i].\n", inst->seqNum); + pcValid[tid] = false; + } else { + TheISA::PCState nextPC; + 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_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) { + 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); + 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); } - } else { - nextPC = inst->pcState(); - advancePC(nextPC, inst->staticInst); - } - DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %s.\n", - tid, nextPC); - pc[tid] = nextPC; + 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; - } + // 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; - } + pcValid[tid] = true; + } + } Resource::squash(inst, squash_stage, squash_seq_num, tid); } @@ -272,6 +280,17 @@ FetchSeqUnit::suspendThread(ThreadID 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 FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid) { diff --git a/src/cpu/inorder/resources/fetch_seq_unit.hh b/src/cpu/inorder/resources/fetch_seq_unit.hh index 7c57fa17b..1cd0047e2 100644 --- a/src/cpu/inorder/resources/fetch_seq_unit.hh +++ b/src/cpu/inorder/resources/fetch_seq_unit.hh @@ -65,15 +65,12 @@ class FetchSeqUnit : public Resource { void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid); - /** Override default Resource squash sequence. This actually, - * looks in the global communication buffer to get squash - * info - */ + /** Update to correct PC from a squash */ void squash(DynInstPtr inst, int squash_stage, - InstSeqNum squash_seq_num, ThreadID tid); + InstSeqNum squash_seq_num, ThreadID tid); - - inline void squashAfterInst(DynInstPtr inst, int stage_num, ThreadID tid); + /** Update to correct PC from a trap */ + void trap(Fault fault, ThreadID tid, DynInstPtr inst); protected: unsigned instSize; diff --git a/src/cpu/inorder/resources/fetch_unit.cc b/src/cpu/inorder/resources/fetch_unit.cc index 692f78c7b..60452bacd 100644 --- a/src/cpu/inorder/resources/fetch_unit.cc +++ b/src/cpu/inorder/resources/fetch_unit.cc @@ -111,6 +111,7 @@ FetchUnit::createMachInst(std::list::iterator fetch_it, predecoder.setTC(cpu->thread[tid]->getTC()); predecoder.moreBytes(instPC, inst->instAddr(), mach_inst); + assert(predecoder.extMachInstReady()); ext_inst = predecoder.getExtMachInst(instPC); inst->pcState(instPC); @@ -552,3 +553,9 @@ FetchUnit::squashCacheRequest(CacheReqPtr req_ptr) CacheUnit::squashCacheRequest(req_ptr); } +void +FetchUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst) +{ + //@todo: per thread? + predecoder.reset(); +} diff --git a/src/cpu/inorder/resources/fetch_unit.hh b/src/cpu/inorder/resources/fetch_unit.hh index 3075e726d..d6e36419a 100644 --- a/src/cpu/inorder/resources/fetch_unit.hh +++ b/src/cpu/inorder/resources/fetch_unit.hh @@ -88,6 +88,8 @@ class FetchUnit : public CacheUnit /** Executes one of the commands from the "Command" enum */ void execute(int slot_num); + void trap(Fault fault, ThreadID tid, DynInstPtr inst); + private: void squashCacheRequest(CacheReqPtr req_ptr); diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc index 826ed8e03..9c17db945 100644 --- a/src/cpu/inorder/resources/graduation_unit.cc +++ b/src/cpu/inorder/resources/graduation_unit.cc @@ -67,7 +67,14 @@ GraduationUnit::execute(int slot_num) // Handle Any Faults Before Graduating Instruction 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,