/* * 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 #include #include #include #include #include "base/compiler.hh" #include "base/statistics.hh" #include "enums/AddrMap.hh" #include "enums/PageManage.hh" #include "mem/abstract_mem.hh" #include "mem/mem_ctrl.hh" #include "params/MemInterface.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 memory controller 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; /** * NVM specific variable, but declaring it here allows * treating different interfaces in a more genral way * at the memory controller's end */ uint32_t numWritesQueued; /** * Till when the controller must wait before issuing next RD/WR burst? */ Tick nextBurstAt = 0; Tick nextReqTime = 0; /** * Reads/writes performed by the controller for this interface before * bus direction is switched */ uint32_t readsThisTime = 0; uint32_t writesThisTime = 0; /** * Read/write packets in the read/write queue for this interface * qos/mem_ctrl.hh has similar counters, but they track all packets * in the controller for all memory interfaces connected to the * controller. */ uint32_t readQueueSize = 0; uint32_t writeQueueSize = 0; MemCtrl::BusState busState = MemCtrl::READ; /** bus state for next request event triggered */ MemCtrl::BusState busStateNext = MemCtrl::READ; /** * pseudo channel number used for HBM modeling */ uint8_t pseudoChannel; /** 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 * @param pseudo_channel pseudo channel number */ void setCtrl(MemCtrl* _ctrl, unsigned int command_window, uint8_t pseudo_channel = 0); /** * 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 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 pseudo_channel pseudo channel number of the packet * @return A MemPacket pointer with the decoded information */ virtual MemPacket* decodePacket(const PacketPtr pkt, Addr pkt_addr, unsigned int size, bool is_read, uint8_t pseudo_channel = 0) { panic("MemInterface decodePacket should not be executed from here.\n"); return nullptr; } /** * 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; /** * This function checks if ranks are busy. */ virtual bool isBusy(bool read_queue_empty, bool all_writes_nvm) = 0; /** * This function performs the burst and update stats. */ virtual std::pair doBurstAccess(MemPacket* mem_pkt, Tick next_burst_at, const std::vector& queue) = 0; /** * This function is DRAM specific. */ virtual void respondEvent(uint8_t rank) { panic("MemInterface respondEvent should not be executed from here.\n"); }; /** * This function is DRAM specific. */ virtual void checkRefreshState(uint8_t rank) { panic("MemInterface checkRefreshState (DRAM) should " "not be executed from here.\n"); }; /** * This function is DRAM specific. */ virtual void drainRanks() { panic("MemInterface drainRanks (DRAM) should " "not be executed from here.\n"); } /** * This function is DRAM specific. */ virtual void suspend() { panic("MemInterface suspend (DRAM) should " "not be executed from here.\n"); } /** * This function is NVM specific. */ virtual bool readsWaitingToIssue() const { panic("MemInterface readsWaitingToIssue (NVM) " "should not be executed from here.\n"); }; /** * This function is NVM specific. */ virtual void chooseRead(MemPacketQueue& queue) { panic("MemInterface chooseRead (NVM) should " "not be executed from here.\n"); }; /** * This function is NVM specific. */ virtual bool writeRespQueueFull() const { panic("MemInterface writeRespQueueFull (NVM) " "should not be executed from here.\n"); } typedef MemInterfaceParams Params; MemInterface(const Params &_p); }; } // namespace memory } // namespace gem5 #endif //__MEM_INTERFACE_HH__