diff options
Diffstat (limited to 'src/cpu')
35 files changed, 889 insertions, 673 deletions
diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index 0c566ec65..8b6662d70 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2006 The Regents of The University of Michigan * Copyright (c) 2009 The University of Edinburgh * All rights reserved. @@ -150,6 +162,29 @@ class BaseDynInst : public FastAlloc, public RefCounted /** Finish a DTB address translation. */ void finishTranslation(WholeTranslationState *state); + /** True if the DTB address translation has started. */ + bool translationStarted; + + /** True if the DTB address translation has completed. */ + bool translationCompleted; + + /** + * Returns true if the DTB address translation is being delayed due to a hw + * page table walk. + */ + bool isTranslationDelayed() const + { + return (translationStarted && !translationCompleted); + } + + /** + * Saved memory requests (needed when the DTB address translation is + * delayed due to a hw page table walk). + */ + RequestPtr savedReq; + RequestPtr savedSreqLow; + RequestPtr savedSreqHigh; + /** @todo: Consider making this private. */ public: /** The sequence number of the instruction. */ @@ -835,33 +870,42 @@ BaseDynInst<Impl>::readBytes(Addr addr, uint8_t *data, unsigned size, unsigned flags) { reqMade = true; - Request *req = new Request(asid, addr, size, flags, this->pc.instAddr(), - thread->contextId(), threadNumber); - + Request *req = NULL; Request *sreqLow = NULL; Request *sreqHigh = NULL; - // Only split the request if the ISA supports unaligned accesses. - if (TheISA::HasUnalignedMemAcc) { - splitRequest(req, sreqLow, sreqHigh); - } - initiateTranslation(req, sreqLow, sreqHigh, NULL, BaseTLB::Read); - - if (fault == NoFault) { - effAddr = req->getVaddr(); - effAddrValid = true; - fault = cpu->read(req, sreqLow, sreqHigh, data, lqIdx); + if (reqMade && translationStarted) { + req = savedReq; + sreqLow = savedSreqLow; + sreqHigh = savedSreqHigh; } else { - // Commit will have to clean up whatever happened. Set this - // instruction as executed. - this->setExecuted(); + req = new Request(asid, addr, size, flags, this->pc.instAddr(), + thread->contextId(), threadNumber); + + // Only split the request if the ISA supports unaligned accesses. + if (TheISA::HasUnalignedMemAcc) { + splitRequest(req, sreqLow, sreqHigh); + } + initiateTranslation(req, sreqLow, sreqHigh, NULL, BaseTLB::Read); } - if (fault != NoFault) { - // Return a fixed value to keep simulation deterministic even - // along misspeculated paths. - if (data) - bzero(data, size); + if (translationCompleted) { + if (fault == NoFault) { + effAddr = req->getVaddr(); + effAddrValid = true; + fault = cpu->read(req, sreqLow, sreqHigh, data, lqIdx); + } else { + // Commit will have to clean up whatever happened. Set this + // instruction as executed. + this->setExecuted(); + } + + if (fault != NoFault) { + // Return a fixed value to keep simulation deterministic even + // along misspeculated paths. + if (data) + bzero(data, size); + } } if (traceData) { @@ -897,19 +941,26 @@ BaseDynInst<Impl>::writeBytes(uint8_t *data, unsigned size, } reqMade = true; - Request *req = new Request(asid, addr, size, flags, this->pc.instAddr(), - thread->contextId(), threadNumber); - + Request *req = NULL; Request *sreqLow = NULL; Request *sreqHigh = NULL; - // Only split the request if the ISA supports unaligned accesses. - if (TheISA::HasUnalignedMemAcc) { - splitRequest(req, sreqLow, sreqHigh); + if (reqMade && translationStarted) { + req = savedReq; + sreqLow = savedSreqLow; + sreqHigh = savedSreqHigh; + } else { + req = new Request(asid, addr, size, flags, this->pc.instAddr(), + thread->contextId(), threadNumber); + + // Only split the request if the ISA supports unaligned accesses. + if (TheISA::HasUnalignedMemAcc) { + splitRequest(req, sreqLow, sreqHigh); + } + initiateTranslation(req, sreqLow, sreqHigh, res, BaseTLB::Write); } - initiateTranslation(req, sreqLow, sreqHigh, res, BaseTLB::Write); - if (fault == NoFault) { + if (fault == NoFault && translationCompleted) { effAddr = req->getVaddr(); effAddrValid = true; fault = cpu->write(req, sreqLow, sreqHigh, data, sqIdx); @@ -953,6 +1004,8 @@ BaseDynInst<Impl>::initiateTranslation(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh, uint64_t *res, BaseTLB::Mode mode) { + translationStarted = true; + if (!TheISA::HasUnalignedMemAcc || sreqLow == NULL) { WholeTranslationState *state = new WholeTranslationState(req, NULL, res, mode); @@ -961,6 +1014,12 @@ BaseDynInst<Impl>::initiateTranslation(RequestPtr req, RequestPtr sreqLow, DataTranslation<BaseDynInst<Impl> > *trans = new DataTranslation<BaseDynInst<Impl> >(this, state); cpu->dtb->translateTiming(req, thread->getTC(), trans, mode); + if (!translationCompleted) { + // Save memory requests. + savedReq = state->mainReq; + savedSreqLow = state->sreqLow; + savedSreqHigh = state->sreqHigh; + } } else { WholeTranslationState *state = new WholeTranslationState(req, sreqLow, sreqHigh, NULL, res, mode); @@ -973,6 +1032,12 @@ BaseDynInst<Impl>::initiateTranslation(RequestPtr req, RequestPtr sreqLow, cpu->dtb->translateTiming(sreqLow, thread->getTC(), stransLow, mode); cpu->dtb->translateTiming(sreqHigh, thread->getTC(), stransHigh, mode); + if (!translationCompleted) { + // Save memory requests. + savedReq = state->mainReq; + savedSreqLow = state->sreqLow; + savedSreqHigh = state->sreqHigh; + } } } @@ -998,6 +1063,8 @@ BaseDynInst<Impl>::finishTranslation(WholeTranslationState *state) state->deleteReqs(); } delete state; + + translationCompleted = true; } #endif // __CPU_BASE_DYN_INST_HH__ diff --git a/src/cpu/base_dyn_inst_impl.hh b/src/cpu/base_dyn_inst_impl.hh index 74f199d5f..7e4d25322 100644 --- a/src/cpu/base_dyn_inst_impl.hh +++ b/src/cpu/base_dyn_inst_impl.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * @@ -107,6 +119,9 @@ BaseDynInst<Impl>::initVars() effAddrValid = false; physEffAddr = 0; + translationStarted = false; + translationCompleted = false; + isUncacheable = false; reqMade = false; readyRegs = 0; diff --git a/src/cpu/inorder/SConscript b/src/cpu/inorder/SConscript index ae5ec0257..b9c526763 100644 --- a/src/cpu/inorder/SConscript +++ b/src/cpu/inorder/SConscript @@ -55,7 +55,7 @@ if 'InOrderCPU' in env['CPU_MODELS']: TraceFlag('ThreadModel') TraceFlag('RefCount') TraceFlag('AddrDep') - + TraceFlag('SkedCache') CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU', 'InOrderMDU', 'InOrderAGEN', 'InOrderFetchSeq', 'InOrderTLB', 'InOrderBPred', @@ -63,7 +63,6 @@ if 'InOrderCPU' in env['CPU_MODELS']: 'InOrderGraduation', 'InOrderCachePort', 'RegDepMap', 'Resource', 'ThreadModel', 'AddrDep']) - Source('pipeline_traits.cc') Source('inorder_dyn_inst.cc') Source('inorder_cpu_builder.cc') Source('inorder_trace.cc') diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index ffdcae7df..3a705258d 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -334,9 +334,14 @@ InOrderCPU::InOrderCPU(Params *params) dummyReqInst = new InOrderDynInst(this, NULL, 0, 0, 0); dummyReqInst->setSquashed(); + dummyReqInst->resetInstCount(); dummyBufferInst = new InOrderDynInst(this, NULL, 0, 0, 0); dummyBufferInst->setSquashed(); + dummyBufferInst->resetInstCount(); + + endOfSkedIt = skedCache.end(); + frontEndSked = createFrontEndSked(); lastRunningCycle = curTick(); @@ -348,7 +353,6 @@ InOrderCPU::InOrderCPU(Params *params) reset(); #endif - dummyBufferInst->resetInstCount(); // Schedule First Tick Event, CPU will reschedule itself from here on out. scheduleTickEvent(0); @@ -359,6 +363,118 @@ InOrderCPU::~InOrderCPU() delete resPool; } +std::map<InOrderCPU::SkedID, ThePipeline::RSkedPtr> InOrderCPU::skedCache; + +RSkedPtr +InOrderCPU::createFrontEndSked() +{ + RSkedPtr res_sked = new ResourceSked(); + int stage_num = 0; + StageScheduler F(res_sked, stage_num++); + StageScheduler D(res_sked, stage_num++); + + // FETCH + F.needs(FetchSeq, FetchSeqUnit::AssignNextPC); + F.needs(ICache, FetchUnit::InitiateFetch); + + // DECODE + D.needs(ICache, FetchUnit::CompleteFetch); + D.needs(Decode, DecodeUnit::DecodeInst); + D.needs(BPred, BranchPredictor::PredictBranch); + D.needs(FetchSeq, FetchSeqUnit::UpdateTargetPC); + + + DPRINTF(SkedCache, "Resource Sked created for instruction \"front_end\"\n"); + + return res_sked; +} + +RSkedPtr +InOrderCPU::createBackEndSked(DynInstPtr inst) +{ + RSkedPtr res_sked = lookupSked(inst); + if (res_sked != NULL) { + DPRINTF(SkedCache, "Found %s in sked cache.\n", + inst->instName()); + return res_sked; + } else { + res_sked = new ResourceSked(); + } + + int stage_num = ThePipeline::BackEndStartStage; + StageScheduler X(res_sked, stage_num++); + StageScheduler M(res_sked, stage_num++); + StageScheduler W(res_sked, stage_num++); + + if (!inst->staticInst) { + warn_once("Static Instruction Object Not Set. Can't Create" + " Back End Schedule"); + return NULL; + } + + // EXECUTE + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + if (!idx || !inst->isStore()) { + X.needs(RegManager, UseDefUnit::ReadSrcReg, idx); + } + } + + if ( inst->isNonSpeculative() ) { + // skip execution of non speculative insts until later + } else if ( inst->isMemRef() ) { + if ( inst->isLoad() ) { + X.needs(AGEN, AGENUnit::GenerateAddr); + } + } else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + X.needs(MDU, MultDivUnit::StartMultDiv); + } else { + X.needs(ExecUnit, ExecutionUnit::ExecuteInst); + } + + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + X.needs(MDU, MultDivUnit::EndMultDiv); + } + + // MEMORY + if ( inst->isLoad() ) { + M.needs(DCache, CacheUnit::InitiateReadData); + } else if ( inst->isStore() ) { + if ( inst->numSrcRegs() >= 2 ) { + M.needs(RegManager, UseDefUnit::ReadSrcReg, 1); + } + M.needs(AGEN, AGENUnit::GenerateAddr); + M.needs(DCache, CacheUnit::InitiateWriteData); + } + + + // WRITEBACK + if ( inst->isLoad() ) { + W.needs(DCache, CacheUnit::CompleteReadData); + } else if ( inst->isStore() ) { + W.needs(DCache, CacheUnit::CompleteWriteData); + } + + if ( inst->isNonSpeculative() ) { + if ( inst->isMemRef() ) fatal("Non-Speculative Memory Instruction"); + W.needs(ExecUnit, ExecutionUnit::ExecuteInst); + } + + for (int idx=0; idx < inst->numDestRegs(); idx++) { + W.needs(RegManager, UseDefUnit::WriteDestReg, idx); + } + + W.needs(Grad, GraduationUnit::GraduateInst); + + // Insert Front Schedule into our cache of + // resource schedules + addToSkedCache(inst, res_sked); + + DPRINTF(SkedCache, "Back End Sked Created for instruction: %s (%08p)\n", + inst->instName(), inst->getMachInst()); + res_sked->print(); + + return res_sked; +} void InOrderCPU::regStats() @@ -1299,14 +1415,6 @@ InOrderCPU::cleanUpRemovedInsts() DynInstPtr inst = *removeList.front(); ThreadID tid = inst->threadNumber; - // Make Sure Resource Schedule Is Emptied Out - ThePipeline::ResSchedule *inst_sched = &inst->resSched; - while (!inst_sched->empty()) { - ScheduleEntry* sch_entry = inst_sched->top(); - inst_sched->pop(); - delete sch_entry; - } - // Remove From Register Dependency Map, If Necessary archRegDepMap[(*removeList.front())->threadNumber]. remove((*removeList.front())); @@ -1314,8 +1422,8 @@ InOrderCPU::cleanUpRemovedInsts() // Clear if Non-Speculative if (inst->staticInst && - inst->seqNum == nonSpecSeqNum[tid] && - nonSpecInstActive[tid] == true) { + inst->seqNum == nonSpecSeqNum[tid] && + nonSpecInstActive[tid] == true) { nonSpecInstActive[tid] = false; } diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index 9ff0f12ce..2a5c815e1 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -296,6 +296,91 @@ class InOrderCPU : public BaseCPU TheISA::TLB *getITBPtr(); TheISA::TLB *getDTBPtr(); + /** Accessor Type for the SkedCache */ + typedef uint32_t SkedID; + + /** Cache of Instruction Schedule using the instruction's name as a key */ + static std::map<SkedID, ThePipeline::RSkedPtr> skedCache; + + typedef std::map<SkedID, ThePipeline::RSkedPtr>::iterator SkedCacheIt; + + /** Initialized to last iterator in map, signifying a invalid entry + on map searches + */ + SkedCacheIt endOfSkedIt; + + ThePipeline::RSkedPtr frontEndSked; + + /** Add a new instruction schedule to the schedule cache */ + void addToSkedCache(DynInstPtr inst, ThePipeline::RSkedPtr inst_sked) + { + SkedID sked_id = genSkedID(inst); + skedCache[sked_id] = inst_sked; + } + + + /** Find a instruction schedule */ + ThePipeline::RSkedPtr lookupSked(DynInstPtr inst) + { + SkedID sked_id = genSkedID(inst); + SkedCacheIt lookup_it = skedCache.find(sked_id); + + if (lookup_it != endOfSkedIt) { + return (*lookup_it).second; + } else { + return NULL; + } + } + + static const uint8_t INST_OPCLASS = 26; + static const uint8_t INST_LOAD = 25; + static const uint8_t INST_STORE = 24; + static const uint8_t INST_CONTROL = 23; + static const uint8_t INST_NONSPEC = 22; + static const uint8_t INST_DEST_REGS = 18; + static const uint8_t INST_SRC_REGS = 14; + + inline SkedID genSkedID(DynInstPtr inst) + { + SkedID id = 0; + id = (inst->opClass() << INST_OPCLASS) | + (inst->isLoad() << INST_LOAD) | + (inst->isStore() << INST_STORE) | + (inst->isControl() << INST_CONTROL) | + (inst->isNonSpeculative() << INST_NONSPEC) | + (inst->numDestRegs() << INST_DEST_REGS) | + (inst->numSrcRegs() << INST_SRC_REGS); + return id; + } + + ThePipeline::RSkedPtr createFrontEndSked(); + ThePipeline::RSkedPtr createBackEndSked(DynInstPtr inst); + + class StageScheduler { + private: + ThePipeline::RSkedPtr rsked; + int stageNum; + int nextTaskPriority; + + public: + StageScheduler(ThePipeline::RSkedPtr _rsked, int stage_num) + : rsked(_rsked), stageNum(stage_num), + nextTaskPriority(0) + { } + + void needs(int unit, int request) { + rsked->push(new ScheduleEntry( + stageNum, nextTaskPriority++, unit, request + )); + } + + void needs(int unit, int request, int param) { + rsked->push(new ScheduleEntry( + stageNum, nextTaskPriority++, unit, request, param + )); + } + }; + public: /** Registers statistics. */ diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc index 71c6ec3e0..b656ca1c7 100644 --- a/src/cpu/inorder/first_stage.cc +++ b/src/cpu/inorder/first_stage.cc @@ -181,7 +181,7 @@ FirstStage::processInsts(ThreadID tid) inst->setInstListIt(cpu->addInst(inst)); // Create Front-End Resource Schedule For Instruction - ThePipeline::createFrontEndSchedule(inst); + inst->setFrontSked(cpu->frontEndSked); } int reqs_processed = 0; diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc index 6afe35862..e9deb7625 100644 --- a/src/cpu/inorder/inorder_dyn_inst.cc +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -51,7 +51,7 @@ InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst, const TheISA::PCState &instPC, const TheISA::PCState &_predPC, InstSeqNum seq_num, InOrderCPU *cpu) - : staticInst(machInst, instPC.instAddr()), traceData(NULL), cpu(cpu) + : staticInst(machInst, instPC.instAddr()), traceData(NULL), cpu(cpu) { seqNum = seq_num; @@ -108,6 +108,8 @@ InOrderDynInst::setMachInst(ExtMachInst machInst) void InOrderDynInst::initVars() { + inFrontEnd = true; + fetchMemReq = NULL; dataMemReq = NULL; splitMemData = NULL; @@ -123,7 +125,6 @@ InOrderDynInst::initVars() readyRegs = 0; nextStage = 0; - nextInstStageNum = 0; for(int i = 0; i < MaxInstDestRegs; i++) instResult[i].val.integer = 0; @@ -206,8 +207,6 @@ InOrderDynInst::~InOrderDynInst() --instcount; - deleteStages(); - DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed" " (active insts: %i)\n", threadNumber, seqNum, instcount); } @@ -282,29 +281,6 @@ InOrderDynInst::completeAcc(Packet *pkt) return this->fault; } -InstStage *InOrderDynInst::addStage() -{ - this->currentInstStage = new InstStage(this, nextInstStageNum++); - instStageList.push_back( this->currentInstStage ); - return this->currentInstStage; -} - -InstStage *InOrderDynInst::addStage(int stage_num) -{ - nextInstStageNum = stage_num; - return InOrderDynInst::addStage(); -} - -void InOrderDynInst::deleteStages() { - std::list<InstStage*>::iterator list_it = instStageList.begin(); - std::list<InstStage*>::iterator list_end = instStageList.end(); - - while(list_it != list_end) { - delete *list_it; - list_it++; - } -} - Fault InOrderDynInst::memAccess() { diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh index 1c0ee4384..0e6be3da2 100644 --- a/src/cpu/inorder/inorder_dyn_inst.hh +++ b/src/cpu/inorder/inorder_dyn_inst.hh @@ -210,9 +210,6 @@ class InOrderDynInst : public FastAlloc, public RefCounted /** Data used for a store for operation. */ uint64_t storeData; - /** The resource schedule for this inst */ - ThePipeline::ResSchedule resSched; - /** List of active resource requests for this instruction */ std::list<ResourceRequest*> reqList; @@ -304,11 +301,6 @@ class InOrderDynInst : public FastAlloc, public RefCounted int nextStage; - /* vars to keep track of InstStage's - used for resource sched defn */ - int nextInstStageNum; - ThePipeline::InstStage *currentInstStage; - std::list<ThePipeline::InstStage*> instStageList; - private: /** Function to initialize variables in the constructors. */ void initVars(); @@ -337,9 +329,10 @@ class InOrderDynInst : public FastAlloc, public RefCounted //////////////////////////////////////////////////////////// std::string instName() { return staticInst->getName(); } - void setMachInst(ExtMachInst inst); + ExtMachInst getMachInst() { return staticInst->machInst; } + /** Sets the StaticInst. */ void setStaticInst(StaticInstPtr &static_inst); @@ -411,68 +404,88 @@ class InOrderDynInst : public FastAlloc, public RefCounted // RESOURCE SCHEDULING // ///////////////////////////////////////////// + typedef ThePipeline::RSkedPtr RSkedPtr; + bool inFrontEnd; - void setNextStage(int stage_num) { nextStage = stage_num; } - int getNextStage() { return nextStage; } + RSkedPtr frontSked; + RSkedIt frontSked_end; + + RSkedPtr backSked; + RSkedIt backSked_end; - ThePipeline::InstStage *addStage(); - ThePipeline::InstStage *addStage(int stage); - ThePipeline::InstStage *currentStage() { return currentInstStage; } - void deleteStages(); + RSkedIt curSkedEntry; + + void setFrontSked(RSkedPtr front_sked) + { + frontSked = front_sked; + frontSked_end.init(frontSked); + frontSked_end = frontSked->end(); + //DPRINTF(InOrderDynInst, "Set FrontSked End to : %x \n" , + // frontSked_end.getIt()/*, frontSked->end()*/); + //assert(frontSked_end == frontSked->end()); + + // This initializes instruction to be able + // to walk the resource schedule + curSkedEntry.init(frontSked); + curSkedEntry = frontSked->begin(); + } - /** Add A Entry To Reource Schedule */ - void addToSched(ScheduleEntry* sched_entry) - { resSched.push(sched_entry); } + void setBackSked(RSkedPtr back_sked) + { + backSked = back_sked; + backSked_end.init(backSked); + backSked_end = backSked->end(); + } + void setNextStage(int stage_num) { nextStage = stage_num; } + int getNextStage() { return nextStage; } /** Print Resource Schedule */ - /** @NOTE: DEBUG ONLY */ - void printSched() + void printSked() { - ThePipeline::ResSchedule tempSched; - std::cerr << "\tInst. Res. Schedule: "; - while (!resSched.empty()) { - std::cerr << '\t' << resSched.top()->stageNum << "-" - << resSched.top()->resNum << ", "; - - tempSched.push(resSched.top()); - resSched.pop(); + if (frontSked != NULL) { + frontSked->print(); } - std::cerr << std::endl; - resSched = tempSched; + if (backSked != NULL) { + backSked->print(); + } } /** Return Next Resource Stage To Be Used */ int nextResStage() { - if (resSched.empty()) - return -1; - else - return resSched.top()->stageNum; + assert((inFrontEnd && curSkedEntry != frontSked_end) || + (!inFrontEnd && curSkedEntry != backSked_end)); + + return curSkedEntry->stageNum; } /** Return Next Resource To Be Used */ int nextResource() { - if (resSched.empty()) - return -1; - else - return resSched.top()->resNum; + assert((inFrontEnd && curSkedEntry != frontSked_end) || + (!inFrontEnd && curSkedEntry != backSked_end)); + + return curSkedEntry->resNum; } - /** Remove & Deallocate a schedule entry */ - void popSchedEntry() + /** Finish using a schedule entry, increment to next entry */ + bool finishSkedEntry() { - if (!resSched.empty()) { - ScheduleEntry* sked = resSched.top(); - resSched.pop(); - if (sked != 0) { - delete sked; - - } + curSkedEntry++; + + if (inFrontEnd && curSkedEntry == frontSked_end) { + assert(backSked != NULL); + curSkedEntry.init(backSked); + curSkedEntry = backSked->begin(); + inFrontEnd = false; + } else if (!inFrontEnd && curSkedEntry == backSked_end) { + return true; } + + return false; } /** Release a Resource Request (Currently Unused) */ diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index 744ffd4d2..bc31a8537 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -944,11 +944,16 @@ PipelineStage::processInstSchedule(DynInstPtr inst,int &reqs_processed) "completed.\n", tid, inst->seqNum, cpu->resPool->name(res_num)); - inst->popSchedEntry(); - reqs_processed++; req->stagePasses++; + + bool done_in_pipeline = inst->finishSkedEntry(); + if (done_in_pipeline) { + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] finished " + "in pipeline.\n", tid, inst->seqNum); + break; + } } else { DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed." "\n", tid, inst->seqNum, cpu->resPool->name(res_num)); @@ -982,7 +987,7 @@ PipelineStage::processInstSchedule(DynInstPtr inst,int &reqs_processed) // Activate Next Ready Thread at end of cycle DPRINTF(ThreadModel, "Attempting to activate next ready " "thread due to cache miss.\n"); - cpu->activateNextReadyContext(); + cpu->activateNextReadyContext(); } // Mark request for deletion diff --git a/src/cpu/inorder/pipeline_traits.cc b/src/cpu/inorder/pipeline_traits.cc deleted file mode 100644 index a6fad68f7..000000000 --- a/src/cpu/inorder/pipeline_traits.cc +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2007 MIPS Technologies, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Korey Sewell - * - */ - -#include "cpu/inorder/pipeline_traits.hh" -#include "cpu/inorder/inorder_dyn_inst.hh" -#include "cpu/inorder/resources/resource_list.hh" - -using namespace std; - -namespace ThePipeline { - -//@TODO: create my own Instruction Schedule Class -//that operates as a Priority QUEUE -int getNextPriority(DynInstPtr &inst, int stage_num) -{ - int cur_pri = 20; - - /* - std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, - entryCompare>::iterator sked_it = inst->resSched.begin(); - - std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, - entryCompare>::iterator sked_end = inst->resSched.end(); - - while (sked_it != sked_end) { - - if (sked_it.top()->stageNum == stage_num) { - cur_pri = sked_it.top()->priority; - } - - sked_it++; - } - */ - - return cur_pri; -} - -void createFrontEndSchedule(DynInstPtr &inst) -{ - InstStage *F = inst->addStage(); - InstStage *D = inst->addStage(); - - // FETCH - F->needs(FetchSeq, FetchSeqUnit::AssignNextPC); - F->needs(ICache, FetchUnit::InitiateFetch); - - // DECODE - D->needs(ICache, FetchUnit::CompleteFetch); - D->needs(Decode, DecodeUnit::DecodeInst); - D->needs(BPred, BranchPredictor::PredictBranch); - D->needs(FetchSeq, FetchSeqUnit::UpdateTargetPC); - - inst->resSched.init(); -} - -bool createBackEndSchedule(DynInstPtr &inst) -{ - if (!inst->staticInst) { - return false; - } - - InstStage *X = inst->addStage(); - InstStage *M = inst->addStage(); - InstStage *W = inst->addStage(); - - // EXECUTE - for (int idx=0; idx < inst->numSrcRegs(); idx++) { - if (!idx || !inst->isStore()) { - X->needs(RegManager, UseDefUnit::ReadSrcReg, idx); - } - } - - if ( inst->isNonSpeculative() ) { - // skip execution of non speculative insts until later - } else if ( inst->isMemRef() ) { - if ( inst->isLoad() ) { - X->needs(AGEN, AGENUnit::GenerateAddr); - } - } else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { - X->needs(MDU, MultDivUnit::StartMultDiv); - } else { - X->needs(ExecUnit, ExecutionUnit::ExecuteInst); - } - - if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { - X->needs(MDU, MultDivUnit::EndMultDiv); - } - - // MEMORY - if ( inst->isLoad() ) { - M->needs(DCache, CacheUnit::InitiateReadData); - } else if ( inst->isStore() ) { - if ( inst->numSrcRegs() >= 2 ) { - M->needs(RegManager, UseDefUnit::ReadSrcReg, 1); - } - M->needs(AGEN, AGENUnit::GenerateAddr); - M->needs(DCache, CacheUnit::InitiateWriteData); - } - - - // WRITEBACK - if ( inst->isLoad() ) { - W->needs(DCache, CacheUnit::CompleteReadData); - } else if ( inst->isStore() ) { - W->needs(DCache, CacheUnit::CompleteWriteData); - } - - if ( inst->isNonSpeculative() ) { - if ( inst->isMemRef() ) fatal("Non-Speculative Memory Instruction"); - W->needs(ExecUnit, ExecutionUnit::ExecuteInst); - } - - for (int idx=0; idx < inst->numDestRegs(); idx++) { - W->needs(RegManager, UseDefUnit::WriteDestReg, idx); - } - - W->needs(Grad, GraduationUnit::GraduateInst); - - return true; -} - -InstStage::InstStage(DynInstPtr inst, int stage_num) -{ - stageNum = stage_num; - nextTaskPriority = 0; - instSched = &inst->resSched; -} - -void -InstStage::needs(int unit, int request) { - instSched->push( new ScheduleEntry( - stageNum, nextTaskPriority++, unit, request - )); -} - -void -InstStage::needs(int unit, int request, int param) { - instSched->push( new ScheduleEntry( - stageNum, nextTaskPriority++, unit, request, param - )); -} - -}; diff --git a/src/cpu/inorder/pipeline_traits.hh b/src/cpu/inorder/pipeline_traits.hh index df964e254..75f01adb1 100644 --- a/src/cpu/inorder/pipeline_traits.hh +++ b/src/cpu/inorder/pipeline_traits.hh @@ -77,23 +77,7 @@ namespace ThePipeline { // RESOURCE SCHEDULING ////////////////////////// typedef ResourceSked ResSchedule; - - void createFrontEndSchedule(DynInstPtr &inst); - bool createBackEndSchedule(DynInstPtr &inst); - int getNextPriority(DynInstPtr &inst, int stage_num); - - class InstStage { - private: - int nextTaskPriority; - int stageNum; - ResSchedule *instSched; - - public: - InstStage(DynInstPtr inst, int stage_num); - - void needs(int unit, int request); - void needs(int unit, int request, int param); - }; + typedef ResourceSked* RSkedPtr; }; diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc index 51beb5aa0..72b45dda8 100644 --- a/src/cpu/inorder/resource.cc +++ b/src/cpu/inorder/resource.cc @@ -184,8 +184,8 @@ Resource::request(DynInstPtr inst) if (slot_num != -1) { // Get Stage # from Schedule Entry - stage_num = inst->resSched.top()->stageNum; - unsigned cmd = inst->resSched.top()->cmd; + stage_num = inst->curSkedEntry->stageNum; + unsigned cmd = inst->curSkedEntry->cmd; // Generate Resource Request inst_req = getRequest(inst, stage_num, id, slot_num, cmd); diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc index a037cbe9e..e1914623a 100644 --- a/src/cpu/inorder/resource_pool.cc +++ b/src/cpu/inorder/resource_pool.cc @@ -91,6 +91,7 @@ ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params) resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4, 0, _cpu, params)); + } ResourcePool::~ResourcePool() @@ -122,6 +123,16 @@ ResourcePool::name() return cpu->name() + ".ResourcePool"; } +void +ResourcePool::print() +{ + for (int i=0; i < resources.size(); i++) { + DPRINTF(InOrderDynInst, "Res:%i %s\n", + i, resources[i]->name()); + } + +} + void ResourcePool::regStats() diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh index e8061d3ff..fde38b4e9 100644 --- a/src/cpu/inorder/resource_pool.hh +++ b/src/cpu/inorder/resource_pool.hh @@ -130,6 +130,8 @@ class ResourcePool { void init(); + void print(); + /** Register Statistics in All Resources */ void regStats(); diff --git a/src/cpu/inorder/resource_sked.cc b/src/cpu/inorder/resource_sked.cc index 4104e6989..4cf791228 100644 --- a/src/cpu/inorder/resource_sked.cc +++ b/src/cpu/inorder/resource_sked.cc @@ -34,30 +34,30 @@ #include <vector> #include <list> -#include <stdio.h> +#include <cstdio> using namespace std; using namespace ThePipeline; ResourceSked::ResourceSked() { - sked.resize(NumStages); + stages.resize(NumStages); } void ResourceSked::init() { - assert(!sked[0].empty()); + assert(!stages[0].empty()); - curSkedEntry = sked[0].begin(); + curSkedEntry = stages[0].begin(); } int ResourceSked::size() { int total = 0; - for (int i = 0; i < sked.size(); i++) { - total += sked[i].size(); + for (int i = 0; i < stages.size(); i++) { + total += stages[i].size(); } return total; @@ -69,6 +69,26 @@ ResourceSked::empty() return size() == 0; } + +ResourceSked::SkedIt +ResourceSked::begin() +{ + int num_stages = stages.size(); + for (int i = 0; i < num_stages; i++) { + if (stages[i].size() > 0) + return stages[i].begin(); + } + + return stages[num_stages - 1].end(); +} + +ResourceSked::SkedIt +ResourceSked::end() +{ + int num_stages = stages.size(); + return stages[num_stages - 1].end(); +} + ScheduleEntry* ResourceSked::top() { @@ -82,18 +102,18 @@ ResourceSked::pop() { int stage_num = (*curSkedEntry)->stageNum; - sked[stage_num].erase(curSkedEntry); + stages[stage_num].erase(curSkedEntry); - if (!sked[stage_num].empty()) { - curSkedEntry = sked[stage_num].begin(); + if (!stages[stage_num].empty()) { + curSkedEntry = stages[stage_num].begin(); } else { int next_stage = stage_num + 1; while (next_stage < NumStages) { - if (sked[next_stage].empty()) { + if (stages[next_stage].empty()) { next_stage++; } else { - curSkedEntry = sked[next_stage].begin(); + curSkedEntry = stages[next_stage].begin(); break; } } @@ -108,7 +128,7 @@ ResourceSked::push(ScheduleEntry* sked_entry) SkedIt pri_iter = findIterByPriority(sked_entry, stage_num); - sked[stage_num].insert(pri_iter, sked_entry); + stages[stage_num].insert(pri_iter, sked_entry); } void @@ -122,23 +142,23 @@ ResourceSked::pushBefore(ScheduleEntry* sked_entry, int sked_cmd, SkedIt pri_iter = findIterByCommand(sked_entry, stage_num, sked_cmd, sked_cmd_idx); - assert(pri_iter != sked[stage_num].end() && + assert(pri_iter != stages[stage_num].end() && "Could not find command to insert in front of."); - sked[stage_num].insert(pri_iter, sked_entry); + stages[stage_num].insert(pri_iter, sked_entry); } ResourceSked::SkedIt ResourceSked::findIterByPriority(ScheduleEntry* sked_entry, int stage_num) { - if (sked[stage_num].empty()) { - return sked[stage_num].end(); + if (stages[stage_num].empty()) { + return stages[stage_num].end(); } int priority = sked_entry->priority; - SkedIt sked_it = sked[stage_num].begin(); - SkedIt sked_end = sked[stage_num].end(); + SkedIt sked_it = stages[stage_num].begin(); + SkedIt sked_end = stages[stage_num].end(); while (sked_it != sked_end) { if ((*sked_it)->priority > priority) @@ -154,12 +174,12 @@ ResourceSked::SkedIt ResourceSked::findIterByCommand(ScheduleEntry* sked_entry, int stage_num, int sked_cmd, int sked_cmd_idx) { - if (sked[stage_num].empty()) { - return sked[stage_num].end(); + if (stages[stage_num].empty()) { + return stages[stage_num].end(); } - SkedIt sked_it = sked[stage_num].begin(); - SkedIt sked_end = sked[stage_num].end(); + SkedIt sked_it = stages[stage_num].begin(); + SkedIt sked_end = stages[stage_num].end(); while (sked_it != sked_end) { if ((*sked_it)->cmd == sked_cmd && @@ -175,12 +195,16 @@ ResourceSked::findIterByCommand(ScheduleEntry* sked_entry, int stage_num, void ResourceSked::print() { - for (int i = 0; i < sked.size(); i++) { - cprintf("Stage %i\n====\n", i); - SkedIt sked_it = sked[i].begin(); - SkedIt sked_end = sked[i].end(); + for (int i = 0; i < stages.size(); i++) { + //ccprintf(cerr, "Stage %i\n====\n", i); + SkedIt sked_it = stages[i].begin(); + SkedIt sked_end = stages[i].end(); while (sked_it != sked_end) { - cprintf("\t res:%i cmd:%i idx:%i\n", (*sked_it)->resNum, (*sked_it)->cmd, (*sked_it)->idx); + DPRINTF(SkedCache, "\t stage:%i res:%i cmd:%i idx:%i\n", + (*sked_it)->stageNum, + (*sked_it)->resNum, + (*sked_it)->cmd, + (*sked_it)->idx); sked_it++; } } diff --git a/src/cpu/inorder/resource_sked.hh b/src/cpu/inorder/resource_sked.hh index 22e29d728..bd002e161 100644 --- a/src/cpu/inorder/resource_sked.hh +++ b/src/cpu/inorder/resource_sked.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 The Regents of The University of Michigan + * Copyright (c) 2010-2011 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,7 +34,19 @@ #include <vector> #include <list> +#include <cstdlib> +/** ScheduleEntry class represents a single function that an instruction + wants to do at any pipeline stage. For example, if an instruction + needs to be decoded and do a branch prediction all in one stage + then each of those tasks would need it's own ScheduleEntry. + + Each schedule entry corresponds to some resource that the instruction + wants to interact with. + + The file pipeline_traits.cc shows how a typical instruction schedule is + made up of these schedule entries. +*/ class ScheduleEntry { public: ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, @@ -43,45 +55,225 @@ class ScheduleEntry { idx(_idx), priority(_priority) { } - // Stage number to perform this service. + /** Stage number to perform this service. */ int stageNum; - // Resource ID to access + /** Resource ID to access */ int resNum; - // See specific resource for meaning + /** See specific resource for meaning */ unsigned cmd; - // See specific resource for meaning + /** See specific resource for meaning */ unsigned idx; - // Some Resources May Need Priority + /** Some Resources May Need Priority */ int priority; }; +/** The ResourceSked maintains the complete schedule + for an instruction. That schedule includes what + resources an instruction wants to acquire at each + pipeline stage and is represented by a collection + of ScheduleEntry objects (described above) that + must be executed in-order. + + In every pipeline stage, the InOrder model will + process all entries on the resource schedule for + that stage and then send the instruction to the next + stage if and only if the instruction successfully + completed each ScheduleEntry. +*/ class ResourceSked { public: typedef std::list<ScheduleEntry*>::iterator SkedIt; + typedef std::vector<std::list<ScheduleEntry*> > StageList; ResourceSked(); + /** Initializee the current entry pointer to + pipeline stage 0 and the 1st schedule entry + */ void init(); + /** Goes through the remaining stages on the schedule + and sums all the remaining entries left to be + processed + */ int size(); + + /** Is the schedule empty? */ bool empty(); + + /** Beginning Entry of this schedule */ + SkedIt begin(); + + /** Ending Entry of this schedule */ + SkedIt end(); + + /** What is the next task for this instruction schedule? */ ScheduleEntry* top(); + + /** Top() Task is completed, remove it from schedule */ void pop(); + + /** Add To Schedule based on stage num and priority of + Schedule Entry + */ void push(ScheduleEntry* sked_entry); + + /** Add Schedule Entry to be in front of another Entry */ void pushBefore(ScheduleEntry* sked_entry, int sked_cmd, int sked_cmd_idx); + + /** Print what's left on the instruction schedule */ void print(); + StageList *getStages() + { + return &stages; + } + private: + /** Current Schedule Entry Pointer */ SkedIt curSkedEntry; - std::vector<std::list<ScheduleEntry*> > sked; + /** The Stage-by-Stage Resource Schedule: + Resized to Number of Stages in the constructor + */ + StageList stages; + + /** Find a place to insert the instruction using the + schedule entries priority + */ SkedIt findIterByPriority(ScheduleEntry *sked_entry, int stage_num); + + /** Find a place to insert the instruction using a particular command + to look for. + */ SkedIt findIterByCommand(ScheduleEntry *sked_entry, int stage_num, int sked_cmd, int sked_cmd_idx = -1); }; +/** Wrapper class around the SkedIt iterator in the Resource Sked so that + we can use ++ operator to automatically go to the next available + resource schedule entry but otherwise maintain same functionality + as a normal iterator. +*/ +class RSkedIt +{ + public: + RSkedIt() + : curStage(0), numStages(0) + { } + + + /** init() must be called before the use of any other member + in the RSkedIt class. + */ + void init(ResourceSked* rsked) + { + stages = rsked->getStages(); + numStages = stages->size(); + } + + /* Update the encapsulated "myIt" iterator, but only + update curStage/curStage_end if the iterator is valid. + The iterator could be invalid in the case where + someone is saving the end of a list (i.e. std::list->end()) + */ + RSkedIt operator=(ResourceSked::SkedIt const &rhs) + { + myIt = rhs; + if (myIt != (*stages)[numStages-1].end()) { + curStage = (*myIt)->stageNum; + curStage_end = (*stages)[curStage].end(); + } + return *this; + } + + /** Increment to the next entry in current stage. + If no more entries then find the next stage that has + resource schedule to complete. + If no more stages, then return the end() iterator from + the last stage to indicate we are done. + */ + RSkedIt &operator++(int unused) + { + if (++myIt == curStage_end) { + curStage++; + while (curStage < numStages) { + if ((*stages)[curStage].empty()) { + curStage++; + } else { + myIt = (*stages)[curStage].begin(); + curStage_end = (*stages)[curStage].end(); + return *this; + } + } + + myIt = (*stages)[numStages - 1].end(); + } + + return *this; + } + + /** The "pointer" operator can be used on a RSkedIt and it + will use the encapsulated iterator + */ + ScheduleEntry* operator->() + { + return *myIt; + } + + /** Dereferencing a RSKedIt will access the encapsulated + iterator + */ + ScheduleEntry* operator*() + { + return *myIt; + } + + /** Equality for RSkedIt only compares the "myIt" iterators, + as the other members are just ancillary + */ + bool operator==(RSkedIt const &rhs) + { + return this->myIt == rhs.myIt; + } + + /** Inequality for RSkedIt only compares the "myIt" iterators, + as the other members are just ancillary + */ + bool operator!=(RSkedIt const &rhs) + { + return this->myIt != rhs.myIt; + } + + /* The == and != operator overloads should be sufficient + here if need otherwise direct access to the schedule + iterator, then this can be used */ + ResourceSked::SkedIt getIt() + { + return myIt; + } + + private: + /** Schedule Iterator that this class is encapsulating */ + ResourceSked::SkedIt myIt; + + /** Ptr to resource schedule that the 'myIt' iterator + belongs to + */ + ResourceSked::StageList *stages; + + /** The last iterator in the current stage. */ + ResourceSked::SkedIt curStage_end; + + /** Current Stage that "myIt" refers to. */ + int curStage; + + /** Number of stages in the "*stages" object. */ + int numStages; +}; + #endif //__CPU_INORDER_RESOURCE_SKED_HH__ diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc index 8b4dd4402..8cd105493 100644 --- a/src/cpu/inorder/resources/cache_unit.cc +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -260,7 +260,7 @@ CacheUnit::findRequest(DynInstPtr inst) if (cache_req && cache_req->getInst() == inst && - cache_req->instIdx == inst->resSched.top()->idx) { + cache_req->instIdx == inst->curSkedEntry->idx) { return cache_req; } map_it++; @@ -296,7 +296,7 @@ ResReqPtr CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num, unsigned cmd) { - ScheduleEntry* sched_entry = inst->resSched.top(); + ScheduleEntry* sched_entry = *inst->curSkedEntry; if (!inst->validMemAddr()) { panic("Mem. Addr. must be set before requesting cache access\n"); @@ -346,7 +346,7 @@ CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, return new CacheRequest(this, inst, stage_num, id, slot_num, sched_entry->cmd, 0, pkt_cmd, 0/*flags*/, this->cpu->readCpuId(), - inst->resSched.top()->idx); + inst->curSkedEntry->idx); } void @@ -357,17 +357,17 @@ CacheUnit::requestAgain(DynInstPtr inst, bool &service_request) // Check to see if this instruction is requesting the same command // or a different one - if (cache_req->cmd != inst->resSched.top()->cmd && - cache_req->instIdx == inst->resSched.top()->idx) { + if (cache_req->cmd != inst->curSkedEntry->cmd && + cache_req->instIdx == inst->curSkedEntry->idx) { // If different, then update command in the request - cache_req->cmd = inst->resSched.top()->cmd; + cache_req->cmd = inst->curSkedEntry->cmd; DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Updating the command for this " "instruction\n ", inst->readTid(), inst->seqNum); service_request = true; - } else if (inst->resSched.top()->idx != CacheUnit::InitSecondSplitRead && - inst->resSched.top()->idx != CacheUnit::InitSecondSplitWrite) { + } else if (inst->curSkedEntry->idx != CacheUnit::InitSecondSplitRead && + inst->curSkedEntry->idx != CacheUnit::InitSecondSplitWrite) { // If same command, just check to see if memory access was completed // but dont try to re-execute DPRINTF(InOrderCachePort, @@ -487,14 +487,20 @@ CacheUnit::read(DynInstPtr inst, Addr addr, inst->splitMemData = new uint8_t[size]; if (!inst->splitInstSked) { + assert(0 && "Split Requests Not Supported for Now..."); + // Schedule Split Read/Complete for Instruction // ============================== int stage_num = cache_req->getStageNum(); - - int stage_pri = ThePipeline::getNextPriority(inst, stage_num); + RSkedPtr inst_sked = (stage_num >= ThePipeline::BackEndStartStage) ? + inst->backSked : inst->frontSked; + + // this is just an arbitrarily high priority to ensure that this + // gets pushed to the back of the list + int stage_pri = 20; int isplit_cmd = CacheUnit::InitSecondSplitRead; - inst->resSched.push(new + inst_sked->push(new ScheduleEntry(stage_num, stage_pri, cpu->resPool->getResIdx(DCache), @@ -502,7 +508,7 @@ CacheUnit::read(DynInstPtr inst, Addr addr, 1)); int csplit_cmd = CacheUnit::CompleteSecondSplitRead; - inst->resSched.push(new + inst_sked->push(new ScheduleEntry(stage_num + 1, 1/*stage_pri*/, cpu->resPool->getResIdx(DCache), @@ -590,27 +596,33 @@ CacheUnit::write(DynInstPtr inst, uint8_t *data, unsigned size, inst->splitInst = true; if (!inst->splitInstSked) { + assert(0 && "Split Requests Not Supported for Now..."); + // Schedule Split Read/Complete for Instruction // ============================== int stage_num = cache_req->getStageNum(); + RSkedPtr inst_sked = (stage_num >= ThePipeline::BackEndStartStage) ? + inst->backSked : inst->frontSked; - int stage_pri = ThePipeline::getNextPriority(inst, stage_num); + // this is just an arbitrarily high priority to ensure that this + // gets pushed to the back of the list + int stage_pri = 20; int isplit_cmd = CacheUnit::InitSecondSplitWrite; - inst->resSched.push(new - ScheduleEntry(stage_num, - stage_pri, - cpu->resPool->getResIdx(DCache), - isplit_cmd, - 1)); + inst_sked->push(new + ScheduleEntry(stage_num, + stage_pri, + cpu->resPool->getResIdx(DCache), + isplit_cmd, + 1)); int csplit_cmd = CacheUnit::CompleteSecondSplitWrite; - inst->resSched.push(new - ScheduleEntry(stage_num + 1, - 1/*stage_pri*/, - cpu->resPool->getResIdx(DCache), - csplit_cmd, - 1)); + inst_sked->push(new + ScheduleEntry(stage_num + 1, + 1/*stage_pri*/, + cpu->resPool->getResIdx(DCache), + csplit_cmd, + 1)); inst->splitInstSked = true; } else { DPRINTF(InOrderCachePort, "[tid:%i] sn:%i] Retrying Split Read " diff --git a/src/cpu/inorder/resources/decode_unit.cc b/src/cpu/inorder/resources/decode_unit.cc index c2f7ae22d..42857c783 100644 --- a/src/cpu/inorder/resources/decode_unit.cc +++ b/src/cpu/inorder/resources/decode_unit.cc @@ -57,13 +57,16 @@ DecodeUnit::execute(int slot_num) { case DecodeInst: { - bool done_sked = ThePipeline::createBackEndSchedule(inst); + inst->setBackSked(cpu->createBackEndSked(inst)); - if (done_sked) { + if (inst->backSked != NULL) { DPRINTF(InOrderDecode, "[tid:%i]: Setting Destination Register(s) for [sn:%i].\n", tid, inst->seqNum); regDepMap[tid]->insert(inst); + + //inst->printSked(); + decode_req->done(); } else { DPRINTF(Resource, diff --git a/src/cpu/inorder/resources/fetch_unit.cc b/src/cpu/inorder/resources/fetch_unit.cc index 0e9866708..0a5483aff 100644 --- a/src/cpu/inorder/resources/fetch_unit.cc +++ b/src/cpu/inorder/resources/fetch_unit.cc @@ -118,7 +118,7 @@ ResReqPtr FetchUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num, unsigned cmd) { - ScheduleEntry* sched_entry = inst->resSched.top(); + ScheduleEntry* sched_entry = *inst->curSkedEntry; if (!inst->validMemAddr()) { panic("Mem. Addr. must be set before requesting cache access\n"); @@ -144,7 +144,7 @@ FetchUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, return new CacheRequest(this, inst, stage_num, id, slot_num, sched_entry->cmd, 0, pkt_cmd, 0/*flags*/, this->cpu->readCpuId(), - inst->resSched.top()->idx); + inst->curSkedEntry->idx); } void @@ -447,7 +447,7 @@ FetchUnit::processCacheCompletion(PacketPtr pkt) short asid = cpu->asid[tid]; assert(!cache_req->isSquashed()); - assert(inst->resSched.top()->cmd == CompleteFetch); + assert(inst->curSkedEntry->cmd == CompleteFetch); DPRINTF(InOrderCachePort, "[tid:%u]: [sn:%i]: Processing fetch access for block %#x\n", diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc index 8ccdaa36a..362641b54 100644 --- a/src/cpu/inorder/resources/graduation_unit.cc +++ b/src/cpu/inorder/resources/graduation_unit.cc @@ -52,14 +52,15 @@ GraduationUnit::execute(int slot_num) ResourceRequest* grad_req = reqMap[slot_num]; DynInstPtr inst = reqMap[slot_num]->inst; ThreadID tid = inst->readTid(); - int stage_num = inst->resSched.top()->stageNum; + int stage_num = inst->curSkedEntry->stageNum; switch (grad_req->cmd) { case GraduateInst: { // Make sure this is the last thing on the resource schedule - assert(inst->resSched.size() == 1); + // @todo: replace this check + // assert(inst->resSched.size() == 1); // Handle Any Faults Before Graduating Instruction if (inst->fault != NoFault) { diff --git a/src/cpu/inorder/resources/inst_buffer.cc b/src/cpu/inorder/resources/inst_buffer.cc index 18dd26a78..988fcd4da 100644 --- a/src/cpu/inorder/resources/inst_buffer.cc +++ b/src/cpu/inorder/resources/inst_buffer.cc @@ -99,19 +99,22 @@ InstBuffer::execute(int slot_idx) inst->seqNum, next_stage); // Add to schedule: Insert into buffer in next stage - int stage_pri = ThePipeline::getNextPriority(inst, - next_stage); + int stage_pri = 20; + RSkedPtr insert_sked = (stage_num >= ThePipeline::BackEndStartStage) ? + inst->backSked : inst->frontSked; - inst->resSched.push(new ScheduleEntry(next_stage, + insert_sked->push(new ScheduleEntry(next_stage, stage_pri, id, InstBuffer::InsertInst)); // Add to schedule: Remove from buffer in next next (bypass) // stage - stage_pri = ThePipeline::getNextPriority(inst, bypass_stage); + stage_pri = 20; + RSkedPtr bypass_sked = (stage_num >= ThePipeline::BackEndStartStage) ? + inst->backSked : inst->frontSked; - inst->resSched.push(new ScheduleEntry(bypass_stage, + bypass_sked->push(new ScheduleEntry(bypass_stage, stage_pri, id, InstBuffer::RemoveInst)); diff --git a/src/cpu/inorder/resources/inst_buffer_new.cc b/src/cpu/inorder/resources/inst_buffer_new.cc deleted file mode 100644 index 2e5a9666a..000000000 --- a/src/cpu/inorder/resources/inst_buffer_new.cc +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2007 MIPS Technologies, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Korey Sewell - * - */ - -#include <vector> -#include <list> - -#include "arch/isa_traits.hh" -#include "config/the_isa.hh" -#include "cpu/inorder/pipeline_traits.hh" -#include "cpu/inorder/resources/inst_buffer.hh" -#include "cpu/inorder/cpu.hh" - -using namespace std; -using namespace TheISA; -using namespace ThePipeline; - -InstBuffer::InstBuffer(string res_name, int res_id, int res_width, - int res_latency, InOrderCPU *_cpu) - : Resource(res_name, res_id, res_width, res_latency, _cpu) -{ } - -ResReqPtr -InstBuffer::getRequest(DynInstPtr inst, int stage_num, int res_idx, - int slot_num) -{ - // After this is working, change this to a reinterpret cast - // for performance considerations - InstBufferEntry* ib_entry = dynamic_cast<InstBufferEntry*>(inst->resSched.top()); - assert(ib_entry); - - return new InstBufferRequest(this, inst, stage_num, id, slot_num, - ib_entry->cmd); -} - -void -InstBuffer::execute(int slot_idx) -{ - // After this is working, change this to a reinterpret cast - // for performance considerations - InstBufferRequest* ib_req = dynamic_cast<InstBufferRequest*>(reqMap[slot_idx]); - assert(ib_req); - - DynInstPtr inst = ib_req->inst; - ThreadID tid = inst->readTid(); - int seq_num = inst->seqNum; - ib_req->fault = NoFault; - - switch (ib_req->cmd) - { - case InsertInst: - { - DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n", - tid, seq_num); - insert(inst); - ib_req->done(); - } - break; - - case RemoveInst: - { - DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n", - tid, seq_num); - remove(inst); - ib_req->done(); - } - break; - - default: - fatal("Unrecognized command to %s", resName); - } - - DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size()); -} - -void -InstBuffer::insert(DynInstPtr inst) -{ - instList.push_back(inst); -} - -void -InstBuffer::remove(DynInstPtr inst) -{ - std::list<DynInstPtr>::iterator list_it = instList.begin(); - std::list<DynInstPtr>::iterator list_end = instList.end(); - - while (list_it != list_end) { - if((*list_it) == inst) { - instList.erase(list_it); - break; - } - list_it++; - } -} - -void -InstBuffer::pop() -{ instList.pop_front(); } - -ThePipeline::DynInstPtr -InstBuffer::top() -{ return instList.front(); } - -void -InstBuffer::squash(InstSeqNum squash_seq_num, ThreadID tid) -{ - list<DynInstPtr>::iterator list_it = instList.begin(); - list<DynInstPtr>::iterator list_end = instList.end(); - queue<list<DynInstPtr>::iterator> remove_list; - - // Collect All Instructions to be Removed in Remove List - while (list_it != list_end) { - if((*list_it)->seqNum > squash_seq_num) { - DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i] in resource.\n", - tid, (*list_it)->seqNum); - (*list_it)->setSquashed(); - remove_list.push(list_it); - } - - list_it++; - } - - // Removed Instructions from InstList & Clear Remove List - while (!remove_list.empty()) { - instList.erase(remove_list.front()); - remove_list.pop(); - } - - Resource::squash(squash_seq_num, tid); -} diff --git a/src/cpu/inorder/resources/inst_buffer_new.hh b/src/cpu/inorder/resources/inst_buffer_new.hh deleted file mode 100644 index b1d5a7b09..000000000 --- a/src/cpu/inorder/resources/inst_buffer_new.hh +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2007 MIPS Technologies, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Korey Sewell - * - */ - -#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__ -#define __CPU_INORDER_INST_BUFF_UNIT_HH__ - -#include <vector> -#include <list> -#include <string> - -#include "cpu/inorder/resource.hh" -#include "cpu/inorder/inorder_dyn_inst.hh" -#include "cpu/inorder/pipeline_traits.hh" -#include "cpu/inorder/cpu.hh" - -class InstBuffer : public Resource { - public: - typedef InOrderDynInst::DynInstPtr DynInstPtr; - - public: - enum Command { - InsertInst, - InsertAddr, - RemoveInst, - RemoveAddr - }; - - public: - InstBuffer(std::string res_name, int res_id, int res_width, - int res_latency, InOrderCPU *_cpu); - virtual ~InstBuffer() {} - - virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, - int res_idx, int slot_num); - - virtual void execute(int slot_num); - - virtual void insert(DynInstPtr inst); - - virtual void remove(DynInstPtr inst); - - virtual void pop(); - - virtual DynInstPtr top(); - - virtual void squash(InstSeqNum squash_seq_num, ThreadID tid); - - protected: - /** List of instructions this resource is currently - * processing. - */ - std::list<DynInstPtr> instList; - - /** @todo: Add Resource Stats Here */ - -}; - -struct InstBufferEntry : public ThePipeline::ScheduleEntry { - InstBufferEntry(int stage_num, int res_num, InstBuffer::Command _cmd) : - ScheduleEntry(stage_num, res_num), cmd(_cmd) - { } - - InstBuffer::Command cmd; -}; - -class InstBufferRequest : public ResourceRequest { - public: - typedef InOrderDynInst::DynInstPtr DynInstPtr; - - public: - InstBufferRequest(InstBuffer *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num, - InstBuffer::Command _cmd) - : ResourceRequest(res, inst, stage_num, res_idx, slot_num), - cmd(_cmd) - { } - - InstBuffer::Command cmd; -}; - - -#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/cpu/inorder/resources/mult_div_unit.cc b/src/cpu/inorder/resources/mult_div_unit.cc index 5aa0b0aa1..042fb590b 100644 --- a/src/cpu/inorder/resources/mult_div_unit.cc +++ b/src/cpu/inorder/resources/mult_div_unit.cc @@ -110,9 +110,9 @@ MultDivUnit::requestAgain(DynInstPtr inst, bool &service_request) // Check to see if this instruction is requesting the same command // or a different one - if (mult_div_req->cmd != inst->resSched.top()->cmd) { + if (mult_div_req->cmd != inst->curSkedEntry->cmd) { // If different, then update command in the request - mult_div_req->cmd = inst->resSched.top()->cmd; + mult_div_req->cmd = inst->curSkedEntry->cmd; DPRINTF(InOrderMDU, "[tid:%i]: [sn:%i]: Updating the command for this " "instruction\n", inst->readTid(), inst->seqNum); @@ -132,7 +132,7 @@ MultDivUnit::getSlot(DynInstPtr inst) // If we have this instruction's request already then return if (slot_num != -1 && - inst->resSched.top()->cmd == reqMap[slot_num]->cmd) + inst->curSkedEntry->cmd == reqMap[slot_num]->cmd) return slot_num; unsigned repeat_rate = 0; diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc index 59840d15b..2e19ea928 100644 --- a/src/cpu/inorder/resources/tlb_unit.cc +++ b/src/cpu/inorder/resources/tlb_unit.cc @@ -217,7 +217,7 @@ TLBUnitEvent::process() // Effectively NOP the instruction but still allow it // to commit //while (!inst->resSched.empty() && - // inst->resSched.top()->stageNum != ThePipeline::NumStages - 1) { + // inst->curSkedEntry->stageNum != ThePipeline::NumStages - 1) { //inst->resSched.pop(); //} } diff --git a/src/cpu/inorder/resources/use_def.cc b/src/cpu/inorder/resources/use_def.cc index 743011573..538b20246 100644 --- a/src/cpu/inorder/resources/use_def.cc +++ b/src/cpu/inorder/resources/use_def.cc @@ -93,7 +93,7 @@ UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num, unsigned cmd) { return new UseDefRequest(this, inst, stage_num, id, slot_num, cmd, - inst->resSched.top()->idx); + inst->curSkedEntry->idx); } @@ -110,8 +110,8 @@ UseDefUnit::findRequest(DynInstPtr inst) if (ud_req && ud_req->getInst() == inst && - ud_req->cmd == inst->resSched.top()->cmd && - ud_req->useDefIdx == inst->resSched.top()->idx) { + ud_req->cmd == inst->curSkedEntry->cmd && + ud_req->useDefIdx == inst->curSkedEntry->idx) { return ud_req; } map_it++; diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 92691720b..647c48a76 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -137,6 +137,10 @@ class DefaultFetch {} void + markDelayed() + {} + + void finish(Fault fault, RequestPtr req, ThreadContext *tc, BaseTLB::Mode mode) { diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index d0c83d586..d2cde496e 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -604,6 +604,9 @@ DefaultFetch<Impl>::finishTranslation(Fault fault, RequestPtr mem_req) ThreadID tid = mem_req->threadId(); Addr block_PC = mem_req->getVaddr(); + // Wake up CPU if it was idle + cpu->wakeCPU(); + // If translation was successful, attempt to read the icache block. if (fault == NoFault) { // Build packet here. @@ -654,6 +657,9 @@ DefaultFetch<Impl>::finishTranslation(Fault fault, RequestPtr mem_req) instruction->fault = fault; wroteToTimeBuffer = true; + DPRINTF(Activity, "Activity this cycle.\n"); + cpu->activityThisCycle(); + fetchStatus[tid] = TrapPending; DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n", tid); @@ -1064,6 +1070,8 @@ DefaultFetch<Impl>::fetch(bool &status_change) Addr pcOffset = fetchOffset[tid]; Addr fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask; + bool inRom = isRomMicroPC(thisPC.microPC()); + // If returning from the delay of a cache miss, then update the status // to running, otherwise do the cache access. Possibly move this up // to tick() function. @@ -1077,7 +1085,7 @@ DefaultFetch<Impl>::fetch(bool &status_change) Addr block_PC = icacheBlockAlignPC(fetchAddr); // Unless buffer already got the block, fetch it from icache. - if (!cacheDataValid[tid] || block_PC != cacheDataPC[tid]) { + if (!(cacheDataValid[tid] && block_PC == cacheDataPC[tid]) && !inRom) { DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read " "instruction, starting at PC %s.\n", tid, thisPC); @@ -1149,7 +1157,7 @@ DefaultFetch<Impl>::fetch(bool &status_change) !predictedBranch) { // If we need to process more memory, do it now. - if (!curMacroop && !predecoder.extMachInstReady()) { + if (!(curMacroop || inRom) && !predecoder.extMachInstReady()) { if (ISA_HAS_DELAY_SLOT && pcOffset == 0) { // Walk past any annulled delay slot instructions. Addr pcAddr = thisPC.instAddr() & BaseCPU::PCMask; @@ -1175,7 +1183,7 @@ DefaultFetch<Impl>::fetch(bool &status_change) // Extract as many instructions and/or microops as we can from // the memory we've processed so far. do { - if (!curMacroop) { + if (!(curMacroop || inRom)) { if (predecoder.extMachInstReady()) { ExtMachInst extMachInst; @@ -1196,8 +1204,13 @@ DefaultFetch<Impl>::fetch(bool &status_change) break; } } - if (curMacroop) { - staticInst = curMacroop->fetchMicroop(thisPC.microPC()); + if (curMacroop || inRom) { + if (inRom) { + staticInst = cpu->microcodeRom.fetchMicroop( + thisPC.microPC(), curMacroop); + } else { + staticInst = curMacroop->fetchMicroop(thisPC.microPC()); + } if (staticInst->isLastMicroop()) { curMacroop = NULL; pcOffset = 0; diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh index 3f3761ff3..03f73c798 100644 --- a/src/cpu/o3/iew_impl.hh +++ b/src/cpu/o3/iew_impl.hh @@ -1241,12 +1241,33 @@ DefaultIEW<Impl>::executeInsts() // Loads will mark themselves as executed, and their writeback // event adds the instruction to the queue to commit fault = ldstQueue.executeLoad(inst); + + if (inst->isTranslationDelayed() && + fault == NoFault) { + // A hw page table walk is currently going on; the + // instruction must be deferred. + DPRINTF(IEW, "Execute: Delayed translation, deferring " + "load.\n"); + instQueue.deferMemInst(inst); + continue; + } + if (inst->isDataPrefetch() || inst->isInstPrefetch()) { fault = NoFault; } } else if (inst->isStore()) { fault = ldstQueue.executeStore(inst); + if (inst->isTranslationDelayed() && + fault == NoFault) { + // A hw page table walk is currently going on; the + // instruction must be deferred. + DPRINTF(IEW, "Execute: Delayed translation, deferring " + "store.\n"); + instQueue.deferMemInst(inst); + continue; + } + // If the store had a fault then it may not have a mem req if (fault != NoFault || inst->readPredicate() == false || !inst->isStoreConditional()) { diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh index be936e204..64df35743 100644 --- a/src/cpu/o3/inst_queue.hh +++ b/src/cpu/o3/inst_queue.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * @@ -180,6 +192,11 @@ class InstructionQueue */ DynInstPtr getInstToExecute(); + /** Returns a memory instruction that was referred due to a delayed DTB + * translation if it is now ready to execute. + */ + DynInstPtr getDeferredMemInstToExecute(); + /** * Records the instruction as the producer of a register without * adding it to the rest of the IQ. @@ -223,6 +240,12 @@ class InstructionQueue /** Completes a memory operation. */ void completeMemInst(DynInstPtr &completed_inst); + /** + * Defers a memory instruction when its DTB translation incurs a hw + * page table walk. + */ + void deferMemInst(DynInstPtr &deferred_inst); + /** Indicates an ordering violation between a store and a load. */ void violation(DynInstPtr &store, DynInstPtr &faulting_load); @@ -284,6 +307,11 @@ class InstructionQueue /** List of instructions that are ready to be executed. */ std::list<DynInstPtr> instsToExecute; + /** List of instructions waiting for their DTB translation to + * complete (hw page table walk in progress). + */ + std::list<DynInstPtr> deferredMemInsts; + /** * Struct for comparing entries to be added to the priority queue. * This gives reverse ordering to the instructions in terms of diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh index 91cb2f0c8..aa21a0edc 100644 --- a/src/cpu/o3/inst_queue_impl.hh +++ b/src/cpu/o3/inst_queue_impl.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * @@ -397,6 +409,7 @@ InstructionQueue<Impl>::resetState() } nonSpecInsts.clear(); listOrder.clear(); + deferredMemInsts.clear(); } template <class Impl> @@ -733,6 +746,15 @@ InstructionQueue<Impl>::scheduleReadyInsts() IssueStruct *i2e_info = issueToExecuteQueue->access(0); + DynInstPtr deferred_mem_inst; + int total_deferred_mem_issued = 0; + while (total_deferred_mem_issued < totalWidth && + (deferred_mem_inst = getDeferredMemInstToExecute()) != 0) { + issueToExecuteQueue->access(0)->size++; + instsToExecute.push_back(deferred_mem_inst); + total_deferred_mem_issued++; + } + // Have iterator to head of the list // While I haven't exceeded bandwidth or reached the end of the list, // Try to get a FU that can do what this op needs. @@ -745,7 +767,7 @@ InstructionQueue<Impl>::scheduleReadyInsts() ListOrderIt order_end_it = listOrder.end(); int total_issued = 0; - while (total_issued < totalWidth && + while (total_issued < (totalWidth - total_deferred_mem_issued) && iewStage->canIssue() && order_it != order_end_it) { OpClass op_class = (*order_it).queueType; @@ -858,7 +880,7 @@ InstructionQueue<Impl>::scheduleReadyInsts() iqInstsIssued+= total_issued; // If we issued any instructions, tell the CPU we had activity. - if (total_issued) { + if (total_issued || total_deferred_mem_issued) { cpu->activityThisCycle(); } else { DPRINTF(IQ, "Not able to schedule any instructions.\n"); @@ -1021,6 +1043,11 @@ void InstructionQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst) { DPRINTF(IQ, "Rescheduling mem inst [sn:%lli]\n", resched_inst->seqNum); + + // Reset DTB translation state + resched_inst->translationStarted = false; + resched_inst->translationCompleted = false; + resched_inst->clearCanIssue(); memDepUnit[resched_inst->threadNumber].reschedule(resched_inst); } @@ -1051,6 +1078,28 @@ InstructionQueue<Impl>::completeMemInst(DynInstPtr &completed_inst) template <class Impl> void +InstructionQueue<Impl>::deferMemInst(DynInstPtr &deferred_inst) +{ + deferredMemInsts.push_back(deferred_inst); +} + +template <class Impl> +typename Impl::DynInstPtr +InstructionQueue<Impl>::getDeferredMemInstToExecute() +{ + for (ListIt it = deferredMemInsts.begin(); it != deferredMemInsts.end(); + ++it) { + if ((*it)->translationCompleted) { + DynInstPtr ret = *it; + deferredMemInsts.erase(it); + return ret; + } + } + return NULL; +} + +template <class Impl> +void InstructionQueue<Impl>::violation(DynInstPtr &store, DynInstPtr &faulting_load) { diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index dd3604ffe..b5d337935 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -445,12 +445,16 @@ LSQUnit<Impl>::executeLoad(DynInstPtr &inst) Fault load_fault = NoFault; DPRINTF(LSQUnit, "Executing load PC %s, [sn:%lli]\n", - inst->pcState(),inst->seqNum); + inst->pcState(), inst->seqNum); assert(!inst->isSquashed()); load_fault = inst->initiateAcc(); + if (inst->isTranslationDelayed() && + load_fault == NoFault) + return load_fault; + // If the instruction faulted or predicated false, then we need to send it // along to commit without the instruction completing. if (load_fault != NoFault || inst->readPredicate() == false) { @@ -532,6 +536,10 @@ LSQUnit<Impl>::executeStore(DynInstPtr &store_inst) Fault store_fault = store_inst->initiateAcc(); + if (store_inst->isTranslationDelayed() && + store_fault == NoFault) + return store_fault; + if (store_inst->readPredicate() == false) store_inst->forwardOldRegs(); diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 453699f84..ab1ff91e8 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -752,6 +752,7 @@ TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) } else { delete req; // fetch fault: advance directly to next instruction (fault handler) + _status = Running; advanceInst(fault); } @@ -805,12 +806,11 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) if (curStaticInst && curStaticInst->isMemRef()) { // load or store: just send to dcache Fault fault = curStaticInst->initiateAcc(this, traceData); - if (_status != Running) { - // instruction will complete in dcache response callback - assert(_status == DcacheWaitResponse || - _status == DcacheRetry || DTBWaitResponse); - assert(fault == NoFault); - } else { + + // If we're not running now the instruction will complete in a dcache + // response callback or the instruction faulted and has started an + // ifetch + if (_status == Running) { if (fault != NoFault && traceData) { // If there was a fault, we shouldn't trace this instruction. delete traceData; diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index 2b0c8942a..a7a3eb7c3 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -108,6 +108,13 @@ class TimingSimpleCPU : public BaseSimpleCPU {} void + markDelayed() + { + assert(cpu->_status == Running); + cpu->_status = ITBWaitResponse; + } + + void finish(Fault fault, RequestPtr req, ThreadContext *tc, BaseTLB::Mode mode) { diff --git a/src/cpu/translation.hh b/src/cpu/translation.hh index 7db7c381a..60953540f 100644 --- a/src/cpu/translation.hh +++ b/src/cpu/translation.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2002-2005 The Regents of The University of Michigan * Copyright (c) 2009 The University of Edinburgh * All rights reserved. @@ -53,6 +65,7 @@ class WholeTranslationState Fault faults[2]; public: + bool delay; bool isSplit; RequestPtr mainReq; RequestPtr sreqLow; @@ -67,8 +80,8 @@ class WholeTranslationState */ WholeTranslationState(RequestPtr _req, uint8_t *_data, uint64_t *_res, BaseTLB::Mode _mode) - : outstanding(1), isSplit(false), mainReq(_req), sreqLow(NULL), - sreqHigh(NULL), data(_data), res(_res), mode(_mode) + : outstanding(1), delay(false), isSplit(false), mainReq(_req), + sreqLow(NULL), sreqHigh(NULL), data(_data), res(_res), mode(_mode) { faults[0] = faults[1] = NoFault; assert(mode == BaseTLB::Read || mode == BaseTLB::Write); @@ -82,8 +95,9 @@ class WholeTranslationState WholeTranslationState(RequestPtr _req, RequestPtr _sreqLow, RequestPtr _sreqHigh, uint8_t *_data, uint64_t *_res, BaseTLB::Mode _mode) - : outstanding(2), isSplit(true), mainReq(_req), sreqLow(_sreqLow), - sreqHigh(_sreqHigh), data(_data), res(_res), mode(_mode) + : outstanding(2), delay(false), isSplit(true), mainReq(_req), + sreqLow(_sreqLow), sreqHigh(_sreqHigh), data(_data), res(_res), + mode(_mode) { faults[0] = faults[1] = NoFault; assert(mode == BaseTLB::Read || mode == BaseTLB::Write); @@ -221,6 +235,16 @@ class DataTranslation : public BaseTLB::Translation } /** + * Signal the translation state that the translation has been delayed due + * to a hw page table walk. Split requests are transparently handled. + */ + void + markDelayed() + { + state->delay = true; + } + + /** * Finish this part of the translation and indicate that the whole * translation is complete if the state says so. */ |