mem-cache: Create an address aware TempCacheBlk
[gem5.git] / src / mem / dram_ctrl.hh
index 57731f5e088f9f8d388423141bb7dc912dd4d90b..11a16edefbcefdb2e0d0387a1260695eb8f54e9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -41,6 +41,9 @@
  *          Ani Udipi
  *          Neha Agarwal
  *          Omar Naji
+ *          Matthias Jung
+ *          Wendy Elsasser
+ *          Radhika Jagtap
  */
 
 /**
@@ -55,6 +58,7 @@
 #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
 {
@@ -138,13 +146,29 @@ 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
@@ -165,7 +189,8 @@ class DRAMCtrl : public AbstractMemory
         uint8_t bank;
         uint8_t bankgr;
 
-        Tick colAllowedAt;
+        Tick rdAllowedAt;
+        Tick wrAllowedAt;
         Tick preAllowedAt;
         Tick actAllowedAt;
 
@@ -174,12 +199,88 @@ class DRAMCtrl : public AbstractMemory
 
         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
@@ -192,41 +293,6 @@ class DRAMCtrl : public AbstractMemory
 
       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
          */
@@ -234,29 +300,20 @@ class DRAMCtrl : public AbstractMemory
 
         /**
          * 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.
          */
@@ -281,9 +338,30 @@ class DRAMCtrl : public AbstractMemory
          */
         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.
          */
@@ -305,16 +383,61 @@ class DRAMCtrl : public AbstractMemory
 
       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.
@@ -330,7 +453,7 @@ class DRAMCtrl : public AbstractMemory
         /** 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
         {
@@ -351,11 +474,44 @@ class DRAMCtrl : public AbstractMemory
         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
@@ -363,27 +519,102 @@ class DRAMCtrl : public AbstractMemory
          */
         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(); };
     };
 
     /**
@@ -478,10 +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;
+    EventFunctionWrapper respondEvent;
 
     /**
      * Check if the read queue has room for more entries
@@ -574,36 +805,36 @@ class DRAMCtrl : public AbstractMemory
      * controller is switching command type.
      *
      * @param queue Queued requests to consider
-     * @param switched_cmd_type Command type is changing
+     * @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
      */
-    bool chooseNext(std::deque<DRAMPacket*>& queue, bool switched_cmd_type);
+    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
-     * Prioritizes accesses to the same rank as previous burst unless
-     * controller is switching command type.
+     * hits and earliest bursts available in DRAM
      *
      * @param queue Queued requests to consider
-     * @param switched_cmd_type Command type is changing
+     * @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
      */
-    bool reorderQueue(std::deque<DRAMPacket*>& queue, bool switched_cmd_type);
+    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 queue Queued requests to consider
-     * @param switched_cmd_type Command type is changing
+     * @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 minBankPrep(const std::deque<DRAMPacket*>& queue,
-                         bool switched_cmd_type) 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
@@ -671,12 +902,6 @@ 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;
-
     /**
      * Vector of ranks
      */
@@ -716,10 +941,10 @@ 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;
@@ -732,7 +957,12 @@ class DRAMCtrl : public AbstractMemory
     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
@@ -763,16 +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;
+    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;
@@ -843,11 +1073,14 @@ class DRAMCtrl : public AbstractMemory
     // 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
@@ -861,32 +1094,41 @@ class DRAMCtrl : public AbstractMemory
     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();
+    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() override;
+    virtual void startup() override;
+    virtual void drainResume() override;
 
-    virtual void init() M5_ATTR_OVERRIDE;
-    virtual void startup() M5_ATTR_OVERRIDE;
-    virtual void drainResume() M5_ATTR_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: