summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKorey Sewell <ksewell@umich.edu>2011-06-19 21:43:40 -0400
committerKorey Sewell <ksewell@umich.edu>2011-06-19 21:43:40 -0400
commitf1c3691356355d2ca865e48e91814c56293f6326 (patch)
tree6608284d5bcdab42d69042034d49198c647b1a2c
parent0bfdf342da40842a05351d53a384db4a8ff88bf5 (diff)
downloadgem5-f1c3691356355d2ca865e48e91814c56293f6326.tar.xz
inorder: check for interrupts each tick
use a dummy instruction to facilitate the squash after the interrupts trap
-rw-r--r--src/cpu/inorder/cpu.cc49
-rw-r--r--src/cpu/inorder/cpu.hh3
-rw-r--r--src/cpu/inorder/pipeline_stage.cc7
-rw-r--r--src/cpu/inorder/resource.cc2
-rw-r--r--src/cpu/inorder/resources/cache_unit.cc3
-rw-r--r--src/cpu/inorder/resources/fetch_seq_unit.cc122
6 files changed, 122 insertions, 64 deletions
diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc
index 232bf8279..2623c6c1d 100644
--- a/src/cpu/inorder/cpu.cc
+++ b/src/cpu/inorder/cpu.cc
@@ -350,6 +350,16 @@ InOrderCPU::InOrderCPU(Params *params)
asid[tid]);
dummyReq[tid] = new ResourceRequest(resPool->getResource(0));
+
+#if FULL_SYSTEM
+ // Use this dummy inst to force squashing behind every instruction
+ // in pipeline
+ dummyTrapInst[tid] = new InOrderDynInst(this, NULL, 0, 0, 0);
+ dummyTrapInst[tid]->seqNum = 0;
+ dummyTrapInst[tid]->squashSeqNum = 0;
+ dummyTrapInst[tid]->setTid(tid);
+#endif
+
}
dummyReqInst = new InOrderDynInst(this, NULL, 0, 0, 0);
@@ -687,6 +697,8 @@ InOrderCPU::tick()
pipes_idle = pipes_idle && pipelineStage[stNum]->idle;
}
+ checkForInterrupts();
+
if (pipes_idle)
idleCycles++;
else
@@ -800,6 +812,43 @@ InOrderCPU::simPalCheck(int palFunc, ThreadID tid)
return true;
}
+void
+InOrderCPU::checkForInterrupts()
+{
+ for (int i = 0; i < threadContexts.size(); i++) {
+ ThreadContext *tc = threadContexts[i];
+
+ if (interrupts->checkInterrupts(tc)) {
+ Fault interrupt = interrupts->getInterrupt(tc);
+
+ if (interrupt != NoFault) {
+ DPRINTF(Interrupt, "Processing Intterupt for [tid:%i].\n",
+ tc->threadId());
+
+ ThreadID tid = tc->threadId();
+ interrupts->updateIntrInfo(tc);
+
+ // Squash from Last Stage in Pipeline
+ unsigned last_stage = NumStages - 1;
+ dummyTrapInst[tid]->squashingStage = last_stage;
+ pipelineStage[last_stage]->setupSquash(dummyTrapInst[tid],
+ tid);
+
+ // By default, setupSquash will always squash from stage + 1
+ pipelineStage[BackEndStartStage - 1]->setupSquash(dummyTrapInst[tid],
+ tid);
+
+ // Schedule Squash Through-out Resource Pool
+ resPool->scheduleEvent(
+ (InOrderCPU::CPUEventType)ResourcePool::SquashAll,
+ dummyTrapInst[tid], 0);
+
+ // Finally, Setup Trap to happen at end of cycle
+ trapContext(interrupt, tid, dummyTrapInst[tid]);
+ }
+ }
+ }
+}
Fault
InOrderCPU::getInterrupts()
diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh
index f6b7a4e95..8a0f2167b 100644
--- a/src/cpu/inorder/cpu.hh
+++ b/src/cpu/inorder/cpu.hh
@@ -253,6 +253,7 @@ class InOrderCPU : public BaseCPU
DynInstPtr dummyInst[ThePipeline::MaxThreads];
DynInstPtr dummyBufferInst;
DynInstPtr dummyReqInst;
+ DynInstPtr dummyTrapInst[ThePipeline::MaxThreads];
/** Used by resources to signify a denied access to a resource. */
ResourceRequest *dummyReq[ThePipeline::MaxThreads];
@@ -414,6 +415,8 @@ class InOrderCPU : public BaseCPU
bool simPalCheck(int palFunc, ThreadID tid);
+ void checkForInterrupts();
+
/** Returns the Fault for any valid interrupt. */
Fault getInterrupts();
diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc
index 80068ab8f..3c945d31c 100644
--- a/src/cpu/inorder/pipeline_stage.cc
+++ b/src/cpu/inorder/pipeline_stage.cc
@@ -364,9 +364,10 @@ PipelineStage::setupSquash(DynInstPtr inst, ThreadID tid)
toPrevStages->stageInfo[squash_stage][tid].doneSeqNum =
squash_seq_num;
- DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], "
- "due to [sn:%i] %s.\n", tid, squash_seq_num,
- inst->seqNum, inst->instName());
+ DPRINTF(InOrderStage, "[tid:%i]: Setting up squashing after "
+ "[sn:%i], due to [sn:%i] %s. Squash-Start-Stage:%i\n",
+ tid, squash_seq_num, inst->seqNum, inst->instName(),
+ squash_stage);
// Save squash num for later stage use
cpu->lastSquashCycle[tid] = curTick();
diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc
index 817cc5868..b7f6a8db6 100644
--- a/src/cpu/inorder/resource.cc
+++ b/src/cpu/inorder/resource.cc
@@ -302,6 +302,8 @@ void
Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
ThreadID tid)
{
+ //@todo: check squash seq num before squashing. can save time going
+ // through this function.
for (int i = 0; i < width; i++) {
ResReqPtr req_ptr = reqs[i];
DynInstPtr inst = req_ptr->getInst();
diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc
index d0cdfa3c9..d21597aba 100644
--- a/src/cpu/inorder/resources/cache_unit.cc
+++ b/src/cpu/inorder/resources/cache_unit.cc
@@ -1248,7 +1248,8 @@ void
CacheUnit::squash(DynInstPtr inst, int stage_num,
InstSeqNum squash_seq_num, ThreadID tid)
{
- if (tlbBlockSeqNum[tid] > squash_seq_num) {
+ if (tlbBlockSeqNum[tid] &&
+ tlbBlockSeqNum[tid] > squash_seq_num) {
DPRINTF(InOrderCachePort, "Releasing TLB Block due to "
" squash after [sn:%i].\n", squash_seq_num);
tlbBlocked[tid] = false;
diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc
index 8a55822a6..58e466e13 100644
--- a/src/cpu/inorder/resources/fetch_seq_unit.cc
+++ b/src/cpu/inorder/resources/fetch_seq_unit.cc
@@ -49,6 +49,8 @@ FetchSeqUnit::FetchSeqUnit(std::string res_name, int res_id, int res_width,
pcValid[tid] = false;
pcBlockStage[tid] = 0;
+ //@todo: Use CPU's squashSeqNum here instead of maintaining our own
+ // state
squashSeqNum[tid] = (InstSeqNum)-1;
lastSquashCycle[tid] = 0;
}
@@ -164,75 +166,77 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
squashSeqNum[tid] = squash_seq_num;
lastSquashCycle[tid] = curTick();
- 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].%s %s \n", inst->seqNum,
- inst->instName(), inst->pcState());
- 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 (inst->staticInst) {
+ 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].%s %s \n", inst->seqNum,
+ inst->instName(), inst->pcState());
+ 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()) {
- bdelay_inst->pc = nextPC;
- advancePC(nextPC, inst->staticInst);
- DPRINTF(Resource, "Advanced PC to %s\n", nextPC);
+ if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
+ bdelay_inst->pc = nextPC;
+ 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]) {
- DPRINTF(InOrderFetchSeq, "[tid:%d]: Setting unblock signal "
- "for stage %i.\n",
- tid, pcBlockStage[tid]);
+ // Unblock Any Stages Waiting for this information to be updated ...
+ if (!pcValid[tid]) {
+ DPRINTF(InOrderFetchSeq, "[tid:%d]: Setting unblock signal "
+ "for stage %i.\n",
+ tid, pcBlockStage[tid]);
+
+ // Need to use "fromNextStages" instead of "toPrevStages"
+ // because the timebuffer will have already have advanced
+ // in the tick function and this squash function will happen after
+ // the tick
+ cpu->pipelineStage[pcBlockStage[tid]]->
+ fromNextStages->stageUnblock[pcBlockStage[tid]][tid] = true;
+ }
- // Need to use "fromNextStages" instead of "toPrevStages"
- // because the timebuffer will have already have advanced
- // in the tick function and this squash function will happen after
- // the tick
- cpu->pipelineStage[pcBlockStage[tid]]->
- fromNextStages->stageUnblock[pcBlockStage[tid]][tid] = true;
+ pcValid[tid] = true;
}
-
- pcValid[tid] = true;
}
- }
+ }
Resource::squash(inst, squash_stage, squash_seq_num, tid);
}
@@ -302,8 +306,6 @@ FetchSeqUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
"%s.\n", tid, pc[tid]);
DPRINTF(InOrderFetchSeq, "[tid:%i]: Trap updating to PC: "
"%s.\n", tid, pc[tid]);
-
- cpu->removePipelineStalls(tid);
}
void