Files
gem5/src/mem/nvm_interface.hh
Maryam Babaie c7c11c5661 mem: splitting dram and nvm interfaces into separate files
This change primarily splits the dram and nvm interfaces
into separate files. And also updates the interfaces so that
they can be handled in a more general way by the controller.
For example, both interfaces now override a virtual isBusy()
function defined in the mem_interface.

Change-Id: Id98bf0be3836a4b6245d5dea1b8fad0a60ce299a
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/59730
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Bobby Bruce <bbruce@ucdavis.edu>
Reviewed-by: Bobby Bruce <bbruce@ucdavis.edu>
2022-06-06 18:31:06 +00:00

323 lines
9.8 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
* NVMInterface declaration
*/
#ifndef __NVM_INTERFACE_HH__
#define __NVM_INTERFACE_HH__
#include "mem/mem_interface.hh"
#include "params/NVMInterface.hh"
namespace gem5
{
namespace memory
{
/**
* 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;
/**
* 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;
MemPacket* decodePacket(const PacketPtr pkt, Addr pkt_addr,
unsigned int size, 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) override;
/**
* 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;
/**
* Following two functions are not required for nvm interface
*/
void respondEvent(uint8_t rank) override { };
void checkRefreshState(uint8_t rank) override { };
/**
* Select read command to issue asynchronously
*/
void chooseRead(MemPacketQueue& queue) override;
/*
* 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 override
{
return writeRespQueue.size() == maxPendingWrites;
}
bool
readsWaitingToIssue() const override
{
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,
const std::vector<MemPacketQueue>& queue) override;
/**
* The next three functions are DRAM-specific and will be ignored by NVM.
*/
void drainRanks() override { }
void suspend() override { }
void startup() override { }
NVMInterface(const NVMInterfaceParams &_p);
};
} // namespace memory
} // namespace gem5
#endif //__NVM_INTERFACE_HH__