Files
gem5/src/mem/mem_interface.hh
Ayaz Akram 32df25e426 mem: HBMCtrl changes to allow PC data buses to be in different states
This change updates the HBMCtrl such that both pseudo channels
can be in separate states (read or write) at the same time. In
addition, the controller queues are now always split in two
halves for both pseudo channels.

Change-Id: Ifb599e611ad99f6c511baaf245bad2b5c9210a86
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/65491
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
2023-05-26 20:08:00 +00:00

424 lines
13 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/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<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 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<Tick, Tick>
doBurstAccess(MemPacket* mem_pkt, Tick next_burst_at,
const std::vector<MemPacketQueue>& 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__