Encapsulate every class inheriting from Abstract or Physical memories, and the memory controller in a memory namespace. Change-Id: I228f7e55efc395089e3616ae0a0a6325867bd782 Issued-on: https://gem5.atlassian.net/browse/GEM5-983 Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br> Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/47309 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Jason Lowe-Power <power.jg@gmail.com> Maintainer: Jason Lowe-Power <power.jg@gmail.com>
1273 lines
38 KiB
C++
1273 lines
38 KiB
C++
/*
|
|
* Copyright (c) 2012-2020 ARM Limited
|
|
* All rights reserved
|
|
*
|
|
* The license below extends only to copyright in the software and shall
|
|
* not be construed as granting a license to any other intellectual
|
|
* property including but not limited to intellectual property relating
|
|
* to a hardware implementation of the functionality of the software
|
|
* licensed hereunder. You may use the software subject to the license
|
|
* terms below provided that you ensure that this notice is replicated
|
|
* unmodified and in its entirety in all distributions of the software,
|
|
* modified or unmodified, in source code or in binary form.
|
|
*
|
|
* Copyright (c) 2013 Amin Farmahini-Farahani
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met: redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer;
|
|
* redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution;
|
|
* neither the name of the copyright holders nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* MemInterface declaration
|
|
*/
|
|
|
|
#ifndef __MEM_INTERFACE_HH__
|
|
#define __MEM_INTERFACE_HH__
|
|
|
|
#include <deque>
|
|
#include <string>
|
|
#include <unordered_set>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "base/compiler.hh"
|
|
#include "base/statistics.hh"
|
|
#include "enums/AddrMap.hh"
|
|
#include "enums/PageManage.hh"
|
|
#include "mem/abstract_mem.hh"
|
|
#include "mem/drampower.hh"
|
|
#include "mem/mem_ctrl.hh"
|
|
#include "params/DRAMInterface.hh"
|
|
#include "params/MemInterface.hh"
|
|
#include "params/NVMInterface.hh"
|
|
#include "sim/eventq.hh"
|
|
|
|
namespace gem5
|
|
{
|
|
|
|
namespace memory
|
|
{
|
|
|
|
/**
|
|
* General interface to memory device
|
|
* Includes functions and parameters shared across media types
|
|
*/
|
|
class MemInterface : public AbstractMemory
|
|
{
|
|
protected:
|
|
/**
|
|
* 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
|
|
* column (read/write) command, when can it be precharged, and
|
|
* when can it be activated.
|
|
*
|
|
* The bank also keeps track of how many bytes have been accessed
|
|
* in the open row since it was opened.
|
|
*/
|
|
class Bank
|
|
{
|
|
|
|
public:
|
|
static const uint32_t NO_ROW = -1;
|
|
|
|
uint32_t openRow;
|
|
uint8_t bank;
|
|
uint8_t bankgr;
|
|
|
|
Tick rdAllowedAt;
|
|
Tick wrAllowedAt;
|
|
Tick preAllowedAt;
|
|
Tick actAllowedAt;
|
|
|
|
uint32_t rowAccesses;
|
|
uint32_t bytesAccessed;
|
|
|
|
Bank() :
|
|
openRow(NO_ROW), bank(0), bankgr(0),
|
|
rdAllowedAt(0), wrAllowedAt(0), preAllowedAt(0), actAllowedAt(0),
|
|
rowAccesses(0), bytesAccessed(0)
|
|
{ }
|
|
};
|
|
|
|
/**
|
|
* A pointer to the parent MemCtrl instance
|
|
*/
|
|
MemCtrl* ctrl;
|
|
|
|
/**
|
|
* Number of commands that can issue in the defined controller
|
|
* command window, used to verify command bandwidth
|
|
*/
|
|
unsigned int maxCommandsPerWindow;
|
|
|
|
/**
|
|
* Memory controller configuration initialized based on parameter
|
|
* values.
|
|
*/
|
|
enums::AddrMap addrMapping;
|
|
|
|
/**
|
|
* General device and channel characteristics
|
|
* The rowsPerBank is determined based on the capacity, number of
|
|
* ranks and banks, the burst size, and the row buffer size.
|
|
*/
|
|
const uint32_t burstSize;
|
|
const uint32_t deviceSize;
|
|
const uint32_t deviceRowBufferSize;
|
|
const uint32_t devicesPerRank;
|
|
const uint32_t rowBufferSize;
|
|
const uint32_t burstsPerRowBuffer;
|
|
const uint32_t burstsPerStripe;
|
|
const uint32_t ranksPerChannel;
|
|
const uint32_t banksPerRank;
|
|
uint32_t rowsPerBank;
|
|
|
|
/**
|
|
* General timing requirements
|
|
*/
|
|
GEM5_CLASS_VAR_USED const Tick tCK;
|
|
const Tick tCS;
|
|
const Tick tBURST;
|
|
const Tick tRTW;
|
|
const Tick tWTR;
|
|
|
|
/*
|
|
* @return delay between write and read commands
|
|
*/
|
|
virtual Tick writeToReadDelay() const { return tBURST + tWTR; }
|
|
|
|
/*
|
|
* @return delay between write and read commands
|
|
*/
|
|
Tick readToWriteDelay() const { return tBURST + tRTW; }
|
|
|
|
/*
|
|
* @return delay between accesses to different ranks
|
|
*/
|
|
Tick rankToRankDelay() const { return tBURST + tCS; }
|
|
|
|
|
|
public:
|
|
|
|
/**
|
|
* Buffer sizes for read and write queues in the controller
|
|
* These are passed to the controller on instantiation
|
|
* Defining them here allows for buffers to be resized based
|
|
* on memory type / configuration.
|
|
*/
|
|
const uint32_t readBufferSize;
|
|
const uint32_t writeBufferSize;
|
|
|
|
/** Set a pointer to the controller and initialize
|
|
* interface based on controller parameters
|
|
* @param _ctrl pointer to the parent controller
|
|
* @param command_window size of command window used to
|
|
* check command bandwidth
|
|
*/
|
|
void setCtrl(MemCtrl* _ctrl, unsigned int command_window);
|
|
|
|
/**
|
|
* Get an address in a dense range which starts from 0. The input
|
|
* address is the physical address of the request in an address
|
|
* space that contains other SimObjects apart from this
|
|
* controller.
|
|
*
|
|
* @param addr The intput address which should be in the addrRange
|
|
* @return An address in the continues range [0, max)
|
|
*/
|
|
Addr getCtrlAddr(Addr addr) { return range.getOffset(addr); }
|
|
|
|
/**
|
|
* Setup the rank based on packet received
|
|
*
|
|
* @param integer value of rank to be setup. used to index ranks vector
|
|
* @param are we setting up rank for read or write packet?
|
|
*/
|
|
virtual void setupRank(const uint8_t rank, const bool is_read) = 0;
|
|
|
|
/**
|
|
* Check drain state of interface
|
|
*
|
|
* @return true if all ranks are drained and idle
|
|
*
|
|
*/
|
|
virtual bool allRanksDrained() const = 0;
|
|
|
|
/**
|
|
* For FR-FCFS policy, find first command that can issue
|
|
* Function will be overriden by interface to select based
|
|
* on media characteristics, used to determine when read
|
|
* or write can issue.
|
|
*
|
|
* @param queue Queued requests to consider
|
|
* @param min_col_at Minimum tick for 'seamless' issue
|
|
* @return an iterator to the selected packet, else queue.end()
|
|
* @return the tick when the packet selected will issue
|
|
*/
|
|
virtual std::pair<MemPacketQueue::iterator, Tick>
|
|
chooseNextFRFCFS(MemPacketQueue& queue, Tick min_col_at) const = 0;
|
|
|
|
/*
|
|
* Function to calulate unloaded latency
|
|
*/
|
|
virtual Tick accessLatency() const = 0;
|
|
|
|
/**
|
|
* @return number of bytes in a burst for this interface
|
|
*/
|
|
uint32_t bytesPerBurst() const { return burstSize; }
|
|
|
|
/*
|
|
* @return time to offset next command
|
|
*/
|
|
virtual Tick commandOffset() const = 0;
|
|
|
|
/**
|
|
* Check if a burst operation can be issued to the interface
|
|
*
|
|
* @param Return true if RD/WR can issue
|
|
*/
|
|
virtual bool burstReady(MemPacket* pkt) const = 0;
|
|
|
|
/**
|
|
* Determine the required delay for an access to a different rank
|
|
*
|
|
* @return required rank to rank delay
|
|
*/
|
|
Tick rankDelay() const { return tCS; }
|
|
|
|
/**
|
|
*
|
|
* @return minimum additional bus turnaround required for read-to-write
|
|
*/
|
|
Tick minReadToWriteDataGap() const { return std::min(tRTW, tCS); }
|
|
|
|
/**
|
|
*
|
|
* @return minimum additional bus turnaround required for write-to-read
|
|
*/
|
|
Tick minWriteToReadDataGap() const { return std::min(tWTR, tCS); }
|
|
|
|
/**
|
|
* Address decoder to figure out physical mapping onto ranks,
|
|
* banks, and rows. This function is called multiple times on the same
|
|
* system packet if the pakcet is larger than burst of the memory. The
|
|
* pkt_addr is used for the offset within the packet.
|
|
*
|
|
* @param pkt The packet from the outside world
|
|
* @param pkt_addr The starting address of the packet
|
|
* @param size The size of the packet in bytes
|
|
* @param is_read Is the request for a read or a write to memory
|
|
* @param is_dram Is the request to a DRAM interface
|
|
* @return A MemPacket pointer with the decoded information
|
|
*/
|
|
MemPacket* decodePacket(const PacketPtr pkt, Addr pkt_addr,
|
|
unsigned int size, bool is_read, bool is_dram);
|
|
|
|
/**
|
|
* Add rank to rank delay to bus timing to all banks in all ranks
|
|
* when access to an alternate interface is issued
|
|
*
|
|
* param cmd_at Time of current command used as starting point for
|
|
* addition of rank-to-rank delay
|
|
*/
|
|
virtual void addRankToRankDelay(Tick cmd_at) = 0;
|
|
|
|
typedef MemInterfaceParams Params;
|
|
MemInterface(const Params &_p);
|
|
};
|
|
|
|
/**
|
|
* Interface to DRAM devices with media specific parameters,
|
|
* statistics, and functions.
|
|
* The DRAMInterface includes a class for individual ranks
|
|
* and per rank functions.
|
|
*/
|
|
class DRAMInterface : public MemInterface
|
|
{
|
|
private:
|
|
/**
|
|
* 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)
|
|
{ }
|
|
};
|
|
|
|
/**
|
|
* 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
|
|
};
|
|
|
|
class Rank;
|
|
struct RankStats : public statistics::Group
|
|
{
|
|
RankStats(DRAMInterface &dram, Rank &rank);
|
|
|
|
void regStats() override;
|
|
void resetStats() override;
|
|
void preDumpStats() override;
|
|
|
|
Rank &rank;
|
|
|
|
/*
|
|
* Command energies
|
|
*/
|
|
statistics::Scalar actEnergy;
|
|
statistics::Scalar preEnergy;
|
|
statistics::Scalar readEnergy;
|
|
statistics::Scalar writeEnergy;
|
|
statistics::Scalar refreshEnergy;
|
|
|
|
/*
|
|
* Active Background Energy
|
|
*/
|
|
statistics::Scalar actBackEnergy;
|
|
|
|
/*
|
|
* Precharge Background Energy
|
|
*/
|
|
statistics::Scalar preBackEnergy;
|
|
|
|
/*
|
|
* Active Power-Down Energy
|
|
*/
|
|
statistics::Scalar actPowerDownEnergy;
|
|
|
|
/*
|
|
* Precharge Power-Down Energy
|
|
*/
|
|
statistics::Scalar prePowerDownEnergy;
|
|
|
|
/*
|
|
* self Refresh Energy
|
|
*/
|
|
statistics::Scalar selfRefreshEnergy;
|
|
|
|
statistics::Scalar totalEnergy;
|
|
statistics::Scalar averagePower;
|
|
|
|
/**
|
|
* Stat to track total DRAM idle time
|
|
*
|
|
*/
|
|
statistics::Scalar totalIdleTime;
|
|
|
|
/**
|
|
* Track time spent in each power state.
|
|
*/
|
|
statistics::Vector pwrStateTime;
|
|
};
|
|
|
|
/**
|
|
* 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 DRAMInterface instance
|
|
*/
|
|
DRAMInterface& dram;
|
|
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* 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 low-power exit until this requirement is met
|
|
*/
|
|
Tick wakeUpAllowedAt;
|
|
|
|
/**
|
|
* One DRAMPower instance per rank
|
|
*/
|
|
DRAMPower power;
|
|
|
|
/**
|
|
* List of commands 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;
|
|
|
|
/**
|
|
* Track when we issued the last read/write burst
|
|
*/
|
|
Tick lastBurstTick;
|
|
|
|
Rank(const DRAMInterfaceParams &_p, int _rank,
|
|
DRAMInterface& _dram);
|
|
|
|
const std::string name() const { return csprintf("%d", 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;
|
|
|
|
/**
|
|
* 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();
|
|
|
|
/**
|
|
* 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;
|
|
|
|
protected:
|
|
RankStats stats;
|
|
};
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* DRAM specific device characteristics
|
|
*/
|
|
const uint32_t bankGroupsPerRank;
|
|
const bool bankGroupArch;
|
|
|
|
/**
|
|
* DRAM specific timing requirements
|
|
*/
|
|
const Tick tCL;
|
|
const Tick tBURST_MIN;
|
|
const Tick tBURST_MAX;
|
|
const Tick tCCD_L_WR;
|
|
const Tick tCCD_L;
|
|
const Tick tRCD;
|
|
const Tick tRP;
|
|
const Tick tRAS;
|
|
const Tick tWR;
|
|
const Tick tRTP;
|
|
const Tick tRFC;
|
|
const Tick tREFI;
|
|
const Tick tRRD;
|
|
const Tick tRRD_L;
|
|
const Tick tPPD;
|
|
const Tick tAAD;
|
|
const Tick tXAW;
|
|
const Tick tXP;
|
|
const Tick tXS;
|
|
const Tick clkResyncDelay;
|
|
const bool dataClockSync;
|
|
const bool burstInterleave;
|
|
const uint8_t twoCycleActivate;
|
|
const uint32_t activationLimit;
|
|
const Tick wrToRdDlySameBG;
|
|
const Tick rdToWrDlySameBG;
|
|
|
|
|
|
enums::PageManage pageMgmt;
|
|
/**
|
|
* Max column accesses (read and write) per row, before forefully
|
|
* closing it.
|
|
*/
|
|
const uint32_t maxAccessesPerRow;
|
|
|
|
// timestamp offset
|
|
uint64_t timeStampOffset;
|
|
|
|
// Holds the value of the DRAM rank of burst issued
|
|
uint8_t activeRank;
|
|
|
|
/** Enable or disable DRAM powerdown states. */
|
|
bool enableDRAMPowerdown;
|
|
|
|
/** The time when stats were last reset used to calculate average power */
|
|
Tick lastStatsResetTick;
|
|
|
|
/**
|
|
* Keep track of when row activations happen, in order to enforce
|
|
* the maximum number of activations in the activation window. The
|
|
* 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 row Index of the 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_tick Time when the precharge takes place
|
|
* @param auto_or_preall Is this an auto-precharge or precharge all command
|
|
* @param trace Is this an auto precharge then do not add to trace
|
|
*/
|
|
void prechargeBank(Rank& rank_ref, Bank& bank_ref,
|
|
Tick pre_tick, bool auto_or_preall = false,
|
|
bool trace = true);
|
|
|
|
struct DRAMStats : public statistics::Group
|
|
{
|
|
DRAMStats(DRAMInterface &dram);
|
|
|
|
void regStats() override;
|
|
void resetStats() override;
|
|
|
|
DRAMInterface &dram;
|
|
|
|
/** total number of DRAM bursts serviced */
|
|
statistics::Scalar readBursts;
|
|
statistics::Scalar writeBursts;
|
|
|
|
/** DRAM per bank stats */
|
|
statistics::Vector perBankRdBursts;
|
|
statistics::Vector perBankWrBursts;
|
|
|
|
// Latencies summed over all requests
|
|
statistics::Scalar totQLat;
|
|
statistics::Scalar totBusLat;
|
|
statistics::Scalar totMemAccLat;
|
|
|
|
// Average latencies per request
|
|
statistics::Formula avgQLat;
|
|
statistics::Formula avgBusLat;
|
|
statistics::Formula avgMemAccLat;
|
|
|
|
// Row hit count and rate
|
|
statistics::Scalar readRowHits;
|
|
statistics::Scalar writeRowHits;
|
|
statistics::Formula readRowHitRate;
|
|
statistics::Formula writeRowHitRate;
|
|
statistics::Histogram bytesPerActivate;
|
|
// Number of bytes transferred to/from DRAM
|
|
statistics::Scalar bytesRead;
|
|
statistics::Scalar bytesWritten;
|
|
|
|
// Average bandwidth
|
|
statistics::Formula avgRdBW;
|
|
statistics::Formula avgWrBW;
|
|
statistics::Formula peakBW;
|
|
// bus utilization
|
|
statistics::Formula busUtil;
|
|
statistics::Formula busUtilRead;
|
|
statistics::Formula busUtilWrite;
|
|
statistics::Formula pageHitRate;
|
|
};
|
|
|
|
DRAMStats stats;
|
|
|
|
/**
|
|
* Vector of dram ranks
|
|
*/
|
|
std::vector<Rank*> ranks;
|
|
|
|
/*
|
|
* @return delay between write and read commands
|
|
*/
|
|
Tick writeToReadDelay() const override { return tBURST + tWTR + tCL; }
|
|
|
|
/**
|
|
* Find which are the earliest banks ready to issue an activate
|
|
* 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 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<std::vector<uint32_t>, bool>
|
|
minBankPrep(const MemPacketQueue& queue, Tick min_col_at) const;
|
|
|
|
/*
|
|
* @return time to send a burst of data without gaps
|
|
*/
|
|
Tick
|
|
burstDelay() const
|
|
{
|
|
return (burstInterleave ? tBURST_MAX / 2 : tBURST);
|
|
}
|
|
|
|
public:
|
|
/**
|
|
* Initialize the DRAM interface and verify parameters
|
|
*/
|
|
void init() override;
|
|
|
|
/**
|
|
* Iterate through dram ranks and instantiate per rank startup routine
|
|
*/
|
|
void startup() override;
|
|
|
|
/**
|
|
* Setup the rank based on packet received
|
|
*
|
|
* @param integer value of rank to be setup. used to index ranks vector
|
|
* @param are we setting up rank for read or write packet?
|
|
*/
|
|
void setupRank(const uint8_t rank, const bool is_read) override;
|
|
|
|
/**
|
|
* Iterate through dram ranks to exit self-refresh in order to drain
|
|
*/
|
|
void drainRanks();
|
|
|
|
/**
|
|
* 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 override;
|
|
|
|
/**
|
|
* Iterate through DRAM ranks and suspend them
|
|
*/
|
|
void suspend();
|
|
|
|
/*
|
|
* @return time to offset next command
|
|
*/
|
|
Tick commandOffset() const override { return (tRP + tRCD); }
|
|
|
|
/*
|
|
* Function to calulate unloaded, closed bank access latency
|
|
*/
|
|
Tick accessLatency() const override { return (tRP + tRCD + tCL); }
|
|
|
|
/**
|
|
* For FR-FCFS policy, find first DRAM command that can issue
|
|
*
|
|
* @param queue Queued requests to consider
|
|
* @param min_col_at Minimum tick for 'seamless' issue
|
|
* @return an iterator to the selected packet, else queue.end()
|
|
* @return the tick when the packet selected will issue
|
|
*/
|
|
std::pair<MemPacketQueue::iterator, Tick>
|
|
chooseNextFRFCFS(MemPacketQueue& queue, Tick min_col_at) const override;
|
|
|
|
/**
|
|
* Actually do the burst - figure out the latency it
|
|
* will take to service the req based on bank state, channel state etc
|
|
* and then update those states to account for this request. Based
|
|
* on this, update the packet's "readyTime" and move it to the
|
|
* response q from where it will eventually go back to the outside
|
|
* world.
|
|
*
|
|
* @param mem_pkt The packet created from the outside world pkt
|
|
* @param next_burst_at Minimum bus timing requirement from controller
|
|
* @param queue Reference to the read or write queue with the packet
|
|
* @return pair, tick when current burst is issued and
|
|
* tick when next burst can issue
|
|
*/
|
|
std::pair<Tick, Tick>
|
|
doBurstAccess(MemPacket* mem_pkt, Tick next_burst_at,
|
|
const std::vector<MemPacketQueue>& queue);
|
|
|
|
/**
|
|
* Check if a burst operation can be issued to the DRAM
|
|
*
|
|
* @param Return true if RD/WR can issue
|
|
* This requires the DRAM to be in the
|
|
* REF IDLE state
|
|
*/
|
|
bool
|
|
burstReady(MemPacket* pkt) const override
|
|
{
|
|
return ranks[pkt->rank]->inRefIdleState();
|
|
}
|
|
|
|
/**
|
|
* This function checks if ranks are actively refreshing and
|
|
* therefore busy. The function also checks if ranks are in
|
|
* the self-refresh state, in which case, a self-refresh exit
|
|
* is initiated.
|
|
*
|
|
* return boolean if all ranks are in refresh and therefore busy
|
|
*/
|
|
bool isBusy();
|
|
|
|
/**
|
|
* Add rank to rank delay to bus timing to all DRAM banks in alli ranks
|
|
* when access to an alternate interface is issued
|
|
*
|
|
* param cmd_at Time of current command used as starting point for
|
|
* addition of rank-to-rank delay
|
|
*/
|
|
void addRankToRankDelay(Tick cmd_at) override;
|
|
|
|
/**
|
|
* Complete response process for DRAM when read burst is complete
|
|
* This will update the counters and check if a power down state
|
|
* can be entered.
|
|
*
|
|
* @param rank Specifies rank associated with read burst
|
|
*/
|
|
void respondEvent(uint8_t rank);
|
|
|
|
/**
|
|
* Check the refresh state to determine if refresh needs
|
|
* to be kicked back into action after a read response
|
|
*
|
|
* @param rank Specifies rank associated with read burst
|
|
*/
|
|
void checkRefreshState(uint8_t rank);
|
|
|
|
DRAMInterface(const DRAMInterfaceParams &_p);
|
|
};
|
|
|
|
/**
|
|
* Interface to NVM devices with media specific parameters,
|
|
* statistics, and functions.
|
|
* The NVMInterface includes a class for individual ranks
|
|
* and per rank functions.
|
|
*/
|
|
class NVMInterface : public MemInterface
|
|
{
|
|
private:
|
|
/**
|
|
* NVM rank class simply includes a vector of banks.
|
|
*/
|
|
class Rank : public EventManager
|
|
{
|
|
public:
|
|
|
|
/**
|
|
* Current Rank index
|
|
*/
|
|
uint8_t rank;
|
|
|
|
/**
|
|
* Vector of NVM banks. Each rank is made of several banks
|
|
* that can be accessed in parallel.
|
|
*/
|
|
std::vector<Bank> banks;
|
|
|
|
Rank(const NVMInterfaceParams &_p, int _rank,
|
|
NVMInterface& _nvm);
|
|
};
|
|
|
|
/**
|
|
* NVM specific device and channel characteristics
|
|
*/
|
|
const uint32_t maxPendingWrites;
|
|
const uint32_t maxPendingReads;
|
|
const bool twoCycleRdWr;
|
|
|
|
/**
|
|
* NVM specific timing requirements
|
|
*/
|
|
const Tick tREAD;
|
|
const Tick tWRITE;
|
|
const Tick tSEND;
|
|
|
|
struct NVMStats : public statistics::Group
|
|
{
|
|
NVMStats(NVMInterface &nvm);
|
|
|
|
void regStats() override;
|
|
|
|
NVMInterface &nvm;
|
|
|
|
/** NVM stats */
|
|
statistics::Scalar readBursts;
|
|
statistics::Scalar writeBursts;
|
|
|
|
statistics::Vector perBankRdBursts;
|
|
statistics::Vector perBankWrBursts;
|
|
|
|
// Latencies summed over all requests
|
|
statistics::Scalar totQLat;
|
|
statistics::Scalar totBusLat;
|
|
statistics::Scalar totMemAccLat;
|
|
|
|
// Average latencies per request
|
|
statistics::Formula avgQLat;
|
|
statistics::Formula avgBusLat;
|
|
statistics::Formula avgMemAccLat;
|
|
|
|
statistics::Scalar bytesRead;
|
|
statistics::Scalar bytesWritten;
|
|
|
|
// Average bandwidth
|
|
statistics::Formula avgRdBW;
|
|
statistics::Formula avgWrBW;
|
|
statistics::Formula peakBW;
|
|
statistics::Formula busUtil;
|
|
statistics::Formula busUtilRead;
|
|
statistics::Formula busUtilWrite;
|
|
|
|
/** NVM stats */
|
|
statistics::Histogram pendingReads;
|
|
statistics::Histogram pendingWrites;
|
|
statistics::Histogram bytesPerBank;
|
|
};
|
|
NVMStats stats;
|
|
|
|
void processWriteRespondEvent();
|
|
EventFunctionWrapper writeRespondEvent;
|
|
|
|
void processReadReadyEvent();
|
|
EventFunctionWrapper readReadyEvent;
|
|
|
|
/**
|
|
* Vector of nvm ranks
|
|
*/
|
|
std::vector<Rank*> ranks;
|
|
|
|
/**
|
|
* Holding queue for non-deterministic write commands, which
|
|
* maintains writes that have been issued but have not completed
|
|
* Stored seperately mostly to keep the code clean and help with
|
|
* events scheduling.
|
|
* This mimics a buffer on the media controller and therefore is
|
|
* not added to the main write queue for sizing
|
|
*/
|
|
std::list<Tick> writeRespQueue;
|
|
|
|
std::deque<Tick> readReadyQueue;
|
|
|
|
/**
|
|
* Check if the write response queue is empty
|
|
*
|
|
* @param Return true if empty
|
|
*/
|
|
bool writeRespQueueEmpty() const { return writeRespQueue.empty(); }
|
|
|
|
/**
|
|
* Till when must we wait before issuing next read command?
|
|
*/
|
|
Tick nextReadAt;
|
|
|
|
// keep track of reads that have issued for which data is either
|
|
// not yet ready or has not yet been transferred to the ctrl
|
|
uint16_t numPendingReads;
|
|
uint16_t numReadDataReady;
|
|
|
|
public:
|
|
// keep track of the number of reads that have yet to be issued
|
|
uint16_t numReadsToIssue;
|
|
|
|
// number of writes in the writeQueue for the NVM interface
|
|
uint32_t numWritesQueued;
|
|
|
|
/**
|
|
* Initialize the NVM interface and verify parameters
|
|
*/
|
|
void init() override;
|
|
|
|
/**
|
|
* Setup the rank based on packet received
|
|
*
|
|
* @param integer value of rank to be setup. used to index ranks vector
|
|
* @param are we setting up rank for read or write packet?
|
|
*/
|
|
void setupRank(const uint8_t rank, const bool is_read) override;
|
|
|
|
/**
|
|
* Check drain state of NVM interface
|
|
*
|
|
* @return true if write response queue is empty
|
|
*
|
|
*/
|
|
bool allRanksDrained() const override { return writeRespQueueEmpty(); }
|
|
|
|
/*
|
|
* @return time to offset next command
|
|
*/
|
|
Tick commandOffset() const override { return tBURST; }
|
|
|
|
/**
|
|
* Check if a burst operation can be issued to the NVM
|
|
*
|
|
* @param Return true if RD/WR can issue
|
|
* for reads, also verfy that ready count
|
|
* has been updated to a non-zero value to
|
|
* account for race conditions between events
|
|
*/
|
|
bool burstReady(MemPacket* pkt) const override;
|
|
|
|
/**
|
|
* This function checks if ranks are busy.
|
|
* This state is true when either:
|
|
* 1) There is no command with read data ready to transmit or
|
|
* 2) The NVM inteface has reached the maximum number of outstanding
|
|
* writes commands.
|
|
* @param read_queue_empty There are no read queued
|
|
* @param all_writes_nvm All writes in queue are for NVM interface
|
|
* @return true of NVM is busy
|
|
*
|
|
*/
|
|
bool isBusy(bool read_queue_empty, bool all_writes_nvm);
|
|
/**
|
|
* For FR-FCFS policy, find first NVM command that can issue
|
|
* default to first command to prepped region
|
|
*
|
|
* @param queue Queued requests to consider
|
|
* @param min_col_at Minimum tick for 'seamless' issue
|
|
* @return an iterator to the selected packet, else queue.end()
|
|
* @return the tick when the packet selected will issue
|
|
*/
|
|
std::pair<MemPacketQueue::iterator, Tick>
|
|
chooseNextFRFCFS(MemPacketQueue& queue, Tick min_col_at) const override;
|
|
|
|
/**
|
|
* Add rank to rank delay to bus timing to all NVM banks in alli ranks
|
|
* when access to an alternate interface is issued
|
|
*
|
|
* param cmd_at Time of current command used as starting point for
|
|
* addition of rank-to-rank delay
|
|
*/
|
|
void addRankToRankDelay(Tick cmd_at) override;
|
|
|
|
|
|
/**
|
|
* Select read command to issue asynchronously
|
|
*/
|
|
void chooseRead(MemPacketQueue& queue);
|
|
|
|
/*
|
|
* Function to calulate unloaded access latency
|
|
*/
|
|
Tick accessLatency() const override { return (tREAD + tSEND); }
|
|
|
|
/**
|
|
* Check if the write response queue has reached defined threshold
|
|
*
|
|
* @param Return true if full
|
|
*/
|
|
bool
|
|
writeRespQueueFull() const
|
|
{
|
|
return writeRespQueue.size() == maxPendingWrites;
|
|
}
|
|
|
|
bool
|
|
readsWaitingToIssue() const
|
|
{
|
|
return ((numReadsToIssue != 0) &&
|
|
(numPendingReads < maxPendingReads));
|
|
}
|
|
|
|
/**
|
|
* Actually do the burst and update stats.
|
|
*
|
|
* @param pkt The packet created from the outside world pkt
|
|
* @param next_burst_at Minimum bus timing requirement from controller
|
|
* @return pair, tick when current burst is issued and
|
|
* tick when next burst can issue
|
|
*/
|
|
std::pair<Tick, Tick>
|
|
doBurstAccess(MemPacket* pkt, Tick next_burst_at);
|
|
|
|
NVMInterface(const NVMInterfaceParams &_p);
|
|
};
|
|
|
|
} // namespace memory
|
|
} // namespace gem5
|
|
|
|
#endif //__MEM_INTERFACE_HH__
|