/*
- * Copyright (c) 2012-2015 ARM Limited
+ * Copyright (c) 2012-2018 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* Ani Udipi
* Neha Agarwal
* Omar Naji
+ * Matthias Jung
+ * Wendy Elsasser
+ * Radhika Jagtap
*/
/**
#include <string>
#include <unordered_set>
+#include "base/callback.hh"
#include "base/statistics.hh"
#include "enums/AddrMap.hh"
#include "enums/MemSched.hh"
* controllers for future system architecture exploration",
* Proc. ISPASS, 2014. If you use this model as part of your research
* please cite the paper.
+ *
+ * The low-power functionality implements a staggered powerdown
+ * similar to that described in "Optimized Active and Power-Down Mode
+ * Refresh Control in 3D-DRAMs" by Jung et al, VLSI-SoC, 2014.
*/
class DRAMCtrl : public AbstractMemory
{
*/
enum BusState {
READ = 0,
- READ_TO_WRITE,
WRITE,
- WRITE_TO_READ
};
BusState busState;
+ /* bus state for next request event triggered */
+ BusState busStateNext;
+
+ /**
+ * Simple structure to hold the values needed to keep track of
+ * commands for DRAMPower
+ */
+ struct Command {
+ Data::MemCommand::cmds type;
+ uint8_t bank;
+ Tick timeStamp;
+
+ constexpr Command(Data::MemCommand::cmds _type, uint8_t _bank,
+ Tick time_stamp)
+ : type(_type), bank(_bank), timeStamp(time_stamp)
+ { }
+ };
+
/**
* A basic class to track the bank state, i.e. what row is
* currently open (if any), when is the bank free to accept a new
uint8_t bank;
uint8_t bankgr;
- Tick colAllowedAt;
+ Tick rdAllowedAt;
+ Tick wrAllowedAt;
Tick preAllowedAt;
Tick actAllowedAt;
Bank() :
openRow(NO_ROW), bank(0), bankgr(0),
- colAllowedAt(0), preAllowedAt(0), actAllowedAt(0),
+ rdAllowedAt(0), wrAllowedAt(0), preAllowedAt(0), actAllowedAt(0),
rowAccesses(0), bytesAccessed(0)
{ }
};
+ /**
+ * The power state captures the different operational states of
+ * the DRAM and interacts with the bus read/write state machine,
+ * and the refresh state machine.
+ *
+ * PWR_IDLE : The idle state in which all banks are closed
+ * From here can transition to: PWR_REF, PWR_ACT,
+ * PWR_PRE_PDN
+ *
+ * PWR_REF : Auto-refresh state. Will transition when refresh is
+ * complete based on power state prior to PWR_REF
+ * From here can transition to: PWR_IDLE, PWR_PRE_PDN,
+ * PWR_SREF
+ *
+ * PWR_SREF : Self-refresh state. Entered after refresh if
+ * previous state was PWR_PRE_PDN
+ * From here can transition to: PWR_IDLE
+ *
+ * PWR_PRE_PDN : Precharge power down state
+ * From here can transition to: PWR_REF, PWR_IDLE
+ *
+ * PWR_ACT : Activate state in which one or more banks are open
+ * From here can transition to: PWR_IDLE, PWR_ACT_PDN
+ *
+ * PWR_ACT_PDN : Activate power down state
+ * From here can transition to: PWR_ACT
+ */
+ enum PowerState {
+ PWR_IDLE = 0,
+ PWR_REF,
+ PWR_SREF,
+ PWR_PRE_PDN,
+ PWR_ACT,
+ PWR_ACT_PDN
+ };
+
+ /**
+ * The refresh state is used to control the progress of the
+ * refresh scheduling. When normal operation is in progress the
+ * refresh state is idle. Once tREFI has elasped, a refresh event
+ * is triggered to start the following STM transitions which are
+ * used to issue a refresh and return back to normal operation
+ *
+ * REF_IDLE : IDLE state used during normal operation
+ * From here can transition to: REF_DRAIN
+ *
+ * REF_SREF_EXIT : Exiting a self-refresh; refresh event scheduled
+ * after self-refresh exit completes
+ * From here can transition to: REF_DRAIN
+ *
+ * REF_DRAIN : Drain state in which on going accesses complete.
+ * From here can transition to: REF_PD_EXIT
+ *
+ * REF_PD_EXIT : Evaluate pwrState and issue wakeup if needed
+ * Next state dependent on whether banks are open
+ * From here can transition to: REF_PRE, REF_START
+ *
+ * REF_PRE : Close (precharge) all open banks
+ * From here can transition to: REF_START
+ *
+ * REF_START : Issue refresh command and update DRAMPower stats
+ * From here can transition to: REF_RUN
+ *
+ * REF_RUN : Refresh running, waiting for tRFC to expire
+ * From here can transition to: REF_IDLE, REF_SREF_EXIT
+ */
+ enum RefreshState {
+ REF_IDLE = 0,
+ REF_DRAIN,
+ REF_PD_EXIT,
+ REF_SREF_EXIT,
+ REF_PRE,
+ REF_START,
+ REF_RUN
+ };
+
/**
* Rank class includes a vector of banks. Refresh and Power state
* machines are defined per rank. Events required to change the
private:
- /**
- * The power state captures the different operational states of
- * the DRAM and interacts with the bus read/write state machine,
- * and the refresh state machine. In the idle state all banks are
- * precharged. From there we either go to an auto refresh (as
- * determined by the refresh state machine), or to a precharge
- * power down mode. From idle the memory can also go to the active
- * state (with one or more banks active), and in turn from there
- * to active power down. At the moment we do not capture the deep
- * power down and self-refresh state.
- */
- enum PowerState {
- PWR_IDLE = 0,
- PWR_REF,
- PWR_PRE_PDN,
- PWR_ACT,
- PWR_ACT_PDN
- };
-
- /**
- * The refresh state is used to control the progress of the
- * refresh scheduling. When normal operation is in progress the
- * refresh state is idle. From there, it progresses to the refresh
- * drain state once tREFI has passed. The refresh drain state
- * captures the DRAM row active state, as it will stay there until
- * all ongoing accesses complete. Thereafter all banks are
- * precharged, and lastly, the DRAM is refreshed.
- */
- enum RefreshState {
- REF_IDLE = 0,
- REF_DRAIN,
- REF_PRE,
- REF_RUN
- };
-
/**
* A reference to the parent DRAMCtrl instance
*/
/**
* Since we are taking decisions out of order, we need to keep
- * track of what power transition is happening at what time, such
- * that we can go back in time and change history. For example, if
- * we precharge all banks and schedule going to the idle state, we
- * might at a later point decide to activate a bank before the
- * transition to idle would have taken place.
+ * track of what power transition is happening at what time
*/
PowerState pwrStateTrans;
/**
- * Current power state.
+ * Previous low-power state, which will be re-entered after refresh.
*/
- PowerState pwrState;
+ PowerState pwrStatePostRefresh;
/**
* Track when we transitioned to the current power state
*/
Tick pwrStateTick;
- /**
- * current refresh state
- */
- RefreshState refreshState;
-
/**
* Keep track of when a refresh is due.
*/
*/
Stats::Scalar preBackEnergy;
+ /*
+ * Active Power-Down Energy
+ */
+ Stats::Scalar actPowerDownEnergy;
+
+ /*
+ * Precharge Power-Down Energy
+ */
+ Stats::Scalar prePowerDownEnergy;
+
+ /*
+ * self Refresh Energy
+ */
+ Stats::Scalar selfRefreshEnergy;
+
Stats::Scalar totalEnergy;
Stats::Scalar averagePower;
+ /**
+ * Stat to track total DRAM idle time
+ *
+ */
+ Stats::Scalar totalIdleTime;
+
/**
* Track time spent in each power state.
*/
public:
+ /**
+ * Current power state.
+ */
+ PowerState pwrState;
+
+ /**
+ * current refresh state
+ */
+ RefreshState refreshState;
+
+ /**
+ * rank is in or transitioning to power-down or self-refresh
+ */
+ bool inLowPowerState;
+
/**
* Current Rank index
*/
uint8_t rank;
+ /**
+ * Track number of packets in read queue going to this rank
+ */
+ uint32_t readEntries;
+
+ /**
+ * Track number of packets in write queue going to this rank
+ */
+ uint32_t writeEntries;
+
+ /**
+ * Number of ACT, RD, and WR events currently scheduled
+ * Incremented when a refresh event is started as well
+ * Used to determine when a low-power state can be entered
+ */
+ uint8_t outstandingEvents;
+
+ /**
+ * delay power-down and self-refresh exit until this requirement is met
+ */
+ Tick wakeUpAllowedAt;
+
/**
* One DRAMPower instance per rank
*/
DRAMPower power;
+ /**
+ * List of comamnds issued, to be sent to DRAMPpower at refresh
+ * and stats dump. Keep commands here since commands to different
+ * banks are added out of order. Will only pass commands up to
+ * curTick() to DRAMPower after sorting.
+ */
+ std::vector<Command> cmdList;
+
/**
* Vector of Banks. Each rank is made of several devices which in
* term are made from several banks.
/** List to keep track of activate ticks */
std::deque<Tick> actTicks;
- Rank(DRAMCtrl& _memory, const DRAMCtrlParams* _p);
+ Rank(DRAMCtrl& _memory, const DRAMCtrlParams* _p, int rank);
const std::string name() const
{
void suspend();
/**
- * Check if the current rank is available for scheduling.
+ * Check if there is no refresh and no preparation of refresh ongoing
+ * i.e. the refresh state machine is in idle
*
* @param Return true if the rank is idle from a refresh point of view
*/
- bool isAvailable() const { return refreshState == REF_IDLE; }
+ bool inRefIdleState() const { return refreshState == REF_IDLE; }
+
+ /**
+ * Check if the current rank has all banks closed and is not
+ * in a low power state
+ *
+ * @param Return true if the rank is idle from a bank
+ * and power point of view
+ */
+ bool inPwrIdleState() const { return pwrState == PWR_IDLE; }
+
+ /**
+ * Trigger a self-refresh exit if there are entries enqueued
+ * Exit if there are any read entries regardless of the bus state.
+ * If we are currently issuing write commands, exit if we have any
+ * write commands enqueued as well.
+ * Could expand this in the future to analyze state of entire queue
+ * if needed.
+ *
+ * @return boolean indicating self-refresh exit should be scheduled
+ */
+ bool forceSelfRefreshExit() const {
+ return (readEntries != 0) ||
+ ((memory.busStateNext == WRITE) && (writeEntries != 0));
+ }
+
+ /**
+ * Check if the command queue of current rank is idle
+ *
+ * @param Return true if the there are no commands in Q.
+ * Bus direction determines queue checked.
+ */
+ bool isQueueEmpty() const;
/**
* Let the rank check if it was waiting for requests to drain
*/
void checkDrainDone();
+ /**
+ * Push command out of cmdList queue that are scheduled at
+ * or before curTick() to DRAMPower library
+ * All commands before curTick are guaranteed to be complete
+ * and can safely be flushed.
+ */
+ void flushCmdList();
+
/*
* Function to register Stats
*/
void regStats();
+ /**
+ * Computes stats just prior to dump event
+ */
+ void computeStats();
+
+ /**
+ * Reset stats on a stats event
+ */
+ void resetStats();
+
+ /**
+ * Schedule a transition to power-down (sleep)
+ *
+ * @param pwr_state Power state to transition to
+ * @param tick Absolute tick when transition should take place
+ */
+ void powerDownSleep(PowerState pwr_state, Tick tick);
+
+ /**
+ * schedule and event to wake-up from power-down or self-refresh
+ * and update bank timing parameters
+ *
+ * @param exit_delay Relative tick defining the delay required between
+ * low-power exit and the next command
+ */
+ void scheduleWakeUpEvent(Tick exit_delay);
+
+ void processWriteDoneEvent();
+ EventFunctionWrapper writeDoneEvent;
+
void processActivateEvent();
- EventWrapper<Rank, &Rank::processActivateEvent>
- activateEvent;
+ EventFunctionWrapper activateEvent;
void processPrechargeEvent();
- EventWrapper<Rank, &Rank::processPrechargeEvent>
- prechargeEvent;
+ EventFunctionWrapper prechargeEvent;
void processRefreshEvent();
- EventWrapper<Rank, &Rank::processRefreshEvent>
- refreshEvent;
+ EventFunctionWrapper refreshEvent;
void processPowerEvent();
- EventWrapper<Rank, &Rank::processPowerEvent>
- powerEvent;
+ EventFunctionWrapper powerEvent;
+
+ void processWakeUpEvent();
+ EventFunctionWrapper wakeUpEvent;
+
+ };
+
+ /**
+ * Define the process to compute stats on a stats dump event, e.g. on
+ * simulation exit or intermediate stats dump. This is defined per rank
+ * as the per rank stats are based on state transition and periodically
+ * updated, requiring re-sync at exit.
+ */
+ class RankDumpCallback : public Callback
+ {
+ Rank *ranks;
+ public:
+ RankDumpCallback(Rank *r) : ranks(r) {}
+ virtual void process() { ranks->computeStats(); };
+ };
+
+ /** Define a process to clear power lib counters on a stats reset */
+ class RankResetCallback : public Callback
+ {
+ private:
+ /** Pointer to the rank, thus we instantiate per rank */
+ Rank *rank;
+
+ public:
+ RankResetCallback(Rank *r) : rank(r) {}
+ virtual void process() { rank->resetStats(); };
+ };
+ /** Define a process to store the time on a stats reset */
+ class MemResetCallback : public Callback
+ {
+ private:
+ /** A reference to the DRAMCtrl instance */
+ DRAMCtrl *mem;
+
+ public:
+ MemResetCallback(DRAMCtrl *_mem) : mem(_mem) {}
+ virtual void process() { mem->lastStatsResetTick = curTick(); };
};
/**
* in these methods
*/
void processNextReqEvent();
- EventWrapper<DRAMCtrl,&DRAMCtrl::processNextReqEvent> nextReqEvent;
+ EventFunctionWrapper nextReqEvent;
void processRespondEvent();
- EventWrapper<DRAMCtrl, &DRAMCtrl::processRespondEvent> respondEvent;
+ EventFunctionWrapper respondEvent;
/**
* Check if the read queue has room for more entries
/**
* Find which are the earliest banks ready to issue an activate
- * for the enqueued requests. Assumes maximum of 64 banks per DIMM
+ * for the enqueued requests. Assumes maximum of 32 banks per rank
* Also checks if the bank is already prepped.
*
* @param queue Queued requests to consider
- * @param time of seamless burst command
+ * @param min_col_at time of seamless burst command
* @return One-hot encoded mask of bank indices
* @return boolean indicating burst can issue seamlessly, with no gaps
*/
- std::pair<uint64_t, bool> minBankPrep(const std::deque<DRAMPacket*>& queue,
+ std::pair<std::vector<uint32_t>, bool> minBankPrep(
+ const std::deque<DRAMPacket*>& queue,
Tick min_col_at) const;
/**
* values.
*/
const Tick M5_CLASS_VAR_USED tCK;
- const Tick tWTR;
const Tick tRTW;
const Tick tCS;
const Tick tBURST;
+ const Tick tCCD_L_WR;
const Tick tCCD_L;
const Tick tRCD;
const Tick tCL;
const Tick tRRD;
const Tick tRRD_L;
const Tick tXAW;
+ const Tick tXP;
+ const Tick tXS;
const uint32_t activationLimit;
+ const Tick rankToRankDly;
+ const Tick wrToRdDly;
+ const Tick rdToWrDly;
/**
* Memory controller configuration initialized based on parameter
const Tick backendLatency;
/**
- * Till when has the main data bus been spoken for already?
+ * Till when must we wait before issuing next RD/WR burst?
*/
- Tick busBusyUntil;
+ Tick nextBurstAt;
Tick prevArrival;
/**
* The soonest you have to start thinking about the next request
* is the longest access time that can occur before
- * busBusyUntil. Assuming you need to precharge, open a new row,
+ * nextBurstAt. Assuming you need to precharge, open a new row,
* and access, it is tRP + tRCD + tCL.
*/
Tick nextReqTime;
// timestamp offset
uint64_t timeStampOffset;
- /** @todo this is a temporary workaround until the 4-phase code is
- * committed. upstream caches needs this packet until true is returned, so
- * hold onto it for deletion until a subsequent call
+ /** The time when stats were last reset used to calculate average power */
+ Tick lastStatsResetTick;
+
+ /**
+ * Upstream caches need this packet until true is returned, so
+ * hold it for deletion until a subsequent call
*/
- std::vector<PacketPtr> pendingDelete;
+ std::unique_ptr<Packet> pendingDelete;
/**
* This function increments the energy when called. If stats are
void updatePowerStats(Rank& rank_ref);
/**
- * Function for sorting commands in the command list of DRAMPower.
+ * Function for sorting Command structures based on timeStamp
*
- * @param a Memory Command in command list of DRAMPower library
- * @param next Memory Command in command list of DRAMPower
- * @return true if timestamp of Command 1 < timestamp of Command 2
+ * @param a Memory Command
+ * @param next Memory Command
+ * @return true if timeStamp of Command 1 < timeStamp of Command 2
*/
- static bool sortTime(const Data::MemCommand& m1,
- const Data::MemCommand& m2) {
- return m1.getTime() < m2.getTime();
+ static bool sortTime(const Command& cmd, const Command& cmd_next) {
+ return cmd.timeStamp < cmd_next.timeStamp;
};
-
public:
void regStats() override;
virtual void startup() override;
virtual void drainResume() override;
+ /**
+ * Return true once refresh is complete for all ranks and there are no
+ * additional commands enqueued. (only evaluated when draining)
+ * This will ensure that all banks are closed, power state is IDLE, and
+ * power stats have been updated
+ *
+ * @return true if all ranks have refreshed, with no commands enqueued
+ *
+ */
+ bool allRanksDrained() const;
+
protected:
Tick recvAtomic(PacketPtr pkt);