X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fdram_ctrl.hh;h=3aa06feac5608b0364f6cd82cb4f0a73023ab9fd;hb=f49830ce0ba79c54c65c9c4b25bc3c6184aaf2a9;hp=0dbff7eaf58593bae771e163f5eecc7aa1b43254;hpb=cc4ca78f99f1e08309461554362ec09d3e5eed26;p=gem5.git diff --git a/src/mem/dram_ctrl.hh b/src/mem/dram_ctrl.hh index 0dbff7eaf..3aa06feac 100644 --- a/src/mem/dram_ctrl.hh +++ b/src/mem/dram_ctrl.hh @@ -40,6 +40,7 @@ * Authors: Andreas Hansson * Ani Udipi * Neha Agarwal + * Omar Naji */ /** @@ -51,6 +52,7 @@ #define __MEM_DRAM_CTRL_HH__ #include +#include #include "base/statistics.hh" #include "enums/AddrMap.hh" @@ -60,25 +62,28 @@ #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. */ class DRAMCtrl : public AbstractMemory { @@ -115,6 +120,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. */ @@ -134,9 +144,6 @@ class DRAMCtrl : public AbstractMemory BusState busState; - /** List to keep track of activate ticks */ - std::vector> actTicks; - /** * 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 @@ -154,6 +161,8 @@ class DRAMCtrl : public AbstractMemory static const uint32_t NO_ROW = -1; uint32_t openRow; + uint8_t bank; + uint8_t bankgr; Tick colAllowedAt; Tick preAllowedAt; @@ -163,11 +172,219 @@ class DRAMCtrl : public AbstractMemory uint32_t bytesAccessed; Bank() : - openRow(NO_ROW), colAllowedAt(0), preAllowedAt(0), actAllowedAt(0), + openRow(NO_ROW), bank(0), bankgr(0), + colAllowedAt(0), preAllowedAt(0), actAllowedAt(0), rowAccesses(0), bytesAccessed(0) { } }; + + /** + * 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 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 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 + activateEvent; + + void processPrechargeEvent(); + EventWrapper + prechargeEvent; + + void processRefreshEvent(); + EventWrapper + refreshEvent; + + void processPowerEvent(); + EventWrapper + powerEvent; + + }; + /** * 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 @@ -186,7 +403,7 @@ class DRAMCtrl : public AbstractMemory BurstHelper(unsigned int _burstCount) : burstCount(_burstCount), burstsServiced(0) - { } + { } }; /** @@ -211,7 +428,7 @@ class DRAMCtrl : public AbstractMemory /** Will be populated by address decoder */ const uint8_t rank; const uint8_t bank; - const uint16_t row; + const uint32_t row; /** * Bank id is calculated considering banks in all the ranks @@ -240,14 +457,15 @@ class DRAMCtrl : public AbstractMemory */ BurstHelper* burstHelper; Bank& bankRef; + Rank& rankRef; DRAMPacket(PacketPtr _pkt, bool is_read, uint8_t _rank, uint8_t _bank, - uint16_t _row, uint16_t bank_id, Addr _addr, - unsigned int _size, Bank& bank_ref) + uint32_t _row, uint16_t bank_id, Addr _addr, + 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) { } }; @@ -264,18 +482,6 @@ class DRAMCtrl : public AbstractMemory void processRespondEvent(); EventWrapper respondEvent; - void processActivateEvent(); - EventWrapper activateEvent; - - void processPrechargeEvent(); - EventWrapper prechargeEvent; - - void processRefreshEvent(); - EventWrapper refreshEvent; - - void processPowerEvent(); - EventWrapper powerEvent; - /** * Check if the read queue has room for more entries * @@ -363,23 +569,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 switched_cmd_type Command type is changing + * @return true if a packet is scheduled to a rank which is available else + * false */ - void chooseNext(std::deque& queue); + bool chooseNext(std::deque& queue, bool switched_cmd_type); /** * 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. + * + * @param queue Queued requests to consider + * @param switched_cmd_type Command type is changing + * @return true if a packet is scheduled to a rank which is available else + * false */ - void reorderQueue(std::deque& queue); + bool reorderQueue(std::deque& queue, bool switched_cmd_type); /** * Find which are the earliest banks ready to issue an activate * for the enqueued requests. Assumes maximum of 64 banks per DIMM + * Also checks if the bank is already prepped. * - * @param Queued requests to consider + * @param queue Queued requests to consider + * @param switched_cmd_type Command type is changing * @return One-hot encoded mask of bank indices */ - uint64_t minBankActAt(const std::deque& queue) const; + uint64_t minBankPrep(const std::deque& queue, + bool switched_cmd_type) const; /** * Keep track of when row activations happen, in order to enforce @@ -387,24 +610,26 @@ class DRAMCtrl : public AbstractMemory * method updates the time that the banks become available based * on the current limits. * + * @param rank_ref Reference to the rank + * @param bank_ref Reference to the bank * @param act_tick Time when the activation takes place - * @param rank Index of the rank - * @param bank Index of the bank * @param row Index of the row - * @param bank_ref Reference to the bank */ - void activateBank(Tick act_tick, uint8_t rank, uint8_t bank, - uint16_t row, Bank& bank_ref); + 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 bank The bank to precharge + * @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, Tick pre_at); + void prechargeBank(Rank& rank_ref, Bank& bank_ref, + Tick pre_at, bool trace = true); /** * Used for debugging to observe the contents of the queues. @@ -434,10 +659,9 @@ class DRAMCtrl : public AbstractMemory DrainManager *drainManager; /** - * Multi-dimensional vector of banks, first dimension is ranks, - * second is bank + * Vector of ranks */ - std::vector > banks; + std::vector ranks; /** * The following are basic design parameters of the memory @@ -445,6 +669,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; @@ -452,7 +677,10 @@ class DRAMCtrl : public AbstractMemory const uint32_t burstSize; const uint32_t rowBufferSize; 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; @@ -468,10 +696,12 @@ class DRAMCtrl : public AbstractMemory * Basic memory timing parameters initialized based on parameter * values. */ - const Tick tCK; + const Tick M5_CLASS_VAR_USED tCK; const Tick tWTR; const Tick tRTW; + const Tick tCS; const Tick tBURST; + const Tick tCCD_L; const Tick tRCD; const Tick tCL; const Tick tRP; @@ -481,6 +711,7 @@ class DRAMCtrl : public AbstractMemory const Tick tRFC; const Tick tREFI; const Tick tRRD; + const Tick tRRD_L; const Tick tXAW; const uint32_t activationLimit; @@ -517,72 +748,6 @@ class DRAMCtrl : public AbstractMemory */ 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 prevArrival; /** @@ -652,13 +817,12 @@ 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; - // To track number of banks which are currently active - unsigned int numBanksActive; + // 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 @@ -666,6 +830,30 @@ class DRAMCtrl : public AbstractMemory */ std::vector 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 commands in the command list of DRAMPower. + * + * @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 + */ + static bool sortTime(const Data::MemCommand& m1, + const Data::MemCommand& m2) { + return m1.getTime() < m2.getTime(); + }; + + public: void regStats(); @@ -677,8 +865,9 @@ class DRAMCtrl : public AbstractMemory virtual BaseSlavePort& getSlavePort(const std::string& if_name, PortID idx = InvalidPortID); - virtual void init(); - virtual void startup(); + virtual void init() M5_ATTR_OVERRIDE; + virtual void startup() M5_ATTR_OVERRIDE; + virtual void drainResume() M5_ATTR_OVERRIDE; protected: