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 (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_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 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()) { + 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; + + // 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; + } + + 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]) { - 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; - } - - 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