# HG changeset patch
# User Korey Sewell <[email protected]>
# Date 1254427253 14400
# Node ID bfed5a5a12278f9dff5feee73ae28052b11f52af
# Parent 15a99db60a81fdd86c7ff5611c1031c92839ee56
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
diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc
--- a/src/cpu/inorder/cpu.cc
+++ b/src/cpu/inorder/cpu.cc
@@ -690,7 +690,9 @@
activeThreads.push_back(tid);
activateThreadInPipeline(tid);
-
+
+ thread[tid]->lastActivate = curTick;
+
wakeCPU();
}
}
@@ -869,6 +871,7 @@
DPRINTF(InOrderCPU, "[tid: %i]: Placing on Suspended Threads List...\n",
tid);
deactivateThread(tid);
suspendedThreads.push_back(tid);
+ thread[tid]->lastSuspend = curTick;
}
void
@@ -1041,13 +1044,24 @@
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
+ // 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 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);
@@ -1058,9 +1072,6 @@
inst->traceData = NULL;
}
- // Set Last Graduated Instruction In Thread State
- //thread[tid]->lastGradInst = inst;
-
// Increment thread-state's instruction count
thread[tid]->numInst++;
@@ -1083,7 +1094,8 @@
// Broadcast to other resources an instruction
// has been completed
- resPool->scheduleEvent((CPUEventType)ResourcePool::InstGraduated, inst,
tid);
+ resPool->scheduleEvent((CPUEventType)ResourcePool::InstGraduated, inst,
+ 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
--- a/src/cpu/inorder/pipeline_stage.cc
+++ b/src/cpu/inorder/pipeline_stage.cc
@@ -551,15 +551,18 @@
} 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
--- a/src/cpu/inorder/resources/fetch_seq_unit.cc
+++ b/src/cpu/inorder/resources/fetch_seq_unit.cc
@@ -347,11 +347,23 @@
{
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
--- a/src/cpu/inorder/thread_state.hh
+++ b/src/cpu/inorder/thread_state.hh
@@ -79,14 +79,14 @@
#if FULL_SYSTEM
InOrderThreadState(InOrderCPU *_cpu, ThreadID _thread_num)
: ThreadState(reinterpret_cast<BaseCPU*>(_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<BaseCPU*>(_cpu), _thread_num,
_process),
- cpu(_cpu), inSyscall(0), trapPending(0)
+ cpu(_cpu), inSyscall(0), trapPending(0), lastGradIsBranch(false)
{ }
#endif
@@ -105,10 +105,15 @@
/** 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__
_______________________________________________
m5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/m5-dev