summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/base_dyn_inst.hh125
-rw-r--r--src/cpu/base_dyn_inst_impl.hh15
-rw-r--r--src/cpu/inorder/SConscript3
-rw-r--r--src/cpu/inorder/cpu.cc130
-rw-r--r--src/cpu/inorder/cpu.hh85
-rw-r--r--src/cpu/inorder/first_stage.cc2
-rw-r--r--src/cpu/inorder/inorder_dyn_inst.cc30
-rw-r--r--src/cpu/inorder/inorder_dyn_inst.hh107
-rw-r--r--src/cpu/inorder/pipeline_stage.cc11
-rw-r--r--src/cpu/inorder/pipeline_traits.cc171
-rw-r--r--src/cpu/inorder/pipeline_traits.hh18
-rw-r--r--src/cpu/inorder/resource.cc4
-rw-r--r--src/cpu/inorder/resource_pool.cc11
-rw-r--r--src/cpu/inorder/resource_pool.hh2
-rw-r--r--src/cpu/inorder/resource_sked.cc78
-rw-r--r--src/cpu/inorder/resource_sked.hh206
-rw-r--r--src/cpu/inorder/resources/cache_unit.cc62
-rw-r--r--src/cpu/inorder/resources/decode_unit.cc7
-rw-r--r--src/cpu/inorder/resources/fetch_unit.cc6
-rw-r--r--src/cpu/inorder/resources/graduation_unit.cc5
-rw-r--r--src/cpu/inorder/resources/inst_buffer.cc13
-rw-r--r--src/cpu/inorder/resources/inst_buffer_new.cc158
-rw-r--r--src/cpu/inorder/resources/inst_buffer_new.hh109
-rw-r--r--src/cpu/inorder/resources/mult_div_unit.cc6
-rw-r--r--src/cpu/inorder/resources/tlb_unit.cc2
-rw-r--r--src/cpu/inorder/resources/use_def.cc6
-rw-r--r--src/cpu/o3/fetch.hh4
-rw-r--r--src/cpu/o3/fetch_impl.hh23
-rw-r--r--src/cpu/o3/iew_impl.hh21
-rw-r--r--src/cpu/o3/inst_queue.hh28
-rw-r--r--src/cpu/o3/inst_queue_impl.hh53
-rw-r--r--src/cpu/o3/lsq_unit_impl.hh10
-rw-r--r--src/cpu/simple/timing.cc12
-rw-r--r--src/cpu/simple/timing.hh7
-rw-r--r--src/cpu/translation.hh32
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.
*/