summaryrefslogtreecommitdiff
path: root/src/cpu/o3/cpu.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/o3/cpu.hh')
-rw-r--r--src/cpu/o3/cpu.hh412
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 &params);
-#else
- BaseFullCPU(Params &params);
-#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 &params);
+ /** 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__