mem-cache: Create an address aware TempCacheBlk
[gem5.git] / src / mem / dram_ctrl.hh
index fc1a6115bb262ecc85f19387411f73f608bf244e..11a16edefbcefdb2e0d0387a1260695eb8f54e9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014 ARM Limited
+ * Copyright (c) 2012-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  * Authors: Andreas Hansson
  *          Ani Udipi
  *          Neha Agarwal
+ *          Omar Naji
+ *          Matthias Jung
+ *          Wendy Elsasser
+ *          Radhika Jagtap
  */
 
 /**
 #define __MEM_DRAM_CTRL_HH__
 
 #include <deque>
+#include <string>
+#include <unordered_set>
 
+#include "base/callback.hh"
 #include "base/statistics.hh"
 #include "enums/AddrMap.hh"
 #include "enums/MemSched.hh"
 #include "mem/qport.hh"
 #include "params/DRAMCtrl.hh"
 #include "sim/eventq.hh"
+#include "mem/drampower.hh"
 
 /**
- * The DRAM controller is a basic single-channel memory controller
- * aiming to mimic a high-level DRAM controller and the most important
- * timing constraints associated with the DRAM. The focus is really on
- * modelling the impact on the system rather than the DRAM itself,
- * hence the focus is on the controller model and not on the
- * memory. By adhering to the correct timing constraints, ultimately
- * there is no need for a memory model in addition to the controller
- * model.
+ * The DRAM controller is a single-channel memory controller capturing
+ * the most important timing constraints associated with a
+ * contemporary DRAM. For multi-channel memory systems, the controller
+ * is combined with a crossbar model, with the channel address
+ * interleaving taking part in the crossbar.
  *
- * As a basic design principle, this controller is not cycle callable,
- * but instead uses events to decide when new decisions can be made,
- * when resources become available, when things are to be considered
- * done, and when to send things back. Through these simple
- * principles, we achieve a performant model that is not
- * cycle-accurate, but enables us to evaluate the system impact of a
- * wide range of memory technologies, and also collect statistics
- * about the use of the memory.
+ * As a basic design principle, this controller
+ * model is not cycle callable, but instead uses events to: 1) decide
+ * when new decisions can be made, 2) when resources become available,
+ * 3) when things are to be considered done, and 4) when to send
+ * things back. Through these simple principles, the model delivers
+ * high performance, and lots of flexibility, allowing users to
+ * evaluate the system impact of a wide range of memory technologies,
+ * such as DDR3/4, LPDDR2/3/4, WideIO1/2, HBM and HMC.
+ *
+ * For more details, please see Hansson et al, "Simulating DRAM
+ * 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
 {
@@ -90,7 +104,7 @@ class DRAMCtrl : public AbstractMemory
     class MemoryPort : public QueuedSlavePort
     {
 
-        SlavePacketQueue queue;
+        RespPacketQueue queue;
         DRAMCtrl& memory;
 
       public:
@@ -115,6 +129,11 @@ class DRAMCtrl : public AbstractMemory
      */
     MemoryPort port;
 
+    /**
+     * Remeber if the memory system is in timing mode
+     */
+    bool isTimingMode;
+
     /**
      * Remember if we have to retry a request when available.
      */
@@ -127,15 +146,28 @@ class DRAMCtrl : public AbstractMemory
      */
     enum BusState {
         READ = 0,
-        READ_TO_WRITE,
         WRITE,
-        WRITE_TO_READ
     };
 
     BusState busState;
 
-    /** List to keep track of activate ticks */
-    std::vector<std::deque<Tick>> actTicks;
+    /* 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
@@ -154,10 +186,11 @@ class DRAMCtrl : public AbstractMemory
         static const uint32_t NO_ROW = -1;
 
         uint32_t openRow;
-        uint8_t rank;
         uint8_t bank;
+        uint8_t bankgr;
 
-        Tick colAllowedAt;
+        Tick rdAllowedAt;
+        Tick wrAllowedAt;
         Tick preAllowedAt;
         Tick actAllowedAt;
 
@@ -165,12 +198,425 @@ class DRAMCtrl : public AbstractMemory
         uint32_t bytesAccessed;
 
         Bank() :
-            openRow(NO_ROW), rank(0), bank(0),
-            colAllowedAt(0), preAllowedAt(0), actAllowedAt(0),
+            openRow(NO_ROW), bank(0), bankgr(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
+     * 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:
+
+        /**
+         * 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
+         */
+        PowerState pwrStateTrans;
+
+        /**
+         * Previous low-power state, which will be re-entered after refresh.
+         */
+        PowerState pwrStatePostRefresh;
+
+        /**
+         * Track when we transitioned to the current power state
+         */
+        Tick pwrStateTick;
+
+        /**
+         * 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;
+
+        /*
+         * 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.
+         */
+        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 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.
+         */
+        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, int rank);
+
+        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 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 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
+         * to allow it to transition states.
+         */
+        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();
+        EventFunctionWrapper activateEvent;
+
+        void processPrechargeEvent();
+        EventFunctionWrapper prechargeEvent;
+
+        void processRefreshEvent();
+        EventFunctionWrapper refreshEvent;
+
+        void processPowerEvent();
+        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(); };
+    };
+
     /**
      * A burst helper helps organize and manage a packet that is larger than
      * the DRAM burst size. A system packet that is larger than the burst size
@@ -189,7 +635,7 @@ class DRAMCtrl : public AbstractMemory
 
         BurstHelper(unsigned int _burstCount)
             : burstCount(_burstCount), burstsServiced(0)
-            { }
+        { }
     };
 
     /**
@@ -243,14 +689,15 @@ class DRAMCtrl : public AbstractMemory
          */
         BurstHelper* burstHelper;
         Bank& bankRef;
+        Rank& rankRef;
 
         DRAMPacket(PacketPtr _pkt, bool is_read, uint8_t _rank, uint8_t _bank,
                    uint32_t _row, uint16_t bank_id, Addr _addr,
-                   unsigned int _size, Bank& bank_ref)
+                   unsigned int _size, Bank& bank_ref, Rank& rank_ref)
             : entryTime(curTick()), readyTime(curTick()),
               pkt(_pkt), isRead(is_read), rank(_rank), bank(_bank), row(_row),
               bankId(bank_id), addr(_addr), size(_size), burstHelper(NULL),
-              bankRef(bank_ref)
+              bankRef(bank_ref), rankRef(rank_ref)
         { }
 
     };
@@ -262,22 +709,10 @@ class DRAMCtrl : public AbstractMemory
      * in these methods
      */
     void processNextReqEvent();
-    EventWrapper<DRAMCtrl,&DRAMCtrl::processNextReqEvent> nextReqEvent;
+    EventFunctionWrapper nextReqEvent;
 
     void processRespondEvent();
-    EventWrapper<DRAMCtrl, &DRAMCtrl::processRespondEvent> respondEvent;
-
-    void processActivateEvent();
-    EventWrapper<DRAMCtrl, &DRAMCtrl::processActivateEvent> activateEvent;
-
-    void processPrechargeEvent();
-    EventWrapper<DRAMCtrl, &DRAMCtrl::processPrechargeEvent> prechargeEvent;
-
-    void processRefreshEvent();
-    EventWrapper<DRAMCtrl, &DRAMCtrl::processRefreshEvent> refreshEvent;
-
-    void processPowerEvent();
-    EventWrapper<DRAMCtrl,&DRAMCtrl::processPowerEvent> powerEvent;
+    EventFunctionWrapper respondEvent;
 
     /**
      * Check if the read queue has room for more entries
@@ -366,23 +801,40 @@ class DRAMCtrl : public AbstractMemory
      * The memory schduler/arbiter - picks which request needs to
      * go next, based on the specified policy such as FCFS or FR-FCFS
      * and moves it to the head of the queue.
+     * Prioritizes accesses to the same rank as previous burst unless
+     * controller is switching command type.
+     *
+     * @param queue Queued requests to consider
+     * @param extra_col_delay Any extra delay due to a read/write switch
+     * @return true if a packet is scheduled to a rank which is available else
+     * false
      */
-    void chooseNext(std::deque<DRAMPacket*>& queue);
+    bool chooseNext(std::deque<DRAMPacket*>& queue, Tick extra_col_delay);
 
     /**
      * For FR-FCFS policy reorder the read/write queue depending on row buffer
-     * hits and earliest banks available in DRAM
+     * hits and earliest bursts available in DRAM
+     *
+     * @param queue Queued requests to consider
+     * @param extra_col_delay Any extra delay due to a read/write switch
+     * @return true if a packet is scheduled to a rank which is available else
+     * false
      */
-    void reorderQueue(std::deque<DRAMPacket*>& queue);
+    bool reorderQueue(std::deque<DRAMPacket*>& queue, Tick extra_col_delay);
 
     /**
      * 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 Queued requests to consider
+     * @param queue Queued requests to consider
+     * @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
      */
-    uint64_t minBankActAt(const std::deque<DRAMPacket*>& queue) const;
+    std::pair<std::vector<uint32_t>, bool> minBankPrep(
+                                          const std::deque<DRAMPacket*>& queue,
+                                          Tick min_col_at) const;
 
     /**
      * Keep track of when row activations happen, in order to enforce
@@ -390,34 +842,56 @@ class DRAMCtrl : public AbstractMemory
      * method updates the time that the banks become available based
      * on the current limits.
      *
-     * @param bank Reference to the bank
+     * @param rank_ref Reference to the rank
+     * @param bank_ref Reference to the bank
      * @param act_tick Time when the activation takes place
      * @param row Index of the row
      */
-    void activateBank(Bank& bank, Tick act_tick, uint32_t row);
+    void activateBank(Rank& rank_ref, Bank& bank_ref, Tick act_tick,
+                      uint32_t row);
 
     /**
      * Precharge a given bank and also update when the precharge is
      * done. This will also deal with any stats related to the
      * accesses to the open page.
      *
+     * @param rank_ref The rank to precharge
      * @param bank_ref The bank to precharge
      * @param pre_at Time when the precharge takes place
      * @param trace Is this an auto precharge then do not add to trace
      */
-    void prechargeBank(Bank& bank_ref, Tick pre_at,  bool trace = true);
+    void prechargeBank(Rank& rank_ref, Bank& bank_ref,
+                       Tick pre_at, bool trace = true);
 
     /**
      * Used for debugging to observe the contents of the queues.
      */
     void printQs() const;
 
+    /**
+     * Burst-align an address.
+     *
+     * @param addr The potentially unaligned address
+     *
+     * @return An address aligned to a DRAM burst
+     */
+    Addr burstAlign(Addr addr) const { return (addr & ~(Addr(burstSize - 1))); }
+
     /**
      * The controller's main read and write queues
      */
     std::deque<DRAMPacket*> readQueue;
     std::deque<DRAMPacket*> writeQueue;
 
+    /**
+     * To avoid iterating over the write queue to check for
+     * overlapping transactions, maintain a set of burst addresses
+     * that are currently queued. Since we merge writes to the same
+     * location we never have more than one address to the same burst
+     * address.
+     */
+    std::unordered_set<Addr> isInWriteQueue;
+
     /**
      * Response queue where read packets wait after we're done working
      * with them, but it's not time to send the response yet. The
@@ -429,16 +903,9 @@ class DRAMCtrl : public AbstractMemory
     std::deque<DRAMPacket*> respQueue;
 
     /**
-     * If we need to drain, keep the drain manager around until we're
-     * done here.
-     */
-    DrainManager *drainManager;
-
-    /**
-     * Multi-dimensional vector of banks, first dimension is ranks,
-     * second is bank
+     * Vector of ranks
      */
-    std::vector<std::vector<Bank> > banks;
+    std::vector<Rank*> ranks;
 
     /**
      * The following are basic design parameters of the memory
@@ -446,6 +913,7 @@ class DRAMCtrl : public AbstractMemory
      * The rowsPerBank is determined based on the capacity, number of
      * ranks and banks, the burst size, and the row buffer size.
      */
+    const uint32_t deviceSize;
     const uint32_t deviceBusWidth;
     const uint32_t burstLength;
     const uint32_t deviceRowBufferSize;
@@ -455,6 +923,8 @@ class DRAMCtrl : public AbstractMemory
     const uint32_t columnsPerRowBuffer;
     const uint32_t columnsPerStripe;
     const uint32_t ranksPerChannel;
+    const uint32_t bankGroupsPerRank;
+    const bool bankGroupArch;
     const uint32_t banksPerRank;
     const uint32_t channels;
     uint32_t rowsPerBank;
@@ -471,9 +941,11 @@ class DRAMCtrl : public AbstractMemory
      * 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 tRP;
@@ -483,8 +955,14 @@ class DRAMCtrl : public AbstractMemory
     const Tick tRFC;
     const Tick tREFI;
     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
@@ -515,82 +993,16 @@ class DRAMCtrl : public AbstractMemory
     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;
-
-    /**
-     * Keep track of when a refresh is due.
-     */
-    Tick refreshDueAt;
-
-    /**
-     * 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
-    };
-
-    RefreshState refreshState;
-
-    /**
-     * 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
-    };
-
-    /**
-     * 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;
-
-    /**
-     * 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);
+    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;
@@ -654,33 +1066,69 @@ class DRAMCtrl : public AbstractMemory
 
     // DRAM Power Calculation
     Stats::Formula pageHitRate;
-    Stats::Vector pwrStateTime;
 
-    // Track when we transitioned to the current power state
-    Tick pwrStateTick;
+    // Holds the value of the rank of burst issued
+    uint8_t activeRank;
+
+    // timestamp offset
+    uint64_t timeStampOffset;
 
-    // To track number of banks which are currently active
-    unsigned int numBanksActive;
+    /** The time when stats were last reset used to calculate average power */
+    Tick lastStatsResetTick;
 
-    /** @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
+    /**
+     * 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
+     * dumped periodically, note accumulated energy values will
+     * appear in the stats (even if the stats are reset). This is a
+     * result of the energy values coming from DRAMPower, and there
+     * is currently no support for resetting the state.
+     *
+     * @param rank Currrent rank
+     */
+    void updatePowerStats(Rank& rank_ref);
+
+    /**
+     * Function for sorting Command structures based on timeStamp
+     *
+     * @param a Memory Command
+     * @param next Memory Command
+     * @return true if timeStamp of Command 1 < timeStamp of Command 2
+     */
+    static bool sortTime(const Command& cmd, const Command& cmd_next) {
+        return cmd.timeStamp < cmd_next.timeStamp;
+    };
 
   public:
 
-    void regStats();
+    void regStats() override;
 
     DRAMCtrl(const DRAMCtrlParams* p);
 
-    unsigned int drain(DrainManager* dm);
+    DrainState drain() override;
 
     virtual BaseSlavePort& getSlavePort(const std::string& if_name,
-                                        PortID idx = InvalidPortID);
+                                        PortID idx = InvalidPortID) override;
 
-    virtual void init();
-    virtual void startup();
+    virtual void init() 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: