+
+ /**
+ * Rank class includes a vector of banks. Refresh and Power state
+ * machines are defined per rank. Events required to change the
+ * state of the refresh and power state machine are scheduled per
+ * rank. This class allows the implementation of rank-wise refresh
+ * and rank-wise power-down.
+ */
+ class Rank : public EventManager
+ {
+
+ 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
+ */
+ DRAMCtrl& memory;
+
+ /**
+ * 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.
+ */
+ PowerState pwrStateTrans;
+
+ /**
+ * Current power state.
+ */
+ PowerState pwrState;
+
+ /**
+ * Track when we transitioned to the current power state
+ */
+ Tick pwrStateTick;
+
+ /**
+ * current refresh state
+ */
+ RefreshState refreshState;
+
+ /**
+ * Keep track of when a refresh is due.
+ */
+ Tick refreshDueAt;
+
+ /*
+ * Command energies
+ */
+ Stats::Scalar actEnergy;
+ Stats::Scalar preEnergy;
+ Stats::Scalar readEnergy;
+ Stats::Scalar writeEnergy;
+ Stats::Scalar refreshEnergy;
+
+ /*
+ * Active Background Energy
+ */
+ Stats::Scalar actBackEnergy;
+
+ /*
+ * Precharge Background Energy
+ */
+ Stats::Scalar preBackEnergy;
+
+ Stats::Scalar totalEnergy;
+ Stats::Scalar averagePower;
+
+ /**
+ * Track time spent in each power state.
+ */
+ Stats::Vector pwrStateTime;
+
+ /**
+ * Function to update Power Stats
+ */
+ void updatePowerStats();
+
+ /**
+ * Schedule a power state transition in the future, and
+ * potentially override an already scheduled transition.
+ *
+ * @param pwr_state Power state to transition to
+ * @param tick Tick when transition should take place
+ */
+ void schedulePowerEvent(PowerState pwr_state, Tick tick);
+
+ public:
+
+ /**
+ * Current Rank index
+ */
+ uint8_t rank;
+
+ /**
+ * One DRAMPower instance per rank
+ */
+ DRAMPower power;
+
+ /**
+ * Vector of Banks. Each rank is made of several devices which in
+ * term are made from several banks.
+ */
+ std::vector<Bank> banks;
+
+ /**
+ * To track number of banks which are currently active for
+ * this rank.
+ */
+ unsigned int numBanksActive;
+
+ /** List to keep track of activate ticks */
+ std::deque<Tick> actTicks;
+
+ Rank(DRAMCtrl& _memory, const DRAMCtrlParams* _p);
+
+ const std::string name() const
+ {
+ return csprintf("%s_%d", memory.name(), rank);
+ }
+
+ /**
+ * Kick off accounting for power and refresh states and
+ * schedule initial refresh.
+ *
+ * @param ref_tick Tick for first refresh
+ */
+ void startup(Tick ref_tick);
+
+ /**
+ * Stop the refresh events.
+ */
+ void suspend();
+
+ /**
+ * Check if the current rank is available for scheduling.
+ *
+ * @param Return true if the rank is idle from a refresh point of view
+ */
+ bool isAvailable() const { return refreshState == REF_IDLE; }
+
+ /**
+ * Let the rank check if it was waiting for requests to drain
+ * to allow it to transition states.
+ */
+ void checkDrainDone();
+
+ /*
+ * Function to register Stats
+ */
+ void regStats();
+
+ void processActivateEvent();
+ EventWrapper<Rank, &Rank::processActivateEvent>
+ activateEvent;
+
+ void processPrechargeEvent();
+ EventWrapper<Rank, &Rank::processPrechargeEvent>
+ prechargeEvent;
+
+ void processRefreshEvent();
+ EventWrapper<Rank, &Rank::processRefreshEvent>
+ refreshEvent;
+
+ void processPowerEvent();
+ EventWrapper<Rank, &Rank::processPowerEvent>
+ powerEvent;
+
+ };
+