diff options
Diffstat (limited to 'src/cpu/o3/cpu.hh')
-rw-r--r-- | src/cpu/o3/cpu.hh | 412 |
1 files changed, 293 insertions, 119 deletions
diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index f7c80e8a1..ff41a3306 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -24,33 +24,36 @@ * 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: Kevin Lim */ -//Todo: Add in a lot of the functions that are ISA specific. Also define -//the functions that currently exist within the base cpu class. Define -//everything for the simobject stuff so it can be serialized and -//instantiated, add in debugging statements everywhere. Have CPU schedule -//itself properly. Threads! -// Avoid running stages and advancing queues if idle/stalled. - -#ifndef __CPU_O3_CPU_FULL_CPU_HH__ -#define __CPU_O3_CPU_FULL_CPU_HH__ +#ifndef __CPU_O3_CPU_HH__ +#define __CPU_O3_CPU_HH__ #include <iostream> #include <list> +#include <queue> +#include <set> #include <vector> +#include "arch/isa_traits.hh" #include "base/statistics.hh" #include "base/timebuf.hh" #include "config/full_system.hh" +#include "cpu/activity.hh" #include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" +#include "cpu/simple_thread.hh" #include "cpu/o3/comm.hh" #include "cpu/o3/cpu_policy.hh" +#include "cpu/o3/scoreboard.hh" +#include "cpu/o3/thread_state.hh" #include "sim/process.hh" -class ExecContext; -class FunctionalMemory; +template <class> +class Checker; +class ThreadContext; +class MemObject; class Process; class BaseFullCPU : public BaseCPU @@ -59,59 +62,79 @@ class BaseFullCPU : public BaseCPU public: typedef BaseCPU::Params Params; -#if FULL_SYSTEM - BaseFullCPU(Params ¶ms); -#else - BaseFullCPU(Params ¶ms); -#endif // FULL_SYSTEM + BaseFullCPU(Params *params); + + void regStats(); + + int readCpuId() { return cpu_id; } protected: int cpu_id; }; +/** + * FullO3CPU class, has each of the stages (fetch through commit) + * within it, as well as all of the time buffers between stages. The + * tick() function for the CPU is defined here. + */ template <class Impl> class FullO3CPU : public BaseFullCPU { public: - //Put typedefs from the Impl here. + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + + // Typedefs from the Impl here. typedef typename Impl::CPUPol CPUPolicy; typedef typename Impl::Params Params; typedef typename Impl::DynInstPtr DynInstPtr; + typedef O3ThreadState<Impl> Thread; + + typedef typename std::list<DynInstPtr>::iterator ListIt; + public: enum Status { Running, Idle, Halted, - Blocked // ? + Blocked, + SwitchedOut }; + /** Overall CPU status. */ Status _status; private: class TickEvent : public Event { private: + /** Pointer to the CPU. */ FullO3CPU<Impl> *cpu; public: + /** Constructs a tick event. */ TickEvent(FullO3CPU<Impl> *c); + + /** Processes a tick event, calling tick() on the CPU. */ void process(); + /** Returns the description of the tick event. */ const char *description(); }; + /** The tick event used for scheduling CPU ticks. */ TickEvent tickEvent; - /// Schedule tick event, regardless of its current state. + /** Schedule tick event, regardless of its current state. */ void scheduleTickEvent(int delay) { if (tickEvent.squashed()) - tickEvent.reschedule(curTick + delay); + tickEvent.reschedule(curTick + cycles(delay)); else if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + delay); + tickEvent.schedule(curTick + cycles(delay)); } - /// Unschedule tick event, regardless of its current state. + /** Unschedule tick event, regardless of its current state. */ void unscheduleTickEvent() { if (tickEvent.scheduled()) @@ -119,25 +142,83 @@ class FullO3CPU : public BaseFullCPU } public: - FullO3CPU(Params ¶ms); + /** Constructs a CPU with the given parameters. */ + FullO3CPU(Params *params); + /** Destructor. */ ~FullO3CPU(); + /** Registers statistics. */ void fullCPURegStats(); + /** Ticks CPU, calling tick() on each stage, and checking the overall + * activity to see if the CPU should deschedule itself. + */ void tick(); + /** Initialize the CPU */ void init(); - void activateContext(int thread_num, int delay); - void suspendContext(int thread_num); - void deallocateContext(int thread_num); - void haltContext(int thread_num); + /** Setup CPU to insert a thread's context */ + void insertThread(unsigned tid); + + /** Remove all of a thread's context from CPU */ + void removeThread(unsigned tid); + + /** Count the Total Instructions Committed in the CPU. */ + virtual Counter totalInstructions() const + { + Counter total(0); + + for (int i=0; i < thread.size(); i++) + total += thread[i]->numInst; + + return total; + } + + /** Add Thread to Active Threads List. */ + void activateContext(int tid, int delay); + + /** Remove Thread from Active Threads List */ + void suspendContext(int tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void deallocateContext(int tid); - void switchOut(); + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void haltContext(int tid); + + /** Activate a Thread When CPU Resources are Available. */ + void activateWhenReady(int tid); + + /** Add or Remove a Thread Context in the CPU. */ + void doContextSwitch(); + + /** Update The Order In Which We Process Threads. */ + void updateThreadPriority(); + + /** Executes a syscall on this cycle. + * --------------------------------------- + * Note: this is a virtual function. CPU-Specific + * functionality defined in derived classes + */ + virtual void syscall(int tid) { panic("Unimplemented!"); } + + /** Switches out this CPU. */ + void switchOut(Sampler *sampler); + + /** Signals to this CPU that a stage has completed switching out. */ + void signalSwitched(); + + /** Takes over from another CPU. */ void takeOverFrom(BaseCPU *oldCPU); /** Get the current instruction sequence number, and increment it. */ - InstSeqNum getAndIncrementInstSeq(); + InstSeqNum getAndIncrementInstSeq() + { return globalSeqNum++; } #if FULL_SYSTEM /** Check if this address is a valid instruction address. */ @@ -147,27 +228,24 @@ class FullO3CPU : public BaseFullCPU bool validDataAddr(Addr addr) { return true; } /** Get instruction asid. */ - int getInstAsid() - { return regFile.miscRegs.getInstAsid(); } + int getInstAsid(unsigned tid) + { return regFile.miscRegs[tid].getInstAsid(); } /** Get data asid. */ - int getDataAsid() - { return regFile.miscRegs.getDataAsid(); } + int getDataAsid(unsigned tid) + { return regFile.miscRegs[tid].getDataAsid(); } #else - bool validInstAddr(Addr addr) - { return thread[0]->validInstAddr(addr); } - - bool validDataAddr(Addr addr) - { return thread[0]->validDataAddr(addr); } + /** Get instruction asid. */ + int getInstAsid(unsigned tid) + { return thread[tid]->getInstAsid(); } - int getInstAsid() { return thread[0]->getInstAsid(); } - int getDataAsid() { return thread[0]->getDataAsid(); } + /** Get data asid. */ + int getDataAsid(unsigned tid) + { return thread[tid]->getDataAsid(); } #endif - // - // New accessors for new decoder. - // + /** Register accessors. Index refers to the physical register index. */ uint64_t readIntReg(int reg_idx); FloatReg readFloatReg(int reg_idx); @@ -180,103 +258,115 @@ class FullO3CPU : public BaseFullCPU void setIntReg(int reg_idx, uint64_t val); - void setFloatReg(int reg_idx, FloatReg val, int width); + void setFloatReg(int reg_idx, FloatReg val); void setFloatReg(int reg_idx, FloatReg val, int width); void setFloatRegBits(int reg_idx, FloatRegBits val); - void setFloatRegBits(int reg_idx, FloatRegBits val); + void setFloatRegBits(int reg_idx, FloatRegBits val, int width); + + uint64_t readArchIntReg(int reg_idx, unsigned tid); + + float readArchFloatRegSingle(int reg_idx, unsigned tid); + + double readArchFloatRegDouble(int reg_idx, unsigned tid); + + uint64_t readArchFloatRegInt(int reg_idx, unsigned tid); + + /** Architectural register accessors. Looks up in the commit + * rename table to obtain the true physical index of the + * architected register first, then accesses that physical + * register. + */ + void setArchIntReg(int reg_idx, uint64_t val, unsigned tid); + + void setArchFloatRegSingle(int reg_idx, float val, unsigned tid); - uint64_t readPC(); + void setArchFloatRegDouble(int reg_idx, double val, unsigned tid); - void setNextPC(uint64_t val); + void setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid); - void setPC(Addr new_PC); + /** Reads the commit PC of a specific thread. */ + uint64_t readPC(unsigned tid); + + /** Sets the commit PC of a specific thread. */ + void setPC(Addr new_PC, unsigned tid); + + /** Reads the next PC of a specific thread. */ + uint64_t readNextPC(unsigned tid); + + /** Sets the next PC of a specific thread. */ + void setNextPC(uint64_t val, unsigned tid); /** Function to add instruction onto the head of the list of the * instructions. Used when new instructions are fetched. */ - void addInst(DynInstPtr &inst); + ListIt addInst(DynInstPtr &inst); /** Function to tell the CPU that an instruction has completed. */ - void instDone(); - - /** Remove all instructions in back of the given instruction, but leave - * that instruction in the list. This is useful in a squash, when there - * are instructions in this list that don't exist in structures such as - * the ROB. The instruction doesn't have to be the last instruction in - * the list, but will be once this function completes. - * @todo: Remove only up until that inst? Squashed inst is most likely - * valid. - */ - void removeBackInst(DynInstPtr &inst); - - /** Remove an instruction from the front of the list. It is expected - * that there are no instructions in front of it (that is, none are older - * than the instruction being removed). Used when retiring instructions. - * @todo: Remove the argument to this function, and just have it remove - * last instruction once it's verified that commit has the same ordering - * as the instruction list. + void instDone(unsigned tid); + + /** Add Instructions to the CPU Remove List*/ + void addToRemoveList(DynInstPtr &inst); + + /** Remove an instruction from the front end of the list. There's + * no restriction on location of the instruction. */ void removeFrontInst(DynInstPtr &inst); /** Remove all instructions that are not currently in the ROB. */ - void removeInstsNotInROB(); + void removeInstsNotInROB(unsigned tid); /** Remove all instructions younger than the given sequence number. */ - void removeInstsUntil(const InstSeqNum &seq_num); + void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid); - /** Remove all instructions from the list. */ - void removeAllInsts(); + /** Removes the instruction pointed to by the iterator. */ + inline void squashInstIt(const ListIt &instIt, const unsigned &tid); - void dumpInsts(); + /** Cleans up all instructions on the remove list. */ + void cleanUpRemovedInsts(); - /** Basically a wrapper function so that instructions executed at - * commit can tell the instruction queue that they have completed. - * Eventually this hack should be removed. - */ - void wakeDependents(DynInstPtr &inst); + /** Debug function to print all instructions on the list. */ + void dumpInsts(); public: /** List of all the instructions in flight. */ - list<DynInstPtr> instList; + std::list<DynInstPtr> instList; + + /** List of all the instructions that will be removed at the end of this + * cycle. + */ + std::queue<ListIt> removeList; + +#ifdef DEBUG + /** Debug structure to keep track of the sequence numbers still in + * flight. + */ + std::set<InstSeqNum> snList; +#endif + + /** Records if instructions need to be removed this cycle due to + * being retired or squashed. + */ + bool removeInstsThisCycle; - //not sure these should be private. protected: /** The fetch stage. */ typename CPUPolicy::Fetch fetch; - /** The fetch stage's status. */ - typename CPUPolicy::Fetch::Status fetchStatus; - /** The decode stage. */ typename CPUPolicy::Decode decode; - /** The decode stage's status. */ - typename CPUPolicy::Decode::Status decodeStatus; - /** The dispatch stage. */ typename CPUPolicy::Rename rename; - /** The dispatch stage's status. */ - typename CPUPolicy::Rename::Status renameStatus; - /** The issue/execute/writeback stages. */ typename CPUPolicy::IEW iew; - /** The issue/execute/writeback stage's status. */ - typename CPUPolicy::IEW::Status iewStatus; - /** The commit stage. */ typename CPUPolicy::Commit commit; - /** The fetch stage's status. */ - typename CPUPolicy::Commit::Status commitStatus; - - //Might want to just pass these objects in to the constructors of the - //appropriate stage. regFile is in iew, freeList in dispatch, renameMap - //in dispatch, and the rob in commit. /** The register file. */ typename CPUPolicy::RegFile regFile; @@ -284,12 +374,33 @@ class FullO3CPU : public BaseFullCPU typename CPUPolicy::FreeList freeList; /** The rename map. */ - typename CPUPolicy::RenameMap renameMap; + typename CPUPolicy::RenameMap renameMap[Impl::MaxThreads]; + + /** The commit rename map. */ + typename CPUPolicy::RenameMap commitRenameMap[Impl::MaxThreads]; /** The re-order buffer. */ typename CPUPolicy::ROB rob; + /** Active Threads List */ + std::list<unsigned> activeThreads; + + /** Integer Register Scoreboard */ + Scoreboard scoreboard; + public: + /** Enum to give each stage a specific index, so when calling + * activateStage() or deactivateStage(), they can specify which stage + * is being activated/deactivated. + */ + enum StageIdx { + FetchIdx, + DecodeIdx, + RenameIdx, + IEWIdx, + CommitIdx, + NumStages }; + /** Typedefs from the Impl to get the structs that each of the * time buffers should use. */ @@ -318,46 +429,109 @@ class FullO3CPU : public BaseFullCPU /** The IEW stage's instruction queue. */ TimeBuffer<IEWStruct> iewQueue; + private: + /** The activity recorder; used to tell if the CPU has any + * activity remaining or if it can go to idle and deschedule + * itself. + */ + ActivityRecorder activityRec; + public: - /** The temporary exec context to support older accessors. */ - CPUExecContext *cpuXC; + /** Records that there was time buffer activity this cycle. */ + void activityThisCycle() { activityRec.activity(); } - /** Temporary function to get pointer to exec context. */ - ExecContext *xcBase() - { - return thread[0]->getProxy(); - } + /** Changes a stage's status to active within the activity recorder. */ + void activateStage(const StageIdx idx) + { activityRec.activateStage(idx); } + + /** Changes a stage's status to inactive within the activity recorder. */ + void deactivateStage(const StageIdx idx) + { activityRec.deactivateStage(idx); } - CPUExecContext *cpuXCBase() + /** Wakes the CPU, rescheduling the CPU if it's not already active. */ + void wakeCPU(); + + /** Gets a free thread id. Use if thread ids change across system. */ + int getFreeTid(); + + public: + /** Returns a pointer to a thread context. */ + ThreadContext *tcBase(unsigned tid) { - return thread[0]; + return thread[tid]->getTC(); } + /** The global sequence number counter. */ InstSeqNum globalSeqNum; + /** Pointer to the checker, which can dynamically verify + * instruction results at run time. This can be set to NULL if it + * is not being used. + */ + Checker<DynInstPtr> *checker; + #if FULL_SYSTEM + /** Pointer to the system. */ System *system; - MemoryController *memCtrl; + /** Pointer to physical memory. */ PhysicalMemory *physmem; +#endif - AlphaITB *itb; - AlphaDTB *dtb; + /** Pointer to memory. */ + MemObject *mem; -// SWContext *swCtx; -#endif - std::vector<CPUExecContext *> thread; + /** Pointer to the sampler */ + Sampler *sampler; + + /** Counter of how many stages have completed switching out. */ + int switchCount; - FunctionalMemory *mem; + /** Pointers to all of the threads in the CPU. */ + std::vector<Thread *> thread; + /** Pointer to the icache interface. */ MemInterface *icacheInterface; + /** Pointer to the dcache interface. */ MemInterface *dcacheInterface; + /** Whether or not the CPU should defer its registration. */ bool deferRegistration; - Counter numInsts; - - Counter funcExeInst; + /** Is there a context switch pending? */ + bool contextSwitch; + + /** Threads Scheduled to Enter CPU */ + std::list<int> cpuWaitList; + + /** The cycle that the CPU was last running, used for statistics. */ + Tick lastRunningCycle; + + /** Number of Threads CPU can process */ + unsigned numThreads; + + /** Mapping for system thread id to cpu id */ + std::map<unsigned,unsigned> threadMap; + + /** Available thread ids in the cpu*/ + std::vector<unsigned> tids; + + /** Stat for total number of times the CPU is descheduled. */ + Stats::Scalar<> timesIdled; + /** Stat for total number of cycles the CPU spends descheduled. */ + Stats::Scalar<> idleCycles; + /** Stat for the number of committed instructions per thread. */ + Stats::Vector<> committedInsts; + /** Stat for the total number of committed instructions. */ + Stats::Scalar<> totalCommittedInsts; + /** Stat for the CPI per thread. */ + Stats::Formula cpi; + /** Stat for the total CPI. */ + Stats::Formula totalCpi; + /** Stat for the IPC per thread. */ + Stats::Formula ipc; + /** Stat for the total IPC. */ + Stats::Formula totalIpc; }; -#endif +#endif // __CPU_O3_CPU_HH__ |