From 973d8b8b13b8e4ea178cafa95aaf6538699b8b15 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Tue, 10 Feb 2009 15:49:29 -0800 Subject: InOrder: Import new inorder CPU model from MIPS. This model currently only works in MIPS_SE mode, so it will take some effort to clean it up and make it generally useful. Hopefully people are willing to help make that happen! --- src/cpu/inorder/pipeline_stage.hh | 358 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 src/cpu/inorder/pipeline_stage.hh (limited to 'src/cpu/inorder/pipeline_stage.hh') diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh new file mode 100644 index 000000000..833547704 --- /dev/null +++ b/src/cpu/inorder/pipeline_stage.hh @@ -0,0 +1,358 @@ +/* + * 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_PIPELINE_STAGE_HH__ +#define __CPU_INORDER_PIPELINE_STAGE_HH__ + +#include +#include + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/comm.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/pipeline_traits.hh" + +class InOrderCPU; + +class PipelineStage +{ + protected: + typedef ThePipeline::Params Params; + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + /** Overall stage status. Used to determine if the CPU can + * deschedule itself due to a lack of activity. + */ + enum StageStatus { + Active, + Inactive + }; + + /** Individual thread status. */ + enum ThreadStatus { + Running, + Idle, + StartSquash, + Squashing, + Blocked, + Unblocking, + MemWaitResponse, + MemWaitRetry, + MemAccessComplete + }; + + protected: + /** The Number of This Pipeline Stage */ + unsigned stageNum; + + /** The width of stage, in instructions. */ + unsigned stageWidth; + + /** Number of Threads*/ + unsigned numThreads; + + /** Stage status. */ + StageStatus _status; + + /** Per-thread status. */ + ThreadStatus stageStatus[ThePipeline::MaxThreads]; + + public: + PipelineStage(Params *params, unsigned stage_num); + + /** MUST use init() function if this constructor is used. */ + PipelineStage() { } + + virtual ~PipelineStage() { } + + /** PipelineStage initialization. */ + void init(Params *params, unsigned stage_num); + + /** Returns the name of stage. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Sets CPU pointer. */ + virtual void setCPU(InOrderCPU *cpu_ptr); + + virtual void scheduleStageStart(int delay, int tid) { } + + /** Sets the main backwards communication time buffer pointer. */ + void setTimeBuffer(TimeBuffer *tb_ptr); + + /** Sets pointer to time buffer coming from fetch. */ + void setPrevStageQueue(TimeBuffer *prev_stage_ptr); + + /** Sets pointer to time buffer used to communicate to the next stage. */ + void setNextStageQueue(TimeBuffer *next_stage_ptr); + + /** Sets pointer to list of active threads. */ + void setActiveThreads(std::list *at_ptr); + + bool nextStageQueueValid(int stage_num); + + bool isBlocked(unsigned tid); + + /** Changes the status of this stage to active, and indicates this + * to the CPU. + */ + //inline void switchToActive(); + + /** Changes the status of this stage to inactive, and indicates + * this to the CPU. + */ + //inline void switchToInactive(); + + /** Switches out the stage stage. */ + void switchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Ticks stage, processing all input signals and executing as many + * instructions as possible. + */ + virtual void tick(); + + /** Is out of order processing valid? */ + bool outOfOrderValid(); + + /** Set a resource stall in the pipeline-stage */ + void setResStall(ResReqPtr res_req, unsigned tid); + + /** Unset a resource stall in the pipeline-stage */ + void unsetResStall(ResReqPtr res_req, unsigned tid); + + /** Remove all stall signals for a particular thread; */ + virtual void removeStalls(unsigned tid); + + /** Is there room in the stage buffer? */ + int stageBufferAvail(); + + protected: + /** Evaluate Stage Conditions and then process stage */ + virtual void processStage(bool &status_change); + + /** Determines what to do based on stage's current status. + * @param status_change stage() sets this variable if there was a status + * change (ie switching from from blocking to unblocking). + * @param tid Thread id to stage instructions from. + */ + virtual void processThread(bool &status_change, unsigned tid); + + /** Processes instructions from fetch and passes them on to rename. + * Decoding of instructions actually happens when they are created in + * fetch, so this function mostly checks if PC-relative branches are + * correct. + */ + virtual void processInsts(unsigned tid); + + /** Process all resources on an instruction's resource schedule */ + virtual bool processInstSchedule(DynInstPtr inst); + + /** Is there room in the next stage buffer for this instruction? */ + virtual bool canSendInstToNextStage(); + + /** Send an instruction to the next stage buffer */ + virtual bool sendInstToNextStage(DynInstPtr inst); + + /** Inserts a thread's instructions into the skid buffer, to be staged + * once stage unblocks. + */ + virtual void skidInsert(unsigned tid); + + /** Returns if all of the skid buffers are empty. */ + bool skidsEmpty(); + + /** Updates overall stage status based on all of the threads' statuses. */ + virtual void updateStatus(); + + /** Separates instructions from fetch into individual lists of instructions + * sorted by thread. + */ + void sortInsts(); + + /** Reads all stall signals from the backwards communication timebuffer. */ + virtual void readStallSignals(unsigned tid); + + /** Checks all input signals and updates stage's status appropriately. */ + virtual bool checkSignalsAndUpdate(unsigned tid); + + /** Checks all stall signals, and returns if any are true. */ + virtual bool checkStall(unsigned tid) const; + + /** Returns if there any instructions from the previous stage + * on this cycle. + */ + inline bool prevStageInstsValid(); + + /** Switches stage to blocking, and signals back that stage has + * become blocked. + * @return Returns true if there is a status change. + */ + virtual bool block(unsigned tid); + + void blockDueToBuffer(unsigned tid); + + /** Switches stage to unblocking if the skid buffer is empty, and + * signals back that stage has unblocked. + * @return Returns true if there is a status change. + */ + virtual bool unblock(unsigned tid); + + + public: + /** Squashes if there is a PC-relative branch that was predicted + * incorrectly. Sends squash information back to fetch. + */ + virtual void squashDueToBranch(DynInstPtr &inst, unsigned tid); + + /** Squash instructions from stage buffer */ + virtual void squashPrevStageInsts(InstSeqNum squash_seq_num, unsigned tid); + + /** Squashes due to commit signalling a squash. Changes status to + * squashing and clears block/unblock signals as needed. + */ + virtual void squash(InstSeqNum squash_num, unsigned tid); + + void dumpInsts(); + + protected: + /** CPU interface. */ + InOrderCPU *cpu; + + Trace::InOrderTrace *tracer; + + /** List of active thread ids */ + std::list *activeThreads; + + /** 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 + */ + 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 */ + DynInstPtr dummyBufferInst; + + /** SeqNum of Squashing Branch Delay Instruction (used for MIPS) */ + Addr bdelayDoneSeqNum[ThePipeline::MaxThreads]; + + /** Instruction used for squashing branch (used for MIPS) */ + DynInstPtr squashInst[ThePipeline::MaxThreads]; + + /** Tells when their is a pending delay slot inst. to send + * to rename. If there is, then wait squash after the next + * instruction (used for MIPS). + */ + bool squashAfterDelaySlot[ThePipeline::MaxThreads]; + + /** Maximum size of the inter-stage buffer connecting the previous stage to + * this stage (which we call a skid buffer) */ + unsigned stageBufferMax; + + /** Variable that tracks if stage has written to the time buffer this + * cycle. Used to tell CPU if there is activity this cycle. + */ + bool wroteToTimeBuffer; + + /** Index of instructions being sent to the next stage. */ + unsigned toNextStageIndex; + + /** The last stage that this particular stage should look for stalls */ + int lastStallingStage[ThePipeline::MaxThreads]; + + /** Time buffer interface. */ + TimeBuffer *timeBuffer; + + public: + /** Wire to get rename's output from backwards time buffer. */ + TimeBuffer::wire fromNextStages; + + /** Wire to get iew's information from backwards time buffer. */ + TimeBuffer::wire toPrevStages; + + /** Instruction queue linking previous stage */ + TimeBuffer *prevStageQueue; + + /** Wire to get the previous stage's. */ + TimeBuffer::wire prevStage; + + /** Instruction queue linking next stage */ + TimeBuffer *nextStageQueue; + + /** Wire to write to the next stage */ + TimeBuffer::wire nextStage; + + /** Is Previous Stage Valid? */ + bool prevStageValid; + + /** Is Next Stage Valid? */ + bool nextStageValid; + + /** Source of possible stalls. */ + struct Stalls { + bool stage[ThePipeline::NumStages]; + std::vector resources; + }; + + /** Tracks which stages are telling decode to stall. */ + Stalls stalls[ThePipeline::MaxThreads]; + + //@TODO: Use Stats for the pipeline stages + /** Stat for total number of idle cycles. */ + //Stats::Scalar<> stageIdleCycles; + /** Stat for total number of blocked cycles. */ + //Stats::Scalar<> stageBlockedCycles; + /** Stat for total number of normal running cycles. */ + //Stats::Scalar<> stageRunCycles; + /** Stat for total number of unblocking cycles. */ + //Stats::Scalar<> stageUnblockCycles; + /** Stat for total number of squashing cycles. */ + //Stats::Scalar<> stageSquashCycles; + /** Stat for total number of staged instructions. */ + //Stats::Scalar<> stageProcessedInsts; + /** Stat for total number of squashed instructions. */ + //Stats::Scalar<> stageSquashedInsts; +}; + +#endif -- cgit v1.2.3