/*
- * Copyright (c) 2011-2012 ARM Limited
+ * Copyright (c) 2011-2013, 2016-2019 ARM Limited
+ * Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved
*
* The license below extends only to copyright in the software and shall
#include <set>
#include <vector>
+#include "arch/generic/types.hh"
#include "arch/types.hh"
#include "base/statistics.hh"
#include "config/the_isa.hh"
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::O3CPU O3CPU;
+ using VecElem = TheISA::VecElem;
+ using VecRegContainer = TheISA::VecRegContainer;
+
+ using VecPredRegContainer = TheISA::VecPredRegContainer;
+
typedef O3ThreadState<Impl> ImplState;
typedef O3ThreadState<Impl> Thread;
SwitchedOut
};
- TheISA::TLB * itb;
- TheISA::TLB * dtb;
+ BaseTLB *itb;
+ BaseTLB *dtb;
+ using LSQRequest = typename LSQ<Impl>::LSQRequest;
/** Overall CPU status. */
Status _status;
/**
* IcachePort class for instruction fetch.
*/
- class IcachePort : public CpuPort
+ class IcachePort : public MasterPort
{
protected:
/** Pointer to fetch. */
public:
/** Default constructor. */
IcachePort(DefaultFetch<Impl> *_fetch, FullO3CPU<Impl>* _cpu)
- : CpuPort(_cpu->name() + ".icache_port", _cpu), fetch(_fetch)
+ : MasterPort(_cpu->name() + ".icache_port", _cpu), fetch(_fetch)
{ }
protected:
/** Timing version of receive. Handles setting fetch to the
* proper status to start fetching. */
virtual bool recvTimingResp(PacketPtr pkt);
- virtual void recvTimingSnoopReq(PacketPtr pkt) { }
/** Handles doing a retry of a failed fetch. */
- virtual void recvRetry();
+ virtual void recvReqRetry();
};
/**
* DcachePort class for the load/store queue.
*/
- class DcachePort : public CpuPort
+ class DcachePort : public MasterPort
{
protected:
/** Pointer to LSQ. */
LSQ<Impl> *lsq;
+ FullO3CPU<Impl> *cpu;
public:
/** Default constructor. */
DcachePort(LSQ<Impl> *_lsq, FullO3CPU<Impl>* _cpu)
- : CpuPort(_cpu->name() + ".dcache_port", _cpu), lsq(_lsq)
+ : MasterPort(_cpu->name() + ".dcache_port", _cpu), lsq(_lsq),
+ cpu(_cpu)
{ }
protected:
virtual bool recvTimingResp(PacketPtr pkt);
virtual void recvTimingSnoopReq(PacketPtr pkt);
+ virtual void recvFunctionalSnoop(PacketPtr pkt)
+ {
+ // @todo: Is there a need for potential invalidation here?
+ }
+
/** Handles doing a retry of the previous send. */
- virtual void recvRetry();
+ virtual void recvReqRetry();
/**
* As this CPU requires snooping to maintain the load store queue
virtual bool isSnooping() const { return true; }
};
- 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() const;
- };
-
/** The tick event used for scheduling CPU ticks. */
- TickEvent tickEvent;
+ EventFunctionWrapper tickEvent;
+
+ /** The exit event used for terminating all ready-to-exit threads */
+ EventFunctionWrapper threadExitEvent;
/** Schedule tick event, regardless of its current state. */
void scheduleTickEvent(Cycles delay)
tickEvent.squash();
}
- class ActivateThreadEvent : public Event
- {
- private:
- /** Number of Thread to Activate */
- ThreadID tid;
-
- /** Pointer to the CPU. */
- FullO3CPU<Impl> *cpu;
-
- public:
- /** Constructs the event. */
- ActivateThreadEvent();
-
- /** Initialize Event */
- void init(int thread_num, FullO3CPU<Impl> *thread_cpu);
-
- /** Processes the event, calling activateThread() on the CPU. */
- void process();
-
- /** Returns the description of the event. */
- const char *description() const;
- };
-
- /** Schedule thread to activate , regardless of its current state. */
- void
- scheduleActivateThreadEvent(ThreadID tid, Cycles delay)
- {
- // Schedule thread to activate, regardless of its current state.
- if (activateThreadEvent[tid].squashed())
- reschedule(activateThreadEvent[tid],
- clockEdge(delay));
- else if (!activateThreadEvent[tid].scheduled()) {
- Tick when = clockEdge(delay);
-
- // Check if the deallocateEvent is also scheduled, and make
- // sure they do not happen at same time causing a sleep that
- // is never woken from.
- if (deallocateContextEvent[tid].scheduled() &&
- deallocateContextEvent[tid].when() == when) {
- when++;
- }
-
- schedule(activateThreadEvent[tid], when);
- }
- }
-
- /** Unschedule actiavte thread event, regardless of its current state. */
- void
- unscheduleActivateThreadEvent(ThreadID tid)
- {
- if (activateThreadEvent[tid].scheduled())
- activateThreadEvent[tid].squash();
- }
-
- /** The tick event used for scheduling CPU ticks. */
- ActivateThreadEvent activateThreadEvent[Impl::MaxThreads];
-
- class DeallocateContextEvent : public Event
- {
- private:
- /** Number of Thread to deactivate */
- ThreadID tid;
-
- /** Should the thread be removed from the CPU? */
- bool remove;
-
- /** Pointer to the CPU. */
- FullO3CPU<Impl> *cpu;
-
- public:
- /** Constructs the event. */
- DeallocateContextEvent();
-
- /** Initialize Event */
- void init(int thread_num, FullO3CPU<Impl> *thread_cpu);
-
- /** Processes the event, calling activateThread() on the CPU. */
- void process();
-
- /** Sets whether the thread should also be removed from the CPU. */
- void setRemove(bool _remove) { remove = _remove; }
-
- /** Returns the description of the event. */
- const char *description() const;
- };
-
- /** Schedule cpu to deallocate thread context.*/
- void
- scheduleDeallocateContextEvent(ThreadID tid, bool remove, Cycles delay)
- {
- // Schedule thread to activate, regardless of its current state.
- if (deallocateContextEvent[tid].squashed())
- reschedule(deallocateContextEvent[tid],
- clockEdge(delay));
- else if (!deallocateContextEvent[tid].scheduled())
- schedule(deallocateContextEvent[tid],
- clockEdge(delay));
- }
-
- /** Unschedule thread deallocation in CPU */
- void
- unscheduleDeallocateContextEvent(ThreadID tid)
- {
- if (deallocateContextEvent[tid].scheduled())
- deallocateContextEvent[tid].squash();
- }
-
- /** The tick event used for scheduling CPU ticks. */
- DeallocateContextEvent deallocateContextEvent[Impl::MaxThreads];
-
/**
- * Check if the pipeline has drained and signal the DrainManager.
+ * Check if the pipeline has drained and signal drain done.
*
* This method checks if a drain has been requested and if the CPU
* has drained successfully (i.e., there are no instructions in
~FullO3CPU();
/** Registers statistics. */
- void regStats();
+ void regStats() override;
+
+ ProbePointArg<PacketPtr> *ppInstAccessComplete;
+ ProbePointArg<std::pair<DynInstPtr, PacketPtr> > *ppDataAccessComplete;
+
+ /** Register probe points. */
+ void regProbePoints() override;
void demapPage(Addr vaddr, uint64_t asn)
{
void tick();
/** Initialize the CPU */
- void init();
+ void init() override;
- void startup();
+ void startup() override;
/** Returns the Number of Active Threads in the CPU */
int numActiveThreads()
void removeThread(ThreadID tid);
/** Count the Total Instructions Committed in the CPU. */
- virtual Counter totalInsts() const;
+ Counter totalInsts() const override;
/** Count the Total Ops (including micro ops) committed in the CPU. */
- virtual Counter totalOps() const;
+ Counter totalOps() const override;
/** Add Thread to Active Threads List. */
- void activateContext(ThreadID tid, Cycles delay);
+ void activateContext(ThreadID tid) override;
/** Remove Thread from Active Threads List */
- void suspendContext(ThreadID tid);
-
- /** Remove Thread from Active Threads List &&
- * Possibly Remove Thread Context from CPU.
- */
- bool scheduleDeallocateContext(ThreadID tid, bool remove,
- Cycles delay = Cycles(1));
+ void suspendContext(ThreadID tid) override;
/** Remove Thread from Active Threads List &&
* Remove Thread Context from CPU.
*/
- void haltContext(ThreadID tid);
-
- /** Activate a Thread When CPU Resources are Available. */
- void activateWhenReady(ThreadID tid);
-
- /** Add or Remove a Thread Context in the CPU. */
- void doContextSwitch();
+ void haltContext(ThreadID tid) override;
/** Update The Order In Which We Process Threads. */
void updateThreadPriority();
/** Is the CPU draining? */
- bool isDraining() const { return getDrainState() == Drainable::Draining; }
+ bool isDraining() const { return drainState() == DrainState::Draining; }
+
+ void serializeThread(CheckpointOut &cp, ThreadID tid) const override;
+ void unserializeThread(CheckpointIn &cp, ThreadID tid) override;
+
+ /** Insert tid to the list of threads trying to exit */
+ void addThreadToExitingList(ThreadID tid);
+
+ /** Is the thread trying to exit? */
+ bool isThreadExiting(ThreadID tid) const;
- /** Serialize state. */
- virtual void serialize(std::ostream &os);
+ /**
+ * If a thread is trying to exit and its corresponding trap event
+ * has been completed, schedule an event to terminate the thread.
+ */
+ void scheduleThreadExitEvent(ThreadID tid);
- /** Unserialize from a checkpoint. */
- virtual void unserialize(Checkpoint *cp, const std::string §ion);
+ /** Terminate all threads that are ready to exit */
+ void exitThreads();
public:
/** Executes a syscall.
* @todo: Determine if this needs to be virtual.
*/
- void syscall(int64_t callnum, ThreadID tid);
+ void syscall(int64_t callnum, ThreadID tid, Fault *fault);
/** Starts draining the CPU's pipeline of all instructions in
* order to stop all memory accesses. */
- unsigned int drain(DrainManager *drain_manager);
+ DrainState drain() override;
/** Resumes execution after a drain. */
- void drainResume();
+ void drainResume() override;
/**
* Commit has reached a safe point to drain a thread.
void commitDrained(ThreadID tid);
/** Switches out this CPU. */
- virtual void switchOut();
+ void switchOut() override;
/** Takes over from another CPU. */
- virtual void takeOverFrom(BaseCPU *oldCPU);
+ void takeOverFrom(BaseCPU *oldCPU) override;
+
+ void verifyMemoryMode() const override;
/** Get the current instruction sequence number, and increment it. */
InstSeqNum getAndIncrementInstSeq()
{ return globalSeqNum++; }
/** Traps to handle given fault. */
- void trap(Fault fault, ThreadID tid, StaticInstPtr inst);
+ void trap(const Fault &fault, ThreadID tid, const StaticInstPtr &inst);
/** HW return from error interrupt. */
Fault hwrei(ThreadID tid);
bool simPalCheck(int palFunc, ThreadID tid);
+ /** Check if a change in renaming is needed for vector registers.
+ * The vecMode variable is updated and propagated to rename maps.
+ *
+ * @param tid ThreadID
+ * @param freelist list of free registers
+ */
+ void switchRenameMode(ThreadID tid, UnifiedFreeList* freelist);
+
/** Returns the Fault for any valid interrupt. */
Fault getInterrupts();
/** Processes any an interrupt fault. */
- void processInterrupts(Fault interrupt);
+ void processInterrupts(const Fault &interrupt);
/** Halts the CPU. */
void halt() { panic("Halt not implemented!\n"); }
- /** Check if this address is a valid instruction address. */
- bool validInstAddr(Addr addr) { return true; }
-
- /** Check if this address is a valid data address. */
- bool validDataAddr(Addr addr) { return true; }
-
/** Register accessors. Index refers to the physical register index. */
/** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegNoEffect(int misc_reg, ThreadID tid);
+ RegVal readMiscRegNoEffect(int misc_reg, ThreadID tid) const;
/** Reads a misc. register, including any side effects the read
* might have as defined by the architecture.
*/
- TheISA::MiscReg readMiscReg(int misc_reg, ThreadID tid);
+ RegVal readMiscReg(int misc_reg, ThreadID tid);
/** Sets a miscellaneous register. */
- void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val,
- ThreadID tid);
+ void setMiscRegNoEffect(int misc_reg, RegVal val, ThreadID tid);
/** Sets a misc. register, including any side effects the write
* might have as defined by the architecture.
*/
- void setMiscReg(int misc_reg, const TheISA::MiscReg &val,
- ThreadID tid);
+ void setMiscReg(int misc_reg, RegVal val, ThreadID tid);
+
+ RegVal readIntReg(PhysRegIdPtr phys_reg);
+
+ RegVal readFloatReg(PhysRegIdPtr phys_reg);
+
+ const VecRegContainer& readVecReg(PhysRegIdPtr reg_idx) const;
+
+ /**
+ * Read physical vector register for modification.
+ */
+ VecRegContainer& getWritableVecReg(PhysRegIdPtr reg_idx);
+
+ /** Returns current vector renaming mode */
+ Enums::VecRegRenameMode vecRenameMode() const { return vecMode; }
+
+ /** Sets the current vector renaming mode */
+ void vecRenameMode(Enums::VecRegRenameMode vec_mode)
+ { vecMode = vec_mode; }
+
+ /**
+ * Read physical vector register lane
+ */
+ template<typename VecElem, int LaneIdx>
+ VecLaneT<VecElem, true>
+ readVecLane(PhysRegIdPtr phys_reg) const
+ {
+ vecRegfileReads++;
+ return regFile.readVecLane<VecElem, LaneIdx>(phys_reg);
+ }
+
+ /**
+ * Read physical vector register lane
+ */
+ template<typename VecElem>
+ VecLaneT<VecElem, true>
+ readVecLane(PhysRegIdPtr phys_reg) const
+ {
+ vecRegfileReads++;
+ return regFile.readVecLane<VecElem>(phys_reg);
+ }
+
+ /** Write a lane of the destination vector register. */
+ template<typename LD>
+ void
+ setVecLane(PhysRegIdPtr phys_reg, const LD& val)
+ {
+ vecRegfileWrites++;
+ return regFile.setVecLane(phys_reg, val);
+ }
+
+ const VecElem& readVecElem(PhysRegIdPtr reg_idx) const;
+
+ const VecPredRegContainer& readVecPredReg(PhysRegIdPtr reg_idx) const;
+
+ VecPredRegContainer& getWritableVecPredReg(PhysRegIdPtr reg_idx);
+
+ RegVal readCCReg(PhysRegIdPtr phys_reg);
+
+ void setIntReg(PhysRegIdPtr phys_reg, RegVal val);
- uint64_t readIntReg(int reg_idx);
+ void setFloatReg(PhysRegIdPtr phys_reg, RegVal val);
- TheISA::FloatReg readFloatReg(int reg_idx);
+ void setVecReg(PhysRegIdPtr reg_idx, const VecRegContainer& val);
- TheISA::FloatRegBits readFloatRegBits(int reg_idx);
+ void setVecElem(PhysRegIdPtr reg_idx, const VecElem& val);
- void setIntReg(int reg_idx, uint64_t val);
+ void setVecPredReg(PhysRegIdPtr reg_idx, const VecPredRegContainer& val);
- void setFloatReg(int reg_idx, TheISA::FloatReg val);
+ void setCCReg(PhysRegIdPtr phys_reg, RegVal val);
- void setFloatRegBits(int reg_idx, TheISA::FloatRegBits val);
+ RegVal readArchIntReg(int reg_idx, ThreadID tid);
- uint64_t readArchIntReg(int reg_idx, ThreadID tid);
+ RegVal readArchFloatReg(int reg_idx, ThreadID tid);
- float readArchFloatReg(int reg_idx, ThreadID tid);
+ const VecRegContainer& readArchVecReg(int reg_idx, ThreadID tid) const;
+ /** Read architectural vector register for modification. */
+ VecRegContainer& getWritableArchVecReg(int reg_idx, ThreadID tid);
+
+ /** Read architectural vector register lane. */
+ template<typename VecElem>
+ VecLaneT<VecElem, true>
+ readArchVecLane(int reg_idx, int lId, ThreadID tid) const
+ {
+ PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
+ RegId(VecRegClass, reg_idx));
+ return readVecLane<VecElem>(phys_reg);
+ }
+
+
+ /** Write a lane of the destination vector register. */
+ template<typename LD>
+ void
+ setArchVecLane(int reg_idx, int lId, ThreadID tid, const LD& val)
+ {
+ PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
+ RegId(VecRegClass, reg_idx));
+ setVecLane(phys_reg, val);
+ }
- uint64_t readArchFloatRegInt(int reg_idx, ThreadID tid);
+ const VecElem& readArchVecElem(const RegIndex& reg_idx,
+ const ElemIndex& ldx, ThreadID tid) const;
+
+ const VecPredRegContainer& readArchVecPredReg(int reg_idx,
+ ThreadID tid) const;
+
+ VecPredRegContainer& getWritableArchVecPredReg(int reg_idx, ThreadID tid);
+
+ RegVal readArchCCReg(int reg_idx, ThreadID 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, ThreadID tid);
+ void setArchIntReg(int reg_idx, RegVal val, ThreadID tid);
+
+ void setArchFloatReg(int reg_idx, RegVal val, ThreadID tid);
- void setArchFloatReg(int reg_idx, float val, ThreadID tid);
+ void setArchVecPredReg(int reg_idx, const VecPredRegContainer& val,
+ ThreadID tid);
- void setArchFloatRegInt(int reg_idx, uint64_t val, ThreadID tid);
+ void setArchVecReg(int reg_idx, const VecRegContainer& val, ThreadID tid);
+
+ void setArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx,
+ const VecElem& val, ThreadID tid);
+
+ void setArchCCReg(int reg_idx, RegVal val, ThreadID tid);
/** Sets the commit PC state of a specific thread. */
void pcState(const TheISA::PCState &newPCState, ThreadID tid);
/** Function to add instruction onto the head of the list of the
* instructions. Used when new instructions are fetched.
*/
- ListIt addInst(DynInstPtr &inst);
+ ListIt addInst(const DynInstPtr &inst);
/** Function to tell the CPU that an instruction has completed. */
- void instDone(ThreadID tid, DynInstPtr &inst);
+ void instDone(ThreadID tid, const 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);
+ void removeFrontInst(const DynInstPtr &inst);
/** Remove all instructions that are not currently in the ROB.
* There's also an option to not squash delay slot instructions.*/
/** The commit stage. */
typename CPUPolicy::Commit commit;
+ /** The rename mode of the vector registers */
+ Enums::VecRegRenameMode vecMode;
+
/** The register file. */
- typename CPUPolicy::RegFile regFile;
+ PhysRegFile regFile;
/** The free list. */
typename CPUPolicy::FreeList freeList;
/** Active Threads List */
std::list<ThreadID> activeThreads;
+ /**
+ * This is a list of threads that are trying to exit. Each thread id
+ * is mapped to a boolean value denoting whether the thread is ready
+ * to exit.
+ */
+ std::unordered_map<ThreadID, bool> exitingThreads;
+
/** Integer Register Scoreboard */
Scoreboard scoreboard;
/** Wakes the CPU, rescheduling the CPU if it's not already active. */
void wakeCPU();
- virtual void wakeup();
+ virtual void wakeup(ThreadID tid) override;
/** Gets a free thread id. Use if thread ids change across system. */
ThreadID getFreeTid();
/** Pointer to the system. */
System *system;
- /** DrainManager to notify when draining has completed. */
- DrainManager *drainManager;
-
/** Pointers to all of the threads in the CPU. */
std::vector<Thread *> thread;
- /** Is there a context switch pending? */
- bool contextSwitch;
-
/** Threads Scheduled to Enter CPU */
std::list<int> cpuWaitList;
/** Available thread ids in the cpu*/
std::vector<ThreadID> tids;
+ /** CPU pushRequest function, forwards request to LSQ. */
+ Fault pushRequest(const DynInstPtr& inst, bool isLoad, uint8_t *data,
+ unsigned int size, Addr addr, Request::Flags flags,
+ uint64_t *res)
+ {
+ return iew.ldstQueue.pushRequest(inst, isLoad, data, size, addr,
+ flags, res);
+ }
+
/** CPU read function, forwards read to LSQ. */
- Fault read(RequestPtr &req, RequestPtr &sreqLow, RequestPtr &sreqHigh,
- uint8_t *data, int load_idx)
+ Fault read(LSQRequest* req, int load_idx)
{
- return this->iew.ldstQueue.read(req, sreqLow, sreqHigh,
- data, load_idx);
+ return this->iew.ldstQueue.read(req, load_idx);
}
/** CPU write function, forwards write to LSQ. */
- Fault write(RequestPtr &req, RequestPtr &sreqLow, RequestPtr &sreqHigh,
- uint8_t *data, int store_idx)
+ Fault write(LSQRequest* req, uint8_t *data, int store_idx)
{
- return this->iew.ldstQueue.write(req, sreqLow, sreqHigh,
- data, store_idx);
+ return this->iew.ldstQueue.write(req, data, store_idx);
}
/** Used by the fetch unit to get a hold of the instruction port. */
- virtual CpuPort &getInstPort() { return icachePort; }
+ MasterPort &getInstPort() override { return icachePort; }
/** Get the dcache port (used to find block size for translations). */
- virtual CpuPort &getDataPort() { return dcachePort; }
+ MasterPort &getDataPort() override { return dcachePort; }
/** Stat for total number of times the CPU is descheduled. */
Stats::Scalar timesIdled;
Stats::Vector committedInsts;
/** Stat for the number of committed ops (including micro ops) per thread. */
Stats::Vector committedOps;
- /** 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. */
//number of float register file accesses
Stats::Scalar fpRegfileReads;
Stats::Scalar fpRegfileWrites;
+ //number of vector register file accesses
+ mutable Stats::Scalar vecRegfileReads;
+ Stats::Scalar vecRegfileWrites;
+ //number of predicate register file accesses
+ mutable Stats::Scalar vecPredRegfileReads;
+ Stats::Scalar vecPredRegfileWrites;
+ //number of CC register file accesses
+ Stats::Scalar ccRegfileReads;
+ Stats::Scalar ccRegfileWrites;
//number of misc
Stats::Scalar miscRegfileReads;
Stats::Scalar miscRegfileWrites;