From 069b38c0d546708491d0da84668ba32f82ca7cb8 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Sun, 31 Jan 2010 18:27:58 -0500 Subject: [PATCH] inorder: track last branch committed when threads are switching in/out the CPU, we need to keep track of special cases like branches. Add appropriate variables in ThreadState t track this and then use these variables when updating pc after context switch --- src/cpu/inorder/cpu.cc | 27 +++++++++++++-------- src/cpu/inorder/pipeline_stage.cc | 9 ++++--- src/cpu/inorder/resources/fetch_seq_unit.cc | 26 ++++++++++++++------ src/cpu/inorder/thread_state.hh | 13 +++++++--- 4 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index 501150386..8d41a18b4 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -709,7 +709,9 @@ InOrderCPU::activateThread(ThreadID tid) activeThreads.push_back(tid); activateThreadInPipeline(tid); - + + thread[tid]->lastActivate = curTick; + wakeCPU(); } } @@ -888,6 +890,7 @@ InOrderCPU::suspendThread(ThreadID tid) DPRINTF(InOrderCPU, "[tid: %i]: Placing on Suspended Threads List...\n", tid); deactivateThread(tid); suspendedThreads.push_back(tid); + thread[tid]->lastSuspend = curTick; } void @@ -1063,15 +1066,22 @@ void InOrderCPU::instDone(DynInstPtr inst, ThreadID tid) { // Set the CPU's PCs - This contributes to the precise state of the CPU - // which can be used when restoring a thread to the CPU after a fork or - // after an exception - // ================= - // @TODO: Set-Up Grad-Info/Committed-Info to let ThreadState know if - // it's a branch or not + // which can be used when restoring a thread to the CPU after after any + // type of context switching activity (fork, exception, etc.) setPC(inst->readPC(), tid); setNextPC(inst->readNextPC(), tid); setNextNPC(inst->readNextNPC(), tid); + if (inst->isControl()) { + thread[tid]->lastGradIsBranch = true; + thread[tid]->lastBranchPC = inst->readPC(); + thread[tid]->lastBranchNextPC = inst->readNextPC(); + thread[tid]->lastBranchNextNPC = inst->readNextNPC(); + } else { + thread[tid]->lastGradIsBranch = false; + } + + // Finalize Trace Data For Instruction if (inst->traceData) { //inst->traceData->setCycle(curTick); @@ -1082,9 +1092,6 @@ InOrderCPU::instDone(DynInstPtr inst, ThreadID tid) inst->traceData = NULL; } - // Set Last Graduated Instruction In Thread State - //thread[tid]->lastGradInst = inst; - // Increment thread-state's instruction count thread[tid]->numInst++; @@ -1108,7 +1115,7 @@ InOrderCPU::instDone(DynInstPtr inst, ThreadID tid) // Broadcast to other resources an instruction // has been completed resPool->scheduleEvent((CPUEventType)ResourcePool::InstGraduated, inst, - tid); + 0, 0, tid); // Finally, remove instruction from CPU removeInst(inst); diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index 620951e34..55ee3ad12 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -568,15 +568,18 @@ PipelineStage::activateThread(ThreadID tid) } else { DynInstPtr inst = switchedOutBuffer[tid]; - DPRINTF(InOrderStage,"[tid:%i]: Re-Inserting [sn:%lli] PC:%#x into stage skidBuffer %i\n", - tid, inst->seqNum, inst->readPC(), inst->threadNumber); + DPRINTF(InOrderStage,"[tid:%i]: Re-Inserting [sn:%lli] PC:%#x into " + "stage skidBuffer %i\n", tid, inst->seqNum, + inst->readPC(), inst->threadNumber); // Make instruction available for pipeline processing skidBuffer[tid].push(inst); // Update PC so that we start fetching after this instruction to prevent // "double"-execution of instructions - cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::UpdateAfterContextSwitch, inst, 0, 0, tid); + cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType) + ResourcePool::UpdateAfterContextSwitch, + inst, 0, 0, tid); // Clear switchout buffer switchedOutBuffer[tid] = NULL; diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc index c217f972e..ba86a91f0 100644 --- a/src/cpu/inorder/resources/fetch_seq_unit.cc +++ b/src/cpu/inorder/resources/fetch_seq_unit.cc @@ -348,11 +348,23 @@ FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid) { pcValid[tid] = true; - PC[tid] = inst->readNextPC(); - nextPC[tid] = inst->readNextNPC(); - nextNPC[tid] = inst->readNextNPC() + instSize; - - - DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating PC:%08p NPC:%08p NNPC:%08p.\n", - tid, PC[tid], nextPC[tid], nextNPC[tid]); + if (cpu->thread[tid]->lastGradIsBranch) { + /** This function assumes that the instruction causing the context + * switch was right after the branch. Thus, if it's not, then + * we are updating incorrectly here + */ + assert(cpu->thread[tid]->lastBranchNextPC == inst->readPC()); + + PC[tid] = cpu->thread[tid]->lastBranchNextNPC; + nextPC[tid] = PC[tid] + instSize; + nextNPC[tid] = nextPC[tid] + instSize; + } else { + PC[tid] = inst->readNextPC(); + nextPC[tid] = inst->readNextNPC(); + nextNPC[tid] = inst->readNextNPC() + instSize; + } + + DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating PCs due to Context Switch." + "Assigning PC:%08p NPC:%08p NNPC:%08p.\n", tid, PC[tid], + nextPC[tid], nextNPC[tid]); } diff --git a/src/cpu/inorder/thread_state.hh b/src/cpu/inorder/thread_state.hh index 422df30aa..0a171a99f 100644 --- a/src/cpu/inorder/thread_state.hh +++ b/src/cpu/inorder/thread_state.hh @@ -79,14 +79,14 @@ class InOrderThreadState : public ThreadState { #if FULL_SYSTEM InOrderThreadState(InOrderCPU *_cpu, ThreadID _thread_num) : ThreadState(reinterpret_cast(_cpu), _thread_num), - cpu(_cpu), inSyscall(0), trapPending(0) + cpu(_cpu), inSyscall(0), trapPending(0), lastGradIsBranch(false) { } #else InOrderThreadState(InOrderCPU *_cpu, ThreadID _thread_num, Process *_process) : ThreadState(reinterpret_cast(_cpu), _thread_num, _process), - cpu(_cpu), inSyscall(0), trapPending(0) + cpu(_cpu), inSyscall(0), trapPending(0), lastGradIsBranch(false) { } #endif @@ -105,10 +105,15 @@ class InOrderThreadState : public ThreadState { /** Returns a pointer to the TC of this thread. */ ThreadContext *getTC() { return tc; } + /** Return the thread id */ int readTid() { return threadId(); } - /** Pointer to the last graduated instruction in the thread */ - //DynInstPtr lastGradInst; + + /** Is last instruction graduated a branch? */ + bool lastGradIsBranch; + Addr lastBranchPC; + Addr lastBranchNextPC; + Addr lastBranchNextNPC; }; #endif // __CPU_INORDER_THREAD_STATE_HH__