/* * 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 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 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 writeRespQueue; std::deque 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, uint8_t pseudo_channel = 0) 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 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 doBurstAccess(MemPacket* pkt, Tick next_burst_at, const std::vector& 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__