diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index ef91f206b..620951e34 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -571,10 +571,15 @@ PipelineStage::activateThread(ThreadID tid) DPRINTF(InOrderStage,"[tid:%i]: Re-Inserting [sn:%lli] PC:%#x into stage skidBuffer %i\n", tid, inst->seqNum, inst->readPC(), inst->threadNumber); + // Make instruction available for pipeline processing skidBuffer[tid].push(inst); - switchedOutBuffer[tid] = NULL; + // Update PC so that we start fetching after this instruction to prevent + // "double"-execution of instructions + cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::UpdateAfterContextSwitch, inst, 0, 0, tid); + // Clear switchout buffer + switchedOutBuffer[tid] = NULL; switchedOutValid[tid] = false; } } diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh index 4ae4db818..383340df2 100644 --- a/src/cpu/inorder/resource.hh +++ b/src/cpu/inorder/resource.hh @@ -96,6 +96,10 @@ class Resource { /** Resources that care about thread activation override this. */ virtual void suspendThread(ThreadID tid) { } + /** Will be called the cycle before a context switch. Any bookkeeping + * that needs to be kept for that, can be done here + */ + virtual void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid) { } /** Resources that care when an instruction has been graduated * can override this diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc index 45a4a9e60..20f112a66 100644 --- a/src/cpu/inorder/resource_pool.cc +++ b/src/cpu/inorder/resource_pool.cc @@ -201,6 +201,9 @@ ResourcePool::slotsInUse(int res_idx) return resources[res_idx]->slotsInUse(); } +//@todo: split this function and call this version schedulePoolEvent +// and use this scheduleEvent for scheduling a specific event on +// a resource void ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, int delay, int res_idx, ThreadID tid) @@ -310,6 +313,20 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, } break; + case ResourcePool::UpdateAfterContextSwitch: + { + DPRINTF(Resource, "Scheduling UpdatePC Resource Pool Event for tick %i.\n", + curTick + delay); + ResPoolEvent *res_pool_event = new ResPoolEvent(this,e_type, + inst, + inst->squashingStage, + inst->seqNum, + inst->readTid()); + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + default: DPRINTF(Resource, "Ignoring Unrecognized CPU Event (%s).\n", InOrderCPU::eventNames[e_type]); @@ -415,6 +432,19 @@ ResourcePool::instGraduated(InstSeqNum seq_num, ThreadID tid) } } +void +ResourcePool::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Update PC to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->updateAfterContextSwitch(inst, tid); + } +} + ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool) : Event((Event::Priority)((unsigned)CPU_Tick_Pri+5)), resPool(_resPool), eventType((InOrderCPU::CPUEventType) Default) @@ -462,6 +492,10 @@ ResourcePool::ResPoolEvent::process() resPool->squashDueToMemStall(inst, stageNum, seqNum, tid); break; + case ResourcePool::UpdateAfterContextSwitch: + resPool->updateAfterContextSwitch(inst, tid); + break; + default: fatal("Unrecognized Event Type"); } diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh index ae63c4c59..3f62d2caa 100644 --- a/src/cpu/inorder/resource_pool.hh +++ b/src/cpu/inorder/resource_pool.hh @@ -63,6 +63,7 @@ class ResourcePool { enum ResPoolEventType { InstGraduated = InOrderCPU::NumCPUEvents, SquashAll, + UpdateAfterContextSwitch, Default }; @@ -175,6 +176,9 @@ class ResourcePool { /** De-Activate Thread in all resources */ void suspendAll(ThreadID tid); + /** Broadcast Context Switch Update to all resources */ + void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid); + /** Broadcast graduation to all resources */ void instGraduated(InstSeqNum seq_num, ThreadID tid); diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc index 2cf6c3195..4f9ed3eca 100644 --- a/src/cpu/inorder/resources/cache_unit.cc +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -49,14 +49,14 @@ using namespace ThePipeline; Tick CacheUnit::CachePort::recvAtomic(PacketPtr pkt) { - panic("DefaultFetch doesn't expect recvAtomic callback!"); + panic("CacheUnit::CachePort doesn't expect recvAtomic callback!"); return curTick; } void CacheUnit::CachePort::recvFunctional(PacketPtr pkt) { - panic("DefaultFetch doesn't expect recvFunctional callback!"); + panic("CacheUnit::CachePort doesn't expect recvFunctional callback!"); } void @@ -65,7 +65,7 @@ CacheUnit::CachePort::recvStatusChange(Status status) if (status == RangeChange) return; - panic("DefaultFetch doesn't expect recvStatusChange callback!"); + panic("CacheUnit::CachePort doesn't expect recvStatusChange callback!"); } bool diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc index e0b9ea1f9..c217f972e 100644 --- a/src/cpu/inorder/resources/fetch_seq_unit.cc +++ b/src/cpu/inorder/resources/fetch_seq_unit.cc @@ -342,3 +342,17 @@ FetchSeqUnit::suspendThread(ThreadID tid) { deactivateThread(tid); } + +void +FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid) +{ + pcValid[tid] = true; + + PC[tid] = inst->readNextPC(); + nextPC[tid] = inst->readNextNPC(); + nextNPC[tid] = inst->readNextNPC() + instSize; + + + DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating PC:%08p NPC:%08p NNPC:%08p.\n", + tid, PC[tid], nextPC[tid], nextNPC[tid]); +} diff --git a/src/cpu/inorder/resources/fetch_seq_unit.hh b/src/cpu/inorder/resources/fetch_seq_unit.hh index fdbc4521f..3283e0330 100644 --- a/src/cpu/inorder/resources/fetch_seq_unit.hh +++ b/src/cpu/inorder/resources/fetch_seq_unit.hh @@ -61,6 +61,8 @@ class FetchSeqUnit : public Resource { virtual void deactivateThread(ThreadID tid); virtual void suspendThread(ThreadID tid); virtual void execute(int slot_num); + void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid); + /** Override default Resource squash sequence. This actually, * looks in the global communication buffer to get squash