diff options
author | Korey Sewell <ksewell@umich.edu> | 2009-02-10 15:49:29 -0800 |
---|---|---|
committer | Korey Sewell <ksewell@umich.edu> | 2009-02-10 15:49:29 -0800 |
commit | 973d8b8b13b8e4ea178cafa95aaf6538699b8b15 (patch) | |
tree | 79321a7384b1fbd183a39e98e28dfa4e9e99d828 /src/cpu/inorder/cpu.hh | |
parent | 36d9065f5f716f88c82a3f4e9a75fa040039aa0a (diff) | |
download | gem5-973d8b8b13b8e4ea178cafa95aaf6538699b8b15.tar.xz |
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!
Diffstat (limited to 'src/cpu/inorder/cpu.hh')
-rw-r--r-- | src/cpu/inorder/cpu.hh | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh new file mode 100644 index 000000000..cd1eb6f92 --- /dev/null +++ b/src/cpu/inorder/cpu.hh @@ -0,0 +1,730 @@ +/* + * 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_CPU_HH__ +#define __CPU_INORDER_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/simple_thread.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/pipeline_stage.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/reg_dep_map.hh" +#include "cpu/o3/dep_graph.hh" +#include "cpu/o3/rename_map.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "mem/request.hh" +#include "sim/eventq.hh" +#include "sim/process.hh" + +class ThreadContext; +class MemInterface; +class MemObject; +class Process; +class ResourcePool; + +class InOrderCPU : public BaseCPU +{ + + protected: + typedef ThePipeline::Params Params; + typedef InOrderThreadState Thread; + + //ISA TypeDefs + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::RegFile RegFile; + typedef SimpleRenameMap RenameMap; + + //DynInstPtr TypeDefs + typedef ThePipeline::DynInstPtr DynInstPtr; + typedef std::list<DynInstPtr>::iterator ListIt; + + //TimeBuffer TypeDefs + typedef TimeBuffer<InterStageStruct> StageQueue; + + friend class Resource; + + public: + /** Constructs a CPU with the given parameters. */ + InOrderCPU(Params *params); + + /** CPU ID */ + int cpu_id; + + /** Type of core that this is */ + std::string coreType; + + int readCpuId() { return cpu_id; } + + void setCpuId(int val) { cpu_id = val; } + + Params *cpu_params; + + TheISA::ITB * itb; + TheISA::DTB * dtb; + + public: + enum Status { + Running, + Idle, + Halted, + Blocked, + SwitchedOut + }; + + /** Overall CPU status. */ + Status _status; + + private: + /** Define TickEvent for the CPU */ + class TickEvent : public Event + { + private: + /** Pointer to the CPU. */ + InOrderCPU *cpu; + + public: + /** Constructs a tick event. */ + TickEvent(InOrderCPU *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. */ + void scheduleTickEvent(int delay) + { + if (tickEvent.squashed()) + mainEventQueue.reschedule(&tickEvent, nextCycle(curTick + ticks(delay))); + else if (!tickEvent.scheduled()) + mainEventQueue.schedule(&tickEvent, nextCycle(curTick + ticks(delay))); + } + + /** Unschedule tick event, regardless of its current state. */ + void unscheduleTickEvent() + { + if (tickEvent.scheduled()) + tickEvent.squash(); + } + + public: + // List of Events That can be scheduled from + // within the CPU. + // NOTE(1): The Resource Pool also uses this event list + // to schedule events broadcast to all resources interfaces + // NOTE(2): CPU Events usually need to schedule a corresponding resource + // pool event. + enum CPUEventType { + ActivateThread, + DeallocateThread, + SuspendThread, + DisableThreads, + EnableThreads, + DisableVPEs, + EnableVPEs, + Trap, + InstGraduated, + SquashAll, + UpdatePCs, + NumCPUEvents + }; + + /** Define CPU Event */ + class CPUEvent : public Event + { + protected: + InOrderCPU *cpu; + + public: + CPUEventType cpuEventType; + unsigned tid; + unsigned vpe; + Fault fault; + + public: + /** Constructs a CPU event. */ + CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, Fault fault, + unsigned _tid, unsigned _vpe); + + /** Set Type of Event To Be Scheduled */ + void setEvent(CPUEventType e_type, Fault _fault, unsigned _tid, unsigned _vpe) + { + fault = _fault; + cpuEventType = e_type; + tid = _tid; + vpe = _vpe; + } + + /** Processes a resource event. */ + virtual void process(); + + /** Returns the description of the resource event. */ + const char *description(); + + /** Schedule Event */ + void scheduleEvent(int delay); + + /** Unschedule This Event */ + void unscheduleEvent(); + }; + + /** Schedule a CPU Event */ + void scheduleCpuEvent(CPUEventType cpu_event, Fault fault, unsigned tid, + unsigned vpe, unsigned delay = 0); + + public: + /** Interface between the CPU and CPU resources. */ + ResourcePool *resPool; + + /** Instruction used to signify that there is no *real* instruction in buffer slot */ + DynInstPtr dummyBufferInst; + + /** Used by resources to signify a denied access to a resource. */ + ResourceRequest *dummyReq; + + /** Identifies the resource id that identifies a fetch + * access unit. + */ + unsigned fetchPortIdx; + + /** Identifies the resource id that identifies a data + * access unit. + */ + unsigned dataPortIdx; + + /** The Pipeline Stages for the CPU */ + PipelineStage *pipelineStage[ThePipeline::NumStages]; + + TheISA::IntReg PC[ThePipeline::MaxThreads]; + TheISA::IntReg nextPC[ThePipeline::MaxThreads]; + TheISA::IntReg nextNPC[ThePipeline::MaxThreads]; + + /** The Register File for the CPU */ + /** @TODO: This regFile wont be a sufficient solution for out-of-order, add register + * files as a resource in order to handle ths problem + */ + TheISA::IntRegFile intRegFile[ThePipeline::MaxThreads];; + TheISA::FloatRegFile floatRegFile[ThePipeline::MaxThreads];; + TheISA::MiscRegFile miscRegFile; + + /** Dependency Tracker for Integer & Floating Point Regs */ + RegDepMap archRegDepMap[ThePipeline::MaxThreads]; + + /** Global communication structure */ + TimeBuffer<TimeStruct> timeBuffer; + + /** Communication structure that sits in between pipeline stages */ + StageQueue *stageQueue[ThePipeline::NumStages-1]; + + public: + + /** Registers statistics. */ + void regStats(); + + /** 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(); + + /** Reset State in the CPU */ + void reset(); + + /** Get a Memory Port */ + Port* getPort(const std::string &if_name, int idx = 0); + + /** trap() - sets up a trap event on the cpuTraps to handle given fault. + * trapCPU() - Traps to handle given fault + */ + void trap(Fault fault, unsigned tid, int delay = 0); + void trapCPU(Fault fault, unsigned tid); + + /** 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); + + /** Add Thread to Active Threads List. */ + void activateContext(unsigned tid, int delay = 0); + void activateThread(unsigned tid); + + /** Remove Thread from Active Threads List */ + void suspendContext(unsigned tid, int delay = 0); + void suspendThread(unsigned tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void deallocateContext(unsigned tid, int delay = 0); + void deallocateThread(unsigned tid); + void deactivateThread(unsigned tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void haltContext(unsigned tid, int delay = 0); + + void removePipelineStalls(unsigned tid); + + void squashThreadInPipeline(unsigned tid); + + /// Notify the CPU to enable a virtual processor element. + virtual void enableVirtProcElement(unsigned vpe); + void enableVPEs(unsigned vpe); + + /// Notify the CPU to disable a virtual processor element. + virtual void disableVirtProcElement(unsigned tid, unsigned vpe); + void disableVPEs(unsigned tid, unsigned vpe); + + /// Notify the CPU that multithreading is enabled. + virtual void enableMultiThreading(unsigned vpe); + void enableThreads(unsigned vpe); + + /// Notify the CPU that multithreading is disabled. + virtual void disableMultiThreading(unsigned tid, unsigned vpe); + void disableThreads(unsigned tid, unsigned vpe); + + // Sets a thread-rescheduling condition. + void setThreadRescheduleCondition(uint32_t tid) + { + //@TODO: IMPLEMENT ME + } + + /** 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(); + + /** Switches a Pipeline Stage to Active. (Unused currently) */ + void switchToActive(int stage_idx) + { /*pipelineStage[stage_idx]->switchToActive();*/ } + + /** Switches out this CPU. (Unused currently) */ + //void switchOut(Sampler *sampler); + + /** Signals to this CPU that a stage has completed switching out. (Unused currently)*/ + void signalSwitched(); + + /** Takes over from another CPU. (Unused currently)*/ + void takeOverFrom(BaseCPU *oldCPU); + + /** Get the current instruction sequence number, and increment it. */ + InstSeqNum getAndIncrementInstSeq(unsigned tid) + { return globalSeqNum[tid]++; } + + /** Get the current instruction sequence number, and increment it. */ + InstSeqNum nextInstSeqNum(unsigned tid) + { return globalSeqNum[tid]; } + + /** Increment Instruction Sequence Number */ + void incrInstSeqNum(unsigned tid) + { globalSeqNum[tid]++; } + + /** Set Instruction Sequence Number */ + void setInstSeqNum(unsigned tid, InstSeqNum seq_num) + { + globalSeqNum[tid] = seq_num; + } + + InstSeqNum getNextEventNum() + { + return cpuEventNum++; + } + + /** Get instruction asid. */ + int getInstAsid(unsigned tid) + { return thread[tid]->getInstAsid(); } + + /** Get data asid. */ + int getDataAsid(unsigned tid) + { return thread[tid]->getDataAsid(); } + + /** Register file accessors */ + uint64_t readIntReg(int reg_idx, unsigned tid); + + FloatReg readFloatReg(int reg_idx, unsigned tid, + int width = TheISA::SingleWidth); + + FloatRegBits readFloatRegBits(int reg_idx, unsigned tid, + int width = TheISA::SingleWidth); + + void setIntReg(int reg_idx, uint64_t val, unsigned tid); + + void setFloatReg(int reg_idx, FloatReg val, unsigned tid, + int width = TheISA::SingleWidth); + + void setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid, + int width = TheISA::SingleWidth); + + /** Reads a miscellaneous register. */ + MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); + + /** Reads a misc. register, including any side effects the read + * might have as defined by the architecture. + */ + MiscReg readMiscReg(int misc_reg, unsigned tid); + + /** Sets a miscellaneous register. */ + void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid); + + /** Sets a misc. register, including any side effects the write + * might have as defined by the architecture. + */ + void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid); + + /** Reads a int/fp/misc reg. from another thread depending on ISA-defined + * target thread + */ + uint64_t readRegOtherThread(unsigned misc_reg, unsigned tid = -1); + + /** Sets a int/fp/misc reg. from another thread depending on an ISA-defined + * target thread + */ + void setRegOtherThread(unsigned misc_reg, const MiscReg &val, unsigned tid); + + /** 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); + + /** Reads the next NPC of a specific thread. */ + uint64_t readNextNPC(unsigned tid); + + /** Sets the next NPC of a specific thread. */ + void setNextNPC(uint64_t val, unsigned tid); + + /** Add Destination Register To Dependency Maps */ + //void addToRegDepMap(DynInstPtr &inst); + + /** Function to add instruction onto the head of the list of the + * instructions. Used when new instructions are fetched. + */ + ListIt addInst(DynInstPtr &inst); + + /** Function to tell the CPU that an instruction has completed. */ + void instDone(DynInstPtr inst, unsigned tid); + + /** Add Instructions to the CPU Remove List*/ + void addToRemoveList(DynInstPtr &inst); + + /** Remove an instruction from CPU */ + void removeInst(DynInstPtr &inst); + + /** Remove all instructions younger than the given sequence number. */ + void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid); + + /** Removes the instruction pointed to by the iterator. */ + inline void squashInstIt(const ListIt &instIt, const unsigned &tid); + + /** Cleans up all instructions on the instruction remove list. */ + void cleanUpRemovedInsts(); + + /** Cleans up all instructions on the request remove list. */ + void cleanUpRemovedReqs(); + + /** Cleans up all instructions on the CPU event remove list. */ + void cleanUpRemovedEvents(); + + /** Debug function to print all instructions on the list. */ + void dumpInsts(); + + /** Translates instruction requestion in syscall emulation mode. */ + Fault translateInstReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Translates data read request in syscall emulation mode. */ + Fault translateDataReadReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Translates data write request in syscall emulation mode. */ + Fault translateDataWriteReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Forwards an instruction read to the appropriate data + * resource (indexes into Resource Pool thru "dataPortIdx") + */ + Fault read(DynInstPtr inst); + + /** Forwards an instruction write. to the appropriate data + * resource (indexes into Resource Pool thru "dataPortIdx") + */ + Fault write(DynInstPtr inst); + + /** Executes a syscall.*/ + void syscall(int64_t callnum, int tid); + + /** Gets a syscall argument. */ + IntReg getSyscallArg(int i, int tid); + + /** Used to shift args for indirect syscall. */ + void setSyscallArg(int i, IntReg val, int tid); + + /** Sets the return value of a syscall. */ + void setSyscallReturn(SyscallReturn return_value, int tid); + + public: + /** Per-Thread List of all the instructions in flight. */ + std::list<DynInstPtr> instList[ThePipeline::MaxThreads]; + + /** List of all the instructions that will be removed at the end of this + * cycle. + */ + std::queue<ListIt> removeList; + + /** List of all the resource requests that will be removed at the end of this + * cycle. + */ + std::queue<ResourceRequest*> reqRemoveList; + + /** List of all the cpu event requests that will be removed at the end of + * the current cycle. + */ + std::queue<Event*> cpuEventRemoveList; + +#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; + + /** True if there is non-speculative Inst Active In Pipeline. Lets any + * execution unit know, NOT to execute while the instruction is active. + */ + bool nonSpecInstActive[ThePipeline::MaxThreads]; + + /** Instruction Seq. Num of current non-speculative instruction. */ + InstSeqNum nonSpecSeqNum[ThePipeline::MaxThreads]; + + /** Instruction Seq. Num of last instruction squashed in pipeline */ + InstSeqNum squashSeqNum[ThePipeline::MaxThreads]; + + /** Last Cycle that the CPU squashed instruction end. */ + Tick lastSquashCycle[ThePipeline::MaxThreads]; + + std::list<unsigned> fetchPriorityList; + + /** Rename Map for architectural-to-physical register mappings. + * In a In-order processor, the mapping is fixed + * (e.g. Thread 1: 0-31, Thread 1: 32-63, etc.) + * In a Out-of-Order processor, this is used to maintain + * sequential consistency (?right word here?). + */ + RenameMap renameMap[ThePipeline::MaxThreads]; + + protected: + /** Active Threads List */ + std::list<unsigned> activeThreads; + + /** Current Threads List */ + std::list<unsigned> currentThreads; + + /** Suspended Threads List */ + std::list<unsigned> suspendedThreads; + + /** Thread Status Functions (Unused Currently) */ + bool isThreadInCPU(unsigned tid); + bool isThreadActive(unsigned tid); + bool isThreadSuspended(unsigned tid); + void addToCurrentThreads(unsigned tid); + void removeFromCurrentThreads(unsigned tid); + + 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: + void readFunctional(Addr addr, uint32_t &buffer); + + /** Number of Active Threads in the CPU */ + int numActiveThreads() { return activeThreads.size(); } + + /** Records that there was time buffer activity this cycle. */ + void activityThisCycle() { activityRec.activity(); } + + /** Changes a stage's status to active within the activity recorder. */ + void activateStage(const int idx) + { activityRec.activateStage(idx); } + + /** Changes a stage's status to inactive within the activity recorder. */ + void deactivateStage(const int idx) + { activityRec.deactivateStage(idx); } + + /** 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(); + + // LL/SC debug functionality + unsigned stCondFails; + unsigned readStCondFailures() { return stCondFails; } + unsigned setStCondFailures(unsigned st_fails) { return stCondFails = st_fails; } + + public: + /** Returns a pointer to a thread context. */ + ThreadContext *tcBase(unsigned tid = 0) + { + return thread[tid]->getTC(); + } + + /** The global sequence number counter. */ + InstSeqNum globalSeqNum[ThePipeline::MaxThreads]; + + /** The global event number counter. */ + InstSeqNum cpuEventNum; + + /** Counter of how many stages have completed switching out. */ + int switchCount; + + /** 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; + + /** Per-Stage Instruction Tracing */ + bool stageTracing; + + /** 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 the CPU can process */ + unsigned numThreads; + + /** Number of Virtual Processors the CPU can process */ + unsigned numVirtProcs; + + /** Update Thread , used for statistic purposes*/ + inline void tickThreadStats(); + + /** Per-Thread Tick */ + Stats::Vector<> threadCycles; + + /** Tick for SMT */ + Stats::Scalar<> smtCycles; + + /** 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 number of committed instructions per thread. */ + Stats::Vector<> smtCommittedInsts; + + /** Stat for the total number of committed instructions. */ + Stats::Scalar<> totalCommittedInsts; + + /** Stat for the CPI per thread. */ + Stats::Formula cpi; + + /** Stat for the SMT-CPI per thread. */ + Stats::Formula smtCpi; + + /** Stat for the total CPI. */ + Stats::Formula totalCpi; + + /** Stat for the IPC per thread. */ + Stats::Formula ipc; + + /** Stat for the total IPC. */ + Stats::Formula smtIpc; + + /** Stat for the total IPC. */ + Stats::Formula totalIpc; +}; + +#endif // __CPU_O3_CPU_HH__ |