From e8312ab6f700b31dfa357607ab51c9c05014572d Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Sun, 31 Jan 2010 18:25:48 -0500 Subject: [PATCH] inorder: switch out buffer add buffer for instructions to switch out to in a pipeline stage can't squash the instruction and remove the pipeline so we kind of need to 'suspend' an instruction at the stage while the memory stall resolves for the switch on cache miss model --- src/cpu/inorder/pipeline_stage.cc | 137 +++++++++++++++++------------- src/cpu/inorder/pipeline_stage.hh | 19 ++++- 2 files changed, 95 insertions(+), 61 deletions(-) diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index dc0378bf3..8d14aae27 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -44,6 +44,9 @@ PipelineStage::PipelineStage(Params *params, unsigned stage_num) stageBufferMax(ThePipeline::interStageBuffSize[stage_num]), prevStageValid(false), nextStageValid(false) { + switchedOutBuffer.resize(ThePipeline::MaxThreads); + switchedOutValid.resize(ThePipeline::MaxThreads); + init(params); } @@ -267,7 +270,8 @@ PipelineStage::isBlocked(ThreadID tid) bool PipelineStage::block(ThreadID tid) { - DPRINTF(InOrderStage, "[tid:%d]: Blocking, sending block signal back to previous stages.\n", tid); + DPRINTF(InOrderStage, "[tid:%d]: Blocking, sending block signal back to " + "previous stages.\n", tid); // Add the current inputs to the skid buffer so they can be // reprocessed when this stage unblocks. @@ -296,7 +300,8 @@ PipelineStage::block(ThreadID tid) void PipelineStage::blockDueToBuffer(ThreadID tid) { - DPRINTF(InOrderStage, "[tid:%d]: Blocking instructions from passing to next stage.\n", tid); + DPRINTF(InOrderStage, "[tid:%d]: Blocking instructions from passing to " + "next stage.\n", tid); if (stageStatus[tid] != Blocked) { // Set the status to Blocked. @@ -334,8 +339,9 @@ PipelineStage::squashDueToBranch(DynInstPtr &inst, ThreadID tid) { if (cpu->squashSeqNum[tid] < inst->seqNum && cpu->lastSquashCycle[tid] == curTick){ - DPRINTF(Resource, "Ignoring [sn:%i] squash signal due to another stage's squash " - "signal for after [sn:%i].\n", inst->seqNum, cpu->squashSeqNum[tid]); + DPRINTF(Resource, "Ignoring [sn:%i] squash signal due to another " + "stage's squash signal for after [sn:%i].\n", inst->seqNum, + cpu->squashSeqNum[tid]); } else { // Send back mispredict information. toPrevStages->stageInfo[stageNum][tid].branchMispredict = true; @@ -346,20 +352,28 @@ PipelineStage::squashDueToBranch(DynInstPtr &inst, ThreadID tid) #if ISA_HAS_DELAY_SLOT - toPrevStages->stageInfo[stageNum][tid].branchTaken = inst->readNextNPC() != + toPrevStages->stageInfo[stageNum][tid].branchTaken = + inst->readNextNPC() != (inst->readNextPC() + sizeof(TheISA::MachInst)); - toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->bdelaySeqNum; + + toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = + inst->bdelaySeqNum; + InstSeqNum squash_seq_num = inst->bdelaySeqNum; #else - toPrevStages->stageInfo[stageNum][tid].branchTaken = inst->readNextPC() != + toPrevStages->stageInfo[stageNum][tid].branchTaken = + inst->readNextPC() != (inst->readPC() + sizeof(TheISA::MachInst)); + toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->seqNum; InstSeqNum squash_seq_num = inst->seqNum; #endif - DPRINTF(InOrderStage, "Target being re-set to %08p\n", inst->readPredTarg()); - DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], due to [sn:%i] " - "branch.\n", tid, squash_seq_num, inst->seqNum); + DPRINTF(InOrderStage, "Target being re-set to %08p\n", + inst->readPredTarg()); + DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], " + "due to [sn:%i] branch.\n", tid, squash_seq_num, + inst->seqNum); // Save squash num for later stage use cpu->squashSeqNum[tid] = squash_seq_num; @@ -394,8 +408,8 @@ PipelineStage::squash(InstSeqNum squash_seq_num, ThreadID tid) squashPrevStageInsts(squash_seq_num, tid); - DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from incoming stage skidbuffer.\n", - tid); + DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from incoming stage" + " skidbuffer.\n", tid); while (!skidBuffer[tid].empty()) { if (skidBuffer[tid].front()->seqNum <= squash_seq_num) { DPRINTF(InOrderStage, "[tid:%i]: Cannot remove skidBuffer " @@ -404,8 +418,9 @@ PipelineStage::squash(InstSeqNum squash_seq_num, ThreadID tid) skidBuffer[tid].size()); break; } - DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n", - tid, skidBuffer[tid].front()->seqNum, skidBuffer[tid].front()->PC); + DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] " + " PC %08p.\n", tid, skidBuffer[tid].front()->seqNum, + skidBuffer[tid].front()->PC); skidBuffer[tid].pop(); } @@ -427,7 +442,8 @@ PipelineStage::stageBufferAvail() int avail = stageBufferMax - total -0;// incoming_insts; if (avail < 0) - fatal("stageNum %i:stageBufferAvail() < 0...stBMax=%i,total=%i,incoming=%i=>%i", + fatal("stageNum %i:stageBufferAvail() < 0..." + "stBMax=%i,total=%i,incoming=%i=>%i", stageNum, stageBufferMax, total, incoming_insts, avail); return avail; @@ -443,7 +459,8 @@ PipelineStage::canSendInstToStage(unsigned stage_num) } if (!buffer_avail && nextStageQueueValid(stage_num)) { - DPRINTF(InOrderStall, "STALL: No room in stage %i buffer.\n", stageNum + 1); + DPRINTF(InOrderStall, "STALL: No room in stage %i buffer.\n", + stageNum + 1); } return buffer_avail; @@ -461,8 +478,9 @@ PipelineStage::skidInsert(ThreadID tid) assert(tid == inst->threadNumber); - DPRINTF(InOrderStage,"[tid:%i]: Inserting [sn:%lli] PC:%#x into stage skidBuffer %i\n", - tid, inst->seqNum, inst->readPC(), inst->threadNumber); + DPRINTF(InOrderStage,"[tid:%i]: Inserting [sn:%lli] PC:%#x into stage " + "skidBuffer %i\n", tid, inst->seqNum, inst->readPC(), + inst->threadNumber); skidBuffer[tid].push(inst); } @@ -547,16 +565,16 @@ PipelineStage::sortInsts() for (int i = 0; i < insts_from_prev_stage; ++i) { if (prevStage->insts[i]->isSquashed()) { - DPRINTF(InOrderStage, "[tid:%i]: Ignoring squashed [sn:%i], not inserting " - "into stage buffer.\n", + DPRINTF(InOrderStage, "[tid:%i]: Ignoring squashed [sn:%i], " + "not inserting into stage buffer.\n", prevStage->insts[i]->readTid(), prevStage->insts[i]->seqNum); continue; } - DPRINTF(InOrderStage, "[tid:%i]: Inserting [sn:%i] into stage buffer.\n", - prevStage->insts[i]->readTid(), + DPRINTF(InOrderStage, "[tid:%i]: Inserting [sn:%i] into stage " + "buffer.\n", prevStage->insts[i]->readTid(), prevStage->insts[i]->seqNum); ThreadID tid = prevStage->insts[i]->threadNumber; @@ -611,8 +629,8 @@ PipelineStage::checkSignalsAndUpdate(ThreadID tid) // Check for squash from later pipeline stages for (int stage_idx=stageNum; stage_idx < NumStages; stage_idx++) { if (fromNextStages->stageInfo[stage_idx][tid].squash) { - DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to squash " - "from stage %u.\n", tid, stage_idx); + DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to " + "squash from stage %u.\n", tid, stage_idx); InstSeqNum squash_seq_num = fromNextStages-> stageInfo[stage_idx][tid].bdelayDoneSeqNum; squash(squash_seq_num, tid); @@ -625,8 +643,8 @@ PipelineStage::checkSignalsAndUpdate(ThreadID tid) } if (stageStatus[tid] == Blocked) { - DPRINTF(InOrderStage, "[tid:%u]: Done blocking, switching to unblocking.\n", - tid); + DPRINTF(InOrderStage, "[tid:%u]: Done blocking, switching to " + "unblocking.\n", tid); stageStatus[tid] = Unblocking; @@ -637,15 +655,15 @@ PipelineStage::checkSignalsAndUpdate(ThreadID tid) if (stageStatus[tid] == Squashing) { if (!skidBuffer[tid].empty()) { - DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to unblocking.\n", - tid); + DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to " + "unblocking.\n", tid); stageStatus[tid] = Unblocking; } else { // Switch status to running if stage isn't being told to block or // squash this cycle. - DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to running.\n", - tid); + DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to " + "running.\n", tid); stageStatus[tid] = Running; } @@ -717,13 +735,13 @@ PipelineStage::unsetResStall(ResReqPtr res_req, ThreadID tid) } if (stalls[tid].resources.size() == 0) { - DPRINTF(InOrderStage, "[tid:%u]: There are no remaining resource stalls.\n", - tid); + DPRINTF(InOrderStage, "[tid:%u]: There are no remaining resource" + "stalls.\n", tid); } } -// @TODO: Update How we handled threads in CPU. Maybe threads shouldnt be handled -// one at a time, but instead first come first serve by instruction? +// @TODO: Update How we handled threads in CPU. Maybe threads shouldnt be +// handled one at a time, but instead first come first serve by instruction? // Questions are how should a pipeline stage handle thread-specific stalls & // pipeline squashes void @@ -749,8 +767,8 @@ PipelineStage::processStage(bool &status_change) DPRINTF(InOrderStage, "%i left in stage %i incoming buffer.\n", skidSize(), stageNum); - DPRINTF(InOrderStage, "%i available in stage %i incoming buffer.\n", stageBufferAvail(), - stageNum); + DPRINTF(InOrderStage, "%i available in stage %i incoming buffer.\n", + stageBufferAvail(), stageNum); } void @@ -828,8 +846,8 @@ PipelineStage::processInsts(ThreadID tid) inst = insts_to_stage.front(); - DPRINTF(InOrderStage, "[tid:%u]: Processing instruction [sn:%lli] with " - "PC %#x\n", + DPRINTF(InOrderStage, "[tid:%u]: Processing instruction [sn:%lli] " + "with PC %#x\n", tid, inst->seqNum, inst->readPC()); if (inst->isSquashed()) { @@ -856,8 +874,8 @@ PipelineStage::processInsts(ThreadID tid) // Send to Next Stage or Break Loop if (nextStageValid && !sendInstToNextStage(inst)) { - DPRINTF(InOrderStage, "[tid:%i] [sn:%i] unable to proceed to stage %i.\n", - tid, inst->seqNum,inst->nextStage); + DPRINTF(InOrderStage, "[tid:%i] [sn:%i] unable to proceed to stage" + " %i.\n", tid, inst->seqNum,inst->nextStage); break; } @@ -897,14 +915,15 @@ PipelineStage::processInstSchedule(DynInstPtr inst) int res_num = inst->nextResource(); - DPRINTF(InOrderStage, "[tid:%i]: [sn:%i]: sending request to %s.\n", - tid, inst->seqNum, cpu->resPool->name(res_num)); + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i]: sending request to %s." + "\n", tid, inst->seqNum, cpu->resPool->name(res_num)); ResReqPtr req = cpu->resPool->request(res_num, inst); if (req->isCompleted()) { - DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s completed.\n", - tid, inst->seqNum, cpu->resPool->name(res_num)); + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s " + "completed.\n", tid, inst->seqNum, + cpu->resPool->name(res_num)); if (req->fault == NoFault) { inst->popSchedEntry(); @@ -913,8 +932,8 @@ PipelineStage::processInstSchedule(DynInstPtr inst) curTick, req->fault->name()); } } else { - DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed.\n", - tid, inst->seqNum, cpu->resPool->name(res_num)); + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed." + "\n", tid, inst->seqNum, cpu->resPool->name(res_num)); last_req_completed = false; @@ -956,12 +975,12 @@ PipelineStage::sendInstToNextStage(DynInstPtr inst) assert(next_stage >= 1); assert(prev_stage >= 0); - DPRINTF(InOrderStage, "[tid:%u]: Attempting to send instructions to stage %u.\n", tid, - stageNum+1); + DPRINTF(InOrderStage, "[tid:%u]: Attempting to send instructions to " + "stage %u.\n", tid, stageNum+1); if (!canSendInstToStage(inst->nextStage)) { - DPRINTF(InOrderStage, "[tid:%u]: Could not send instruction to stage %u.\n", tid, - stageNum+1); + DPRINTF(InOrderStage, "[tid:%u]: Could not send instruction to " + "stage %u.\n", tid, stageNum+1); return false; } @@ -969,12 +988,14 @@ PipelineStage::sendInstToNextStage(DynInstPtr inst) if (nextStageQueueValid(inst->nextStage - 1)) { if (inst->seqNum > cpu->squashSeqNum[tid] && curTick == cpu->lastSquashCycle[tid]) { - DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping insertion " - "into stage %i queue.\n", tid, inst->seqNum, inst->nextStage); + DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping " + "insertion into stage %i queue.\n", tid, inst->seqNum, + inst->nextStage); } else { if (nextStageValid) { - DPRINTF(InOrderStage, "[tid:%u] %i slots available in next stage buffer.\n", - tid, cpu->pipelineStage[next_stage]->stageBufferAvail()); + DPRINTF(InOrderStage, "[tid:%u] %i slots available in next " + "stage buffer.\n", tid, + cpu->pipelineStage[next_stage]->stageBufferAvail()); } DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into " @@ -982,11 +1003,13 @@ PipelineStage::sendInstToNextStage(DynInstPtr inst) tid, inst->seqNum, toNextStageIndex, cpu->pipelineStage[prev_stage]->nextStageQueue->id()); - int next_stage_idx = cpu->pipelineStage[prev_stage]->nextStage->size; + int next_stage_idx = + cpu->pipelineStage[prev_stage]->nextStage->size; - // Place instructions in inter-stage communication struct for the next + // Place instructions in inter-stage communication struct for next // pipeline stage to read next cycle - cpu->pipelineStage[prev_stage]->nextStage->insts[next_stage_idx] = inst; + cpu->pipelineStage[prev_stage]->nextStage->insts[next_stage_idx] + = inst; ++(cpu->pipelineStage[prev_stage]->nextStage->size); diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh index 86ee98132..42a632560 100644 --- a/src/cpu/inorder/pipeline_stage.hh +++ b/src/cpu/inorder/pipeline_stage.hh @@ -240,6 +240,8 @@ class PipelineStage */ virtual void squashDueToBranch(DynInstPtr &inst, ThreadID tid); + virtual void squashDueToMemStall(DynInstPtr &inst, ThreadID tid); + /** Squash instructions from stage buffer */ virtual void squashPrevStageInsts(InstSeqNum squash_seq_num, ThreadID tid); @@ -259,19 +261,28 @@ class PipelineStage /** List of active thread ids */ std::list *activeThreads; + /** Buffer of instructions switched out to mem-stall. + * Only used when using SwitchOnCacheMiss threading model + * Used as 1-to-1 mapping between ThreadID and Entry. + */ + std::vector switchedOutBuffer; + std::vector switchedOutValid; + /** Queue of all instructions coming from previous stage on this cycle. */ std::queue insts[ThePipeline::MaxThreads]; - /** Queue of instructions that are finished processing and ready to go next stage. - * This is used to prevent from processing an instrution more than once on any - * stage. NOTE: It is up to the PROGRAMMER must manage this as a queue + /** Queue of instructions that are finished processing and ready to go + * next stage. This is used to prevent from processing an instrution more + * than once on any stage. NOTE: It is up to the PROGRAMMER must manage + * this as a queue */ std::list instsToNextStage; /** Skid buffer between previous stage and this one. */ std::queue skidBuffer[ThePipeline::MaxThreads]; - /** Instruction used to signify that there is no *real* instruction in buffer slot */ + /** Instruction used to signify that there is no *real* instruction in + * buffer slot */ DynInstPtr dummyBufferInst; /** SeqNum of Squashing Branch Delay Instruction (used for MIPS) */ -- 2.30.2