/*
- * Copyright (c) 2011-2013 ARM Limited
+ * Copyright (c) 2011-2013, 2016-2019 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved
*
#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;
/** 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();
};
/**
/** Pointer to LSQ. */
LSQ<Impl> *lsq;
+ FullO3CPU<Impl> *cpu;
public:
/** Default constructor. */
DcachePort(LSQ<Impl> *_lsq, FullO3CPU<Impl>* _cpu)
- : MasterPort(_cpu->name() + ".dcache_port", _cpu), lsq(_lsq)
+ : MasterPort(_cpu->name() + ".dcache_port", _cpu), lsq(_lsq),
+ cpu(_cpu)
{ }
protected:
}
/** 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)
}
/**
- * 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();
+ 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);
+ 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.
- */
- void deallocateContext(ThreadID tid, bool remove);
+ void suspendContext(ThreadID tid) override;
/** Remove Thread from Active Threads List &&
* Remove Thread Context from CPU.
*/
- void haltContext(ThreadID tid);
+ 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(std::ostream &os, ThreadID tid);
+ void serializeThread(CheckpointOut &cp, ThreadID tid) const override;
+ void unserializeThread(CheckpointIn &cp, ThreadID tid) override;
- void unserializeThread(Checkpoint *cp, const std::string §ion,
- ThreadID tid);
+ /** 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;
+
+ /**
+ * 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);
+
+ /** 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;
+ void verifyMemoryMode() const override;
/** Get the current instruction sequence number, and increment it. */
InstSeqNum getAndIncrementInstSeq()
{ return globalSeqNum++; }
/** Traps to handle given fault. */
- void trap(const 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();
/** 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);
+ }
- uint64_t readIntReg(int reg_idx);
+ /** 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;
- TheISA::FloatReg readFloatReg(int reg_idx);
+ const VecPredRegContainer& readVecPredReg(PhysRegIdPtr reg_idx) const;
- TheISA::FloatRegBits readFloatRegBits(int reg_idx);
+ VecPredRegContainer& getWritableVecPredReg(PhysRegIdPtr reg_idx);
- TheISA::CCReg readCCReg(int reg_idx);
+ RegVal readCCReg(PhysRegIdPtr phys_reg);
- void setIntReg(int reg_idx, uint64_t val);
+ void setIntReg(PhysRegIdPtr phys_reg, RegVal val);
- void setFloatReg(int reg_idx, TheISA::FloatReg val);
+ void setFloatReg(PhysRegIdPtr phys_reg, RegVal val);
- void setFloatRegBits(int reg_idx, TheISA::FloatRegBits val);
+ void setVecReg(PhysRegIdPtr reg_idx, const VecRegContainer& val);
- void setCCReg(int reg_idx, TheISA::CCReg val);
+ void setVecElem(PhysRegIdPtr reg_idx, const VecElem& val);
- uint64_t readArchIntReg(int reg_idx, ThreadID tid);
+ void setVecPredReg(PhysRegIdPtr reg_idx, const VecPredRegContainer& val);
- float readArchFloatReg(int reg_idx, ThreadID tid);
+ void setCCReg(PhysRegIdPtr phys_reg, RegVal val);
- uint64_t readArchFloatRegInt(int reg_idx, ThreadID tid);
+ RegVal readArchIntReg(int reg_idx, ThreadID tid);
- TheISA::CCReg readArchCCReg(int reg_idx, ThreadID tid);
+ RegVal 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);
+ }
+
+ 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 setArchVecPredReg(int reg_idx, const VecPredRegContainer& val,
+ ThreadID tid);
- void setArchFloatReg(int reg_idx, float val, ThreadID tid);
+ void setArchVecReg(int reg_idx, const VecRegContainer& val, ThreadID tid);
- void setArchFloatRegInt(int reg_idx, uint64_t val, ThreadID tid);
+ void setArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx,
+ const VecElem& val, ThreadID tid);
- void setArchCCReg(int reg_idx, TheISA::CCReg 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. */
PhysRegFile regFile;
/** 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;
/** 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 MasterPort &getInstPort() { return icachePort; }
+ MasterPort &getInstPort() override { return icachePort; }
/** Get the dcache port (used to find block size for translations). */
- virtual MasterPort &getDataPort() { return dcachePort; }
+ MasterPort &getDataPort() override { return dcachePort; }
/** Stat for total number of times the CPU is descheduled. */
Stats::Scalar timesIdled;
//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;