mem: Make MemCtrl a ClockedObject

Made DRAMCtrl a ClockedObject, with DRAMInterface
defined as an AbstractMemory. The address
ranges are now defined per interface. Currently
the model only includes a DRAMInterface but this
can be expanded for other media types.

The controller object includes a parameter to the
interface, which is setup when gem5 is configured.

Change-Id: I6a368b845d574a713c7196c5671188ca8c1dc5e8
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/28968
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Wendy Elsasser
2020-02-07 18:00:57 -06:00
committed by Jason Lowe-Power
parent 518e79ad2d
commit 4acc419b6f
26 changed files with 1913 additions and 1736 deletions

File diff suppressed because it is too large Load Diff

1473
src/mem/DRAMInterface.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
# -*- mode:python -*-
#
# Copyright (c) 2018-2019 ARM Limited
# Copyright (c) 2018-2020 ARM Limited
# All rights reserved
#
# The license below extends only to copyright in the software and shall
@@ -47,6 +47,7 @@ SimObject('AbstractMemory.py')
SimObject('AddrMapper.py')
SimObject('Bridge.py')
SimObject('DRAMCtrl.py')
SimObject('DRAMInterface.py')
SimObject('ExternalMaster.py')
SimObject('ExternalSlave.py')
SimObject('MemObject.py')

View File

@@ -47,6 +47,7 @@
#include "debug/DRAMState.hh"
#include "debug/Drain.hh"
#include "debug/QOS.hh"
#include "params/DRAMInterface.hh"
#include "sim/system.hh"
using namespace std;
@@ -58,12 +59,13 @@ DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) :
retryRdReq(false), retryWrReq(false),
nextReqEvent([this]{ processNextReqEvent(); }, name()),
respondEvent([this]{ processRespondEvent(); }, name()),
readBufferSize(p->read_buffer_size),
writeBufferSize(p->write_buffer_size),
dram(p->dram),
readBufferSize(dram->readBufferSize),
writeBufferSize(dram->writeBufferSize),
writeHighThreshold(writeBufferSize * p->write_high_thresh_perc / 100.0),
writeLowThreshold(writeBufferSize * p->write_low_thresh_perc / 100.0),
minWritesPerSwitch(p->min_writes_per_switch),
writesThisTime(0), readsThisTime(0), tCS(p->tCS),
writesThisTime(0), readsThisTime(0),
memSchedPolicy(p->mem_sched_policy),
frontendLatency(p->static_frontend_latency),
backendLatency(p->static_backend_latency),
@@ -74,37 +76,23 @@ DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) :
readQueue.resize(p->qos_priorities);
writeQueue.resize(p->qos_priorities);
dram->setCtrl(this);
// perform a basic check of the write thresholds
if (p->write_low_thresh_perc >= p->write_high_thresh_perc)
fatal("Write buffer low threshold %d must be smaller than the "
"high threshold %d\n", p->write_low_thresh_perc,
p->write_high_thresh_perc);
// determine the rows per bank by looking at the total capacity
uint64_t capacity = ULL(1) << ceilLog2(AbstractMemory::size());
DPRINTF(DRAM, "Memory capacity %lld (%lld) bytes\n", capacity,
AbstractMemory::size());
// create a DRAM interface
// will only populate the ranks if DRAM is configured
dram = new DRAMInterface(*this, p, capacity, range);
DPRINTF(DRAM, "Created DRAM interface \n");
}
void
DRAMCtrl::init()
{
MemCtrl::init();
if (!port.isConnected()) {
fatal("DRAMCtrl %s is unconnected!\n", name());
} else {
port.sendRangeChange();
}
dram->init(range);
}
void
@@ -114,8 +102,6 @@ DRAMCtrl::startup()
isTimingMode = system()->isTimingMode();
if (isTimingMode) {
dram->startupRanks();
// shift the bus busy time sufficiently far ahead that we never
// have to worry about negative values when computing the time for
// the next request, this will add an insignificant bubble at the
@@ -133,7 +119,7 @@ DRAMCtrl::recvAtomic(PacketPtr pkt)
"is responding");
// do the actual memory access and turn the packet into a response
access(pkt);
dram->access(pkt);
Tick latency = 0;
if (pkt->hasData()) {
@@ -263,7 +249,7 @@ DRAMCtrl::addToReadQueue(PacketPtr pkt, unsigned int pktCount)
// address of first DRAM packet is kept unaliged. Subsequent DRAM packets
// are aligned to burst size boundaries. This is to ensure we accurately
// check read packets against packets in write queue.
const Addr base_addr = getCtrlAddr(pkt->getAddr());
const Addr base_addr = dram->getCtrlAddr(pkt->getAddr());
Addr addr = base_addr;
unsigned pktsServicedByWrQ = 0;
BurstHelper* burst_helper = NULL;
@@ -363,7 +349,7 @@ DRAMCtrl::addToWriteQueue(PacketPtr pkt, unsigned int pktCount)
// if the request size is larger than burst size, the pkt is split into
// multiple DRAM packets
const Addr base_addr = getCtrlAddr(pkt->getAddr());
const Addr base_addr = dram->getCtrlAddr(pkt->getAddr());
Addr addr = base_addr;
uint32_t burstSize = dram->bytesPerBurst();
for (int cnt = 0; cnt < pktCount; ++cnt) {
@@ -526,7 +512,7 @@ DRAMCtrl::processRespondEvent()
DRAMPacket* dram_pkt = respQueue.front();
// media specific checks and functions when read response is complete
dram->respondEventDRAM(dram_pkt->rank);
dram->respondEvent(dram_pkt->rank);
if (dram_pkt->burstHelper) {
// it is a split packet
@@ -727,12 +713,12 @@ DRAMCtrl::chooseNextFRFCFS(DRAMPacketQueue& queue, Tick extra_col_delay)
void
DRAMCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency)
{
DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr());
DPRINTF(DRAM, "Responding to Address %lld.. \n",pkt->getAddr());
bool needsResponse = pkt->needsResponse();
// do the actual memory access which also turns the packet into a
// response
access(pkt);
dram->access(pkt);
// turn packet around to go back to requester if response expected
if (needsResponse) {
@@ -877,9 +863,9 @@ DRAMInterface::activateBank(Rank& rank_ref, Bank& bank_ref,
// if not, shift to next burst window
Tick act_at;
if (twoCycleActivate)
act_at = ctrl.verifyMultiCmd(act_tick, tAAD);
act_at = ctrl->verifyMultiCmd(act_tick, tAAD);
else
act_at = ctrl.verifySingleCmd(act_tick);
act_at = ctrl->verifySingleCmd(act_tick);
DPRINTF(DRAM, "Activate at tick %d\n", act_at);
@@ -997,7 +983,7 @@ DRAMInterface::prechargeBank(Rank& rank_ref, Bank& bank, Tick pre_tick,
// Issuing an explicit PRE command
// Verify that we have command bandwidth to issue the precharge
// if not, shift to next burst window
pre_at = ctrl.verifySingleCmd(pre_tick);
pre_at = ctrl->verifySingleCmd(pre_tick);
// enforce tPPD
for (int i = 0; i < banksPerRank; i++) {
rank_ref.banks[i].preAllowedAt = std::max(pre_at + tPPD,
@@ -1096,9 +1082,9 @@ DRAMInterface::doBurstAccess(DRAMPacket* dram_pkt, Tick next_burst_at,
// verify that we have command bandwidth to issue the burst
// if not, shift to next burst window
if (dataClockSync && ((cmd_at - rank_ref.lastBurstTick) > clkResyncDelay))
cmd_at = ctrl.verifyMultiCmd(cmd_at, tCK);
cmd_at = ctrl->verifyMultiCmd(cmd_at, tCK);
else
cmd_at = ctrl.verifySingleCmd(cmd_at);
cmd_at = ctrl->verifySingleCmd(cmd_at);
// if we are interleaving bursts, ensure that
// 1) we don't double interleave on next burst issue
@@ -1196,7 +1182,7 @@ DRAMInterface::doBurstAccess(DRAMPacket* dram_pkt, Tick next_burst_at,
bool got_more_hits = false;
bool got_bank_conflict = false;
for (uint8_t i = 0; i < ctrl.numPriorities(); ++i) {
for (uint8_t i = 0; i < ctrl->numPriorities(); ++i) {
auto p = queue[i].begin();
// keep on looking until we find a hit or reach the end of the
// queue
@@ -1267,6 +1253,7 @@ DRAMInterface::doBurstAccess(DRAMPacket* dram_pkt, Tick next_burst_at,
// Update latency stats
stats.totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime;
stats.totQLat += cmd_at - dram_pkt->entryTime;
stats.totBusLat += tBURST;
} else {
// Schedule write done event to decrement event count
// after the readyTime has been reached
@@ -1350,13 +1337,9 @@ DRAMCtrl::doBurstAccess(DRAMPacket* dram_pkt)
// Update latency stats
stats.masterReadTotalLat[dram_pkt->masterId()] +=
dram_pkt->readyTime - dram_pkt->entryTime;
stats.bytesRead += dram->bytesPerBurst();
stats.totBusLat += dram->burstDelay();
stats.masterReadBytes[dram_pkt->masterId()] += dram_pkt->size;
} else {
++writesThisTime;
stats.bytesWritten += dram->bytesPerBurst();
stats.masterWriteBytes[dram_pkt->masterId()] += dram_pkt->size;
stats.masterWriteTotalLat[dram_pkt->masterId()] +=
dram_pkt->readyTime - dram_pkt->entryTime;
@@ -1458,8 +1441,9 @@ DRAMCtrl::processNextReqEvent()
// Figure out which read request goes next
// If we are changing command type, incorporate the minimum
// bus turnaround delay which will be tCS (different rank) case
to_read = chooseNext((*queue), switched_cmd_type ? tCS : 0);
// bus turnaround delay which will be rank to rank delay
to_read = chooseNext((*queue), switched_cmd_type ?
dram->rankDelay() : 0);
if (to_read != queue->end()) {
// candidate read found
@@ -1538,7 +1522,8 @@ DRAMCtrl::processNextReqEvent()
// If we are changing command type, incorporate the minimum
// bus turnaround delay
to_write = chooseNext((*queue),
switched_cmd_type ? std::min(dram->minRdToWr(), tCS) : 0);
switched_cmd_type ? std::min(dram->minRdToWr(),
dram->rankDelay()) : 0);
if (to_write != queue->end()) {
write_found = true;
@@ -1611,11 +1596,8 @@ DRAMCtrl::processNextReqEvent()
}
}
DRAMInterface::DRAMInterface(DRAMCtrl& _ctrl,
const DRAMCtrlParams* _p,
const uint64_t capacity,
const AddrRange range)
: SimObject(_p), ctrl(_ctrl),
DRAMInterface::DRAMInterface(const DRAMInterfaceParams* _p)
: AbstractMemory(_p),
addrMapping(_p->addr_mapping),
burstSize((_p->devices_per_rank * _p->burst_length *
_p->device_bus_width) / 8),
@@ -1630,7 +1612,7 @@ DRAMInterface::DRAMInterface(DRAMCtrl& _ctrl,
bankGroupsPerRank(_p->bank_groups_per_rank),
bankGroupArch(_p->bank_groups_per_rank > 0),
banksPerRank(_p->banks_per_rank), rowsPerBank(0),
tCK(_p->tCK), tCL(_p->tCL), tBURST(_p->tBURST),
tCK(_p->tCK), tCS(_p->tCS), tCL(_p->tCL), tBURST(_p->tBURST),
tBURST_MIN(_p->tBURST_MIN), tBURST_MAX(_p->tBURST_MAX), tRTW(_p->tRTW),
tCCD_L_WR(_p->tCCD_L_WR), tCCD_L(_p->tCCD_L), tRCD(_p->tRCD),
tRP(_p->tRP), tRAS(_p->tRAS), tWR(_p->tWR), tRTP(_p->tRTP),
@@ -1646,13 +1628,15 @@ DRAMInterface::DRAMInterface(DRAMCtrl& _ctrl,
wrToRdDly(tCL + tBURST + _p->tWTR), rdToWrDly(tBURST + tRTW),
wrToRdDlySameBG(tCL + _p->tBURST_MAX + _p->tWTR_L),
rdToWrDlySameBG(tRTW + _p->tBURST_MAX),
rankToRankDly(ctrl.rankDelay() + tBURST),
rankToRankDly(tCS + tBURST),
pageMgmt(_p->page_policy),
maxAccessesPerRow(_p->max_accesses_per_row),
timeStampOffset(0), activeRank(0),
enableDRAMPowerdown(_p->enable_dram_powerdown),
lastStatsResetTick(0),
stats(_ctrl, *this)
stats(*this),
readBufferSize(_p->read_buffer_size),
writeBufferSize(_p->write_buffer_size)
{
fatal_if(!isPowerOf2(burstSize), "DRAM burst size %d is not allowed, "
"must be a power of two\n", burstSize);
@@ -1664,7 +1648,7 @@ DRAMInterface::DRAMInterface(DRAMCtrl& _ctrl,
for (int i = 0; i < ranksPerChannel; i++) {
DPRINTF(DRAM, "Creating DRAM rank %d \n", i);
Rank* rank = new Rank(ctrl, _p, i, *this);
Rank* rank = new Rank(_p, i, *this);
ranks.push_back(rank);
}
@@ -1672,6 +1656,11 @@ DRAMInterface::DRAMInterface(DRAMCtrl& _ctrl,
uint64_t deviceCapacity = deviceSize / (1024 * 1024) * devicesPerRank *
ranksPerChannel;
uint64_t capacity = ULL(1) << ceilLog2(AbstractMemory::size());
DPRINTF(DRAM, "Memory capacity %lld (%lld) bytes\n", capacity,
AbstractMemory::size());
// if actual DRAM size does not match memory capacity in system warn!
if (deviceCapacity != capacity / (1024 * 1024))
warn("DRAM device capacity (%d Mbytes) does not match the "
@@ -1726,8 +1715,10 @@ DRAMInterface::DRAMInterface(DRAMCtrl& _ctrl,
}
void
DRAMInterface::init(AddrRange range)
DRAMInterface::init()
{
AbstractMemory::init();
// a bit of sanity checks on the interleaving, save it for here to
// ensure that the system pointer is initialised
if (range.interleaved()) {
@@ -1749,7 +1740,7 @@ DRAMInterface::init(AddrRange range)
// channel striping has to be done at a granularity that
// is equal or larger to a cache line
if (ctrl.system()->cacheLineSize() > range.granularity()) {
if (system()->cacheLineSize() > range.granularity()) {
fatal("Channel interleaving of %s must be at least as large "
"as the cache line size\n", name());
}
@@ -1766,10 +1757,12 @@ DRAMInterface::init(AddrRange range)
}
void
DRAMInterface::startupRanks()
DRAMInterface::startup()
{
// timestamp offset should be in clock cycles for DRAMPower
timeStampOffset = divCeil(curTick(), tCK);
if (system()->isTimingMode()) {
// timestamp offset should be in clock cycles for DRAMPower
timeStampOffset = divCeil(curTick(), tCK);
}
for (auto r : ranks) {
r->startup(curTick() + tREFI - tRP);
@@ -1815,7 +1808,7 @@ DRAMInterface::isBusy()
}
void
DRAMInterface::respondEventDRAM(uint8_t rank)
DRAMInterface::respondEvent(uint8_t rank)
{
Rank& rank_ref = *ranks[rank];
@@ -1956,7 +1949,7 @@ DRAMInterface::minBankPrep(const DRAMPacketQueue& queue,
std::max(ranks[i]->banks[j].preAllowedAt, curTick()) + tRP;
// When is the earliest the R/W burst can issue?
const Tick col_allowed_at = ctrl.inReadBusState(false) ?
const Tick col_allowed_at = ctrl->inReadBusState(false) ?
ranks[i]->banks[j].rdAllowedAt :
ranks[i]->banks[j].wrAllowedAt;
Tick col_at = std::max(col_allowed_at, act_at + tRCD);
@@ -1996,9 +1989,15 @@ DRAMInterface::minBankPrep(const DRAMPacketQueue& queue,
return make_pair(bank_mask, hidden_bank_prep);
}
DRAMInterface::Rank::Rank(DRAMCtrl& _ctrl, const DRAMCtrlParams* _p, int _rank,
DRAMInterface& _dram)
: EventManager(&_ctrl), ctrl(_ctrl), dram(_dram),
DRAMInterface*
DRAMInterfaceParams::create()
{
return new DRAMInterface(this);
}
DRAMInterface::Rank::Rank(const DRAMInterfaceParams* _p,
int _rank, DRAMInterface& _dram)
: EventManager(&_dram), dram(_dram),
pwrStateTrans(PWR_IDLE), pwrStatePostRefresh(PWR_IDLE),
pwrStateTick(0), refreshDueAt(0), pwrState(PWR_IDLE),
refreshState(REF_IDLE), inLowPowerState(false), rank(_rank),
@@ -2011,7 +2010,7 @@ DRAMInterface::Rank::Rank(DRAMCtrl& _ctrl, const DRAMCtrlParams* _p, int _rank,
refreshEvent([this]{ processRefreshEvent(); }, name()),
powerEvent([this]{ processPowerEvent(); }, name()),
wakeUpEvent([this]{ processWakeUpEvent(); }, name()),
stats(_ctrl, *this)
stats(_dram, *this)
{
for (int b = 0; b < _p->banks_per_rank; b++) {
banks[b].bank = b;
@@ -2062,8 +2061,10 @@ bool
DRAMInterface::Rank::isQueueEmpty() const
{
// check commmands in Q based on current bus direction
bool no_queued_cmds = (ctrl.inReadBusState(true) && (readEntries == 0))
|| (ctrl.inWriteBusState(true) && (writeEntries == 0));
bool no_queued_cmds = (dram.ctrl->inReadBusState(true) &&
(readEntries == 0))
|| (dram.ctrl->inWriteBusState(true) &&
(writeEntries == 0));
return no_queued_cmds;
}
@@ -2187,7 +2188,7 @@ DRAMInterface::Rank::processRefreshEvent()
// if a request is at the moment being handled and this request is
// accessing the current rank then wait for it to finish
if ((rank == dram.activeRank)
&& (ctrl.requestEventScheduled())) {
&& (dram.ctrl->requestEventScheduled())) {
// hand control over to the request loop until it is
// evaluated next
DPRINTF(DRAM, "Refresh awaiting draining\n");
@@ -2262,7 +2263,7 @@ DRAMInterface::Rank::processRefreshEvent()
// or have outstanding ACT,RD/WR,Auto-PRE sequence scheduled
// should have outstanding precharge or read response event
assert(prechargeEvent.scheduled() ||
ctrl.respondEventScheduled());
dram.ctrl->respondEventScheduled());
// will start refresh when pwrState transitions to IDLE
}
@@ -2322,8 +2323,8 @@ DRAMInterface::Rank::processRefreshEvent()
assert(!powerEvent.scheduled());
if ((ctrl.drainState() == DrainState::Draining) ||
(ctrl.drainState() == DrainState::Drained)) {
if ((dram.ctrl->drainState() == DrainState::Draining) ||
(dram.ctrl->drainState() == DrainState::Drained)) {
// if draining, do not re-enter low-power mode.
// simply go to IDLE and wait
schedulePowerEvent(PWR_IDLE, curTick());
@@ -2548,10 +2549,10 @@ DRAMInterface::Rank::processPowerEvent()
}
// completed refresh event, ensure next request is scheduled
if (!ctrl.requestEventScheduled()) {
if (!dram.ctrl->requestEventScheduled()) {
DPRINTF(DRAM, "Scheduling next request after refreshing"
" rank %d\n", rank);
ctrl.restartScheduler(curTick());
dram.ctrl->restartScheduler(curTick());
}
}
@@ -2610,8 +2611,8 @@ DRAMInterface::Rank::processPowerEvent()
// bypass auto-refresh and go straight to SREF, where memory
// will issue refresh immediately upon entry
if (pwrStatePostRefresh == PWR_PRE_PDN && isQueueEmpty() &&
(ctrl.drainState() != DrainState::Draining) &&
(ctrl.drainState() != DrainState::Drained) &&
(dram.ctrl->drainState() != DrainState::Draining) &&
(dram.ctrl->drainState() != DrainState::Drained) &&
dram.enableDRAMPowerdown) {
DPRINTF(DRAMState, "Rank %d bypassing refresh and transitioning "
"to self refresh at %11u tick\n", rank, curTick());
@@ -2712,7 +2713,7 @@ DRAMInterface::Rank::resetStats() {
bool
DRAMInterface::Rank::forceSelfRefreshExit() const {
return (readEntries != 0) ||
(ctrl.inWriteBusState(true) && (writeEntries != 0));
(dram.ctrl->inWriteBusState(true) && (writeEntries != 0));
}
DRAMCtrl::CtrlStats::CtrlStats(DRAMCtrl &_ctrl)
@@ -2723,15 +2724,15 @@ DRAMCtrl::CtrlStats::CtrlStats(DRAMCtrl &_ctrl)
ADD_STAT(writeReqs, "Number of write requests accepted"),
ADD_STAT(readBursts,
"Number of DRAM read bursts, "
"Number of controller read bursts, "
"including those serviced by the write queue"),
ADD_STAT(writeBursts,
"Number of DRAM write bursts, "
"Number of controller write bursts, "
"including those merged in the write queue"),
ADD_STAT(servicedByWrQ,
"Number of DRAM read bursts serviced by the write queue"),
"Number of controller read bursts serviced by the write queue"),
ADD_STAT(mergedWrBursts,
"Number of DRAM write bursts merged with an existing one"),
"Number of controller write bursts merged with an existing one"),
ADD_STAT(neitherReadNorWriteReqs,
"Number of requests that are neither read nor write"),
@@ -2739,9 +2740,6 @@ DRAMCtrl::CtrlStats::CtrlStats(DRAMCtrl &_ctrl)
ADD_STAT(avgRdQLen, "Average read queue length when enqueuing"),
ADD_STAT(avgWrQLen, "Average write queue length when enqueuing"),
ADD_STAT(totBusLat, "Total ticks spent in databus transfers"),
ADD_STAT(avgBusLat, "Average bus latency per DRAM burst"),
ADD_STAT(numRdRetry, "Number of times read queue was full causing retry"),
ADD_STAT(numWrRetry, "Number of times write queue was full causing retry"),
@@ -2756,22 +2754,13 @@ DRAMCtrl::CtrlStats::CtrlStats(DRAMCtrl &_ctrl)
ADD_STAT(wrPerTurnAround,
"Writes before turning the bus around for reads"),
ADD_STAT(bytesRead, "Total number of bytes read from memory"),
ADD_STAT(bytesReadWrQ, "Total number of bytes read from write queue"),
ADD_STAT(bytesWritten, "Total number of bytes written to DRAM"),
ADD_STAT(bytesReadSys, "Total read bytes from the system interface side"),
ADD_STAT(bytesWrittenSys,
"Total written bytes from the system interface side"),
ADD_STAT(avgRdBW, "Average DRAM read bandwidth in MiByte/s"),
ADD_STAT(avgWrBW, "Average achieved write bandwidth in MiByte/s"),
ADD_STAT(avgRdBWSys, "Average system read bandwidth in MiByte/s"),
ADD_STAT(avgWrBWSys, "Average system write bandwidth in MiByte/s"),
ADD_STAT(peakBW, "Theoretical peak bandwidth in MiByte/s"),
ADD_STAT(busUtil, "Data bus utilization in percentage"),
ADD_STAT(busUtilRead, "Data bus utilization in percentage for reads"),
ADD_STAT(busUtilWrite, "Data bus utilization in percentage for writes"),
ADD_STAT(totGap, "Total gap between requests"),
ADD_STAT(avgGap, "Average gap between requests"),
@@ -2803,12 +2792,11 @@ DRAMCtrl::CtrlStats::regStats()
{
using namespace Stats;
assert(ctrl._system);
const auto max_masters = ctrl._system->maxMasters();
assert(ctrl.system());
const auto max_masters = ctrl.system()->maxMasters();
avgRdQLen.precision(2);
avgWrQLen.precision(2);
avgBusLat.precision(2);
readPktSize.init(ceilLog2(ctrl.dram->bytesPerBurst()) + 1);
writePktSize.init(ceilLog2(ctrl.dram->bytesPerBurst()) + 1);
@@ -2823,14 +2811,9 @@ DRAMCtrl::CtrlStats::regStats()
.init(ctrl.writeBufferSize)
.flags(nozero);
avgRdBW.precision(2);
avgWrBW.precision(2);
avgRdBWSys.precision(2);
avgWrBWSys.precision(2);
peakBW.precision(2);
busUtil.precision(2);
avgGap.precision(2);
busUtilWrite.precision(2);
// per-master bytes read and written to memory
masterReadBytes
@@ -2862,9 +2845,6 @@ DRAMCtrl::CtrlStats::regStats()
.flags(nonan)
.precision(2);
busUtilRead
.precision(2);
masterWriteRate
.flags(nozero | nonan)
.precision(12);
@@ -2878,7 +2858,7 @@ DRAMCtrl::CtrlStats::regStats()
.precision(2);
for (int i = 0; i < max_masters; i++) {
const std::string master = ctrl._system->getMasterName(i);
const std::string master = ctrl.system()->getMasterName(i);
masterReadBytes.subname(i, master);
masterReadRate.subname(i, master);
masterWriteBytes.subname(i, master);
@@ -2892,22 +2872,11 @@ DRAMCtrl::CtrlStats::regStats()
}
// Formula stats
avgBusLat = totBusLat / (readBursts - servicedByWrQ);
avgRdBW = (bytesRead / 1000000) / simSeconds;
avgWrBW = (bytesWritten / 1000000) / simSeconds;
avgRdBWSys = (bytesReadSys / 1000000) / simSeconds;
avgWrBWSys = (bytesWrittenSys / 1000000) / simSeconds;
peakBW = (SimClock::Frequency / ctrl.dram->burstDataDelay()) *
ctrl.dram->bytesPerBurst() / 1000000;
busUtil = (avgRdBW + avgWrBW) / peakBW * 100;
avgGap = totGap / (readReqs + writeReqs);
busUtilRead = avgRdBW / peakBW * 100;
busUtilWrite = avgWrBW / peakBW * 100;
masterReadRate = masterReadBytes / simSeconds;
masterWriteRate = masterWriteBytes / simSeconds;
masterReadAvgLat = masterReadTotalLat / masterReadAccesses;
@@ -2920,8 +2889,8 @@ DRAMInterface::DRAMStats::resetStats()
dram.lastStatsResetTick = curTick();
}
DRAMInterface::DRAMStats::DRAMStats(DRAMCtrl &_ctrl, DRAMInterface &_dram)
: Stats::Group(&_ctrl, csprintf("dram").c_str()),
DRAMInterface::DRAMStats::DRAMStats(DRAMInterface &_dram)
: Stats::Group(&_dram),
dram(_dram),
ADD_STAT(readBursts, "Number of DRAM read bursts"),
@@ -2931,10 +2900,13 @@ DRAMInterface::DRAMStats::DRAMStats(DRAMCtrl &_ctrl, DRAMInterface &_dram)
ADD_STAT(perBankWrBursts, "Per bank write bursts"),
ADD_STAT(totQLat, "Total ticks spent queuing"),
ADD_STAT(totBusLat, "Total ticks spent in databus transfers"),
ADD_STAT(totMemAccLat,
"Total ticks spent from burst creation until serviced "
"by the DRAM"),
ADD_STAT(avgQLat, "Average queueing delay per DRAM burst"),
ADD_STAT(avgBusLat, "Average bus latency per DRAM burst"),
ADD_STAT(avgMemAccLat, "Average memory access latency per DRAM burst"),
ADD_STAT(readRowHits, "Number of row buffer hits during reads"),
@@ -2947,6 +2919,12 @@ DRAMInterface::DRAMStats::DRAMStats(DRAMCtrl &_ctrl, DRAMInterface &_dram)
ADD_STAT(bytesWritten, "Total number of bytes written to DRAM"),
ADD_STAT(avgRdBW, "Average DRAM read bandwidth in MiBytes/s"),
ADD_STAT(avgWrBW, "Average DRAM write bandwidth in MiBytes/s"),
ADD_STAT(peakBW, "Theoretical peak bandwidth in MiByte/s"),
ADD_STAT(busUtil, "Data bus utilization in percentage"),
ADD_STAT(busUtilRead, "Data bus utilization in percentage for reads"),
ADD_STAT(busUtilWrite, "Data bus utilization in percentage for writes"),
ADD_STAT(pageHitRate, "Row buffer hit rate, read and write combined")
{
@@ -2958,6 +2936,7 @@ DRAMInterface::DRAMStats::regStats()
using namespace Stats;
avgQLat.precision(2);
avgBusLat.precision(2);
avgMemAccLat.precision(2);
readRowHitRate.precision(2);
@@ -2971,10 +2950,16 @@ DRAMInterface::DRAMStats::regStats()
dram.maxAccessesPerRow : dram.rowBufferSize)
.flags(nozero);
peakBW.precision(2);
busUtil.precision(2);
busUtilWrite.precision(2);
busUtilRead.precision(2);
pageHitRate.precision(2);
// Formula stats
avgQLat = totQLat / readBursts;
avgBusLat = totBusLat / readBursts;
avgMemAccLat = totMemAccLat / readBursts;
readRowHitRate = (readRowHits / readBursts) * 100;
@@ -2982,13 +2967,19 @@ DRAMInterface::DRAMStats::regStats()
avgRdBW = (bytesRead / 1000000) / simSeconds;
avgWrBW = (bytesWritten / 1000000) / simSeconds;
peakBW = (SimClock::Frequency / dram.burstDataDelay()) *
dram.bytesPerBurst() / 1000000;
busUtil = (avgRdBW + avgWrBW) / peakBW * 100;
busUtilRead = avgRdBW / peakBW * 100;
busUtilWrite = avgWrBW / peakBW * 100;
pageHitRate = (writeRowHits + readRowHits) /
(writeBursts + readBursts) * 100;
}
DRAMInterface::RankStats::RankStats(DRAMCtrl &_ctrl, Rank &_rank)
: Stats::Group(&_ctrl, csprintf("dram_rank%d", _rank.rank).c_str()),
DRAMInterface::RankStats::RankStats(DRAMInterface &_dram, Rank &_rank)
: Stats::Group(&_dram, csprintf("rank%d", _rank.rank).c_str()),
rank(_rank),
ADD_STAT(actEnergy, "Energy for activate commands per rank (pJ)"),
@@ -3047,7 +3038,7 @@ void
DRAMCtrl::recvFunctional(PacketPtr pkt)
{
// rely on the abstract memory
functionalAccess(pkt);
dram->functionalAccess(pkt);
}
Port &
@@ -3093,6 +3084,7 @@ DRAMCtrl::drainResume()
// if we switched to timing mode, kick things into action,
// and behave as if we restored from a checkpoint
startup();
dram->startup();
} else if (isTimingMode && !system()->isTimingMode()) {
// if we switch from timing mode, stop the refresh events to
// not cause issues with KVM
@@ -3112,7 +3104,7 @@ AddrRangeList
DRAMCtrl::MemoryPort::getAddrRanges() const
{
AddrRangeList ranges;
ranges.push_back(ctrl.getAddrRange());
ranges.push_back(ctrl.dram->getAddrRange());
return ranges;
}

View File

@@ -55,12 +55,15 @@
#include "enums/AddrMap.hh"
#include "enums/MemSched.hh"
#include "enums/PageManage.hh"
#include "mem/abstract_mem.hh"
#include "mem/drampower.hh"
#include "mem/qos/mem_ctrl.hh"
#include "mem/qport.hh"
#include "params/DRAMCtrl.hh"
#include "sim/eventq.hh"
class DRAMInterfaceParams;
/**
* 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
@@ -242,7 +245,7 @@ typedef std::deque<DRAMPacket*> DRAMPacketQueue;
* The DRAMInterface includes a class for individual ranks
* and per rank functions.
*/
class DRAMInterface : public SimObject
class DRAMInterface : public AbstractMemory
{
private:
/**
@@ -342,7 +345,7 @@ class DRAMInterface : public SimObject
class Rank;
struct RankStats : public Stats::Group
{
RankStats(DRAMCtrl &ctrl, Rank &rank);
RankStats(DRAMInterface &dram, Rank &rank);
void regStats() override;
void resetStats() override;
@@ -408,13 +411,6 @@ class DRAMInterface : public SimObject
*/
class Rank : public EventManager
{
protected:
/**
* A reference to the parent DRAMCtrl instance
*/
DRAMCtrl& ctrl;
private:
/**
@@ -534,10 +530,10 @@ class DRAMInterface : public SimObject
*/
Tick lastBurstTick;
Rank(DRAMCtrl& _ctrl, const DRAMCtrlParams* _p, int _rank,
Rank(const DRAMInterfaceParams* _p, int _rank,
DRAMInterface& _dram);
const std::string name() const { return csprintf("dram_%d", rank); }
const std::string name() const { return csprintf("%d", rank); }
/**
* Kick off accounting for power and refresh states and
@@ -659,15 +655,16 @@ class DRAMInterface : public SimObject
* @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)
static bool
sortTime(const Command& cmd, const Command& cmd_next)
{
return cmd.timeStamp < cmd_next.timeStamp;
};
}
/**
* A reference to the parent DRAMCtrl instance
* A pointer to the parent DRAMCtrl instance
*/
DRAMCtrl& ctrl;
DRAMCtrl* ctrl;
/**
* Memory controller configuration initialized based on parameter
@@ -698,6 +695,7 @@ class DRAMInterface : public SimObject
* DRAM timing requirements
*/
const Tick M5_CLASS_VAR_USED tCK;
const Tick tCS;
const Tick tCL;
const Tick tBURST;
const Tick tBURST_MIN;
@@ -781,7 +779,7 @@ class DRAMInterface : public SimObject
struct DRAMStats : public Stats::Group
{
DRAMStats(DRAMCtrl &ctrl, DRAMInterface &dram);
DRAMStats(DRAMInterface &dram);
void regStats() override;
void resetStats() override;
@@ -798,10 +796,12 @@ class DRAMInterface : public SimObject
// Latencies summed over all requests
Stats::Scalar totQLat;
Stats::Scalar totBusLat;
Stats::Scalar totMemAccLat;
// Average latencies per request
Stats::Formula avgQLat;
Stats::Formula avgBusLat;
Stats::Formula avgMemAccLat;
// Row hit count and rate
@@ -817,6 +817,11 @@ class DRAMInterface : public SimObject
// Average bandwidth
Stats::Formula avgRdBW;
Stats::Formula avgWrBW;
Stats::Formula peakBW;
// bus utilization
Stats::Formula busUtil;
Stats::Formula busUtilRead;
Stats::Formula busUtilWrite;
Stats::Formula pageHitRate;
};
@@ -828,16 +833,28 @@ class DRAMInterface : public SimObject
std::vector<Rank*> ranks;
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;
/** Setting a pointer to the controller */
void setCtrl(DRAMCtrl* _ctrl) { ctrl = _ctrl; }
/**
* Initialize the DRAM interface and verify parameters
* @param range is the address range for this interface
*/
void init(AddrRange range);
void init() override;
/**
* Iterate through dram ranks and instantiate per rank startup routine
*/
void startupRanks();
void startup() override;
/**
* Iterate through dram ranks to exit self-refresh in order to drain
@@ -860,16 +877,27 @@ class DRAMInterface : public SimObject
*/
void suspend();
/**
* 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); }
/**
* @return number of bytes in a burst for this interface
*/
uint32_t bytesPerBurst() const { return burstSize; };
uint32_t bytesPerBurst() const { return burstSize; }
/**
*
* @return number of ranks per channel for this interface
*/
uint32_t numRanks() const { return ranksPerChannel; };
uint32_t numRanks() const { return ranksPerChannel; }
/*
* @return time to send a burst of data
@@ -879,7 +907,8 @@ class DRAMInterface : public SimObject
/*
* @return time to send a burst of data without gaps
*/
Tick burstDataDelay() const
Tick
burstDataDelay() const
{
return (burstInterleave ? tBURST_MAX / 2 : tBURST);
}
@@ -893,7 +922,14 @@ class DRAMInterface : public SimObject
*
* @return additional bus turnaround required for read-to-write
*/
Tick minRdToWr() const { return tRTW; };
Tick minRdToWr() const { return tRTW; }
/**
* Determine the required delay for an access to a different rank
*
* @return required rank to rank delay
*/
Tick rankDelay() const { return tCS; }
/*
* Function to calulate RAS cycle time for use within and
@@ -957,7 +993,8 @@ class DRAMInterface : public SimObject
* This requires the DRAM to be in the
* REF IDLE state
*/
bool burstReady(uint8_t rank) const
bool
burstReady(uint8_t rank) const
{
return ranks[rank]->inRefIdleState();
}
@@ -979,7 +1016,7 @@ class DRAMInterface : public SimObject
*
* @param rank Specifies rank associated with read burst
*/
void respondEventDRAM(uint8_t rank);
void respondEvent(uint8_t rank);
/**
* Check the refresh state to determine if refresh needs
@@ -989,8 +1026,7 @@ class DRAMInterface : public SimObject
*/
void checkRefreshState(uint8_t rank);
DRAMInterface(DRAMCtrl& _ctrl, const DRAMCtrlParams* _p,
uint64_t capacity, AddrRange range);
DRAMInterface(const DRAMInterfaceParams* _p);
};
/**
@@ -1140,20 +1176,6 @@ class DRAMCtrl : public QoS::MemCtrl
*/
void accessAndRespond(PacketPtr pkt, Tick static_latency);
/**
* 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);
}
/**
* The memory schduler/arbiter - picks which request needs to
* go next, based on the specified policy such as FCFS or FR-FCFS
@@ -1236,6 +1258,11 @@ class DRAMCtrl : public QoS::MemCtrl
*/
std::unordered_multiset<Tick> burstTicks;
/**
* Create pointer to interface of the actual dram media
*/
DRAMInterface* const dram;
/**
* The following are basic design parameters of the memory
* controller, and are initialized based on parameter values.
@@ -1250,12 +1277,6 @@ class DRAMCtrl : public QoS::MemCtrl
uint32_t writesThisTime;
uint32_t readsThisTime;
/**
* Basic memory timing parameters initialized based on parameter
* values. These will be used across memory interfaces.
*/
const Tick tCS;
/**
* Memory controller configuration initialized based on parameter
* values.
@@ -1310,10 +1331,6 @@ class DRAMCtrl : public QoS::MemCtrl
// Average queue lengths
Stats::Average avgRdQLen;
Stats::Average avgWrQLen;
// Latencies summed over all requests
Stats::Scalar totBusLat;
// Average latencies per request
Stats::Formula avgBusLat;
Stats::Scalar numRdRetry;
Stats::Scalar numWrRetry;
@@ -1324,21 +1341,12 @@ class DRAMCtrl : public QoS::MemCtrl
Stats::Histogram rdPerTurnAround;
Stats::Histogram wrPerTurnAround;
Stats::Scalar bytesRead;
Stats::Scalar bytesReadWrQ;
Stats::Scalar bytesWritten;
Stats::Scalar bytesReadSys;
Stats::Scalar bytesWrittenSys;
// Average bandwidth
Stats::Formula avgRdBW;
Stats::Formula avgWrBW;
Stats::Formula avgRdBWSys;
Stats::Formula avgWrBWSys;
Stats::Formula peakBW;
// bus utilization
Stats::Formula busUtil;
Stats::Formula busUtilRead;
Stats::Formula busUtilWrite;
Stats::Scalar totGap;
Stats::Formula avgGap;
@@ -1366,11 +1374,6 @@ class DRAMCtrl : public QoS::MemCtrl
CtrlStats stats;
/**
* Create pointer to interfasce to the actual media
*/
DRAMInterface* dram;
/**
* Upstream caches need this packet until true is returned, so
* hold it for deletion until a subsequent call
@@ -1448,13 +1451,6 @@ class DRAMCtrl : public QoS::MemCtrl
*/
void restartScheduler(Tick tick) { schedule(nextReqEvent, tick); }
/**
* Determine the required delay for an access to a different rank
*
* @return required rank to rank delay
*/
Tick rankDelay() const { return tCS; }
/**
* Check the current direction of the memory channel
*

View File

@@ -40,13 +40,13 @@
#include "base/intmath.hh"
#include "sim/core.hh"
DRAMPower::DRAMPower(const DRAMCtrlParams* p, bool include_io) :
DRAMPower::DRAMPower(const DRAMInterfaceParams* p, bool include_io) :
powerlib(libDRAMPower(getMemSpec(p), include_io))
{
}
Data::MemArchitectureSpec
DRAMPower::getArchParams(const DRAMCtrlParams* p)
DRAMPower::getArchParams(const DRAMInterfaceParams* p)
{
Data::MemArchitectureSpec archSpec;
archSpec.burstLength = p->burst_length;
@@ -68,7 +68,7 @@ DRAMPower::getArchParams(const DRAMCtrlParams* p)
}
Data::MemTimingSpec
DRAMPower::getTimingParams(const DRAMCtrlParams* p)
DRAMPower::getTimingParams(const DRAMInterfaceParams* p)
{
// Set the values that are used for power calculations and ignore
// the ones only used by the controller functionality in DRAMPower
@@ -100,7 +100,7 @@ DRAMPower::getTimingParams(const DRAMCtrlParams* p)
}
Data::MemPowerSpec
DRAMPower::getPowerParams(const DRAMCtrlParams* p)
DRAMPower::getPowerParams(const DRAMInterfaceParams* p)
{
// All DRAMPower currents are in mA
Data::MemPowerSpec powerSpec;
@@ -132,7 +132,7 @@ DRAMPower::getPowerParams(const DRAMCtrlParams* p)
}
Data::MemorySpecification
DRAMPower::getMemSpec(const DRAMCtrlParams* p)
DRAMPower::getMemSpec(const DRAMInterfaceParams* p)
{
Data::MemorySpecification memSpec;
memSpec.memArchSpec = getArchParams(p);
@@ -142,7 +142,18 @@ DRAMPower::getMemSpec(const DRAMCtrlParams* p)
}
bool
DRAMPower::hasTwoVDD(const DRAMCtrlParams* p)
DRAMPower::hasTwoVDD(const DRAMInterfaceParams* p)
{
return p->VDD2 == 0 ? false : true;
}
uint8_t
DRAMPower::getDataRate(const DRAMInterfaceParams* p)
{
uint32_t burst_cycles = divCeil(p->tBURST_MAX, p->tCK);
uint8_t data_rate = p->burst_length / burst_cycles;
// 4 for GDDR5
if (data_rate != 1 && data_rate != 2 && data_rate != 4 && data_rate != 8)
fatal("Got unexpected data rate %d, should be 1 or 2 or 4 or 8\n");
return data_rate;
}

View File

@@ -44,7 +44,7 @@
#define __MEM_DRAM_POWER_HH__
#include "libdrampower/LibDRAMPower.h"
#include "params/DRAMCtrl.hh"
#include "params/DRAMInterface.hh"
/**
* DRAMPower is a standalone tool which calculates the power consumed by a
@@ -57,38 +57,44 @@ class DRAMPower
/**
* Transform the architechture parameters defined in
* DRAMCtrlParams to the memSpec of DRAMPower
* DRAMInterfaceParams to the memSpec of DRAMPower
*/
static Data::MemArchitectureSpec getArchParams(const DRAMCtrlParams* p);
static Data::MemArchitectureSpec getArchParams(
const DRAMInterfaceParams* p);
/**
* Transforms the timing parameters defined in DRAMCtrlParams to
* Transforms the timing parameters defined in DRAMInterfaceParams to
* the memSpec of DRAMPower
*/
static Data::MemTimingSpec getTimingParams(const DRAMCtrlParams* p);
static Data::MemTimingSpec getTimingParams(const DRAMInterfaceParams* p);
/**
* Transforms the power and current parameters defined in
* DRAMCtrlParam to the memSpec of DRAMPower
* DRAMInterfaceParams to the memSpec of DRAMPower
*/
static Data::MemPowerSpec getPowerParams(const DRAMCtrlParams* p);
static Data::MemPowerSpec getPowerParams(const DRAMInterfaceParams* p);
/**
* Determine data rate, either one or two.
*/
static uint8_t getDataRate(const DRAMInterfaceParams* p);
/**
* Determine if DRAM has two voltage domains (or one)
*/
static bool hasTwoVDD(const DRAMCtrlParams* p);
static bool hasTwoVDD(const DRAMInterfaceParams* p);
/**
* Return an instance of MemSpec based on the DRAMCtrlParams
* Return an instance of MemSpec based on the DRAMInterfaceParams
*/
static Data::MemorySpecification getMemSpec(const DRAMCtrlParams* p);
static Data::MemorySpecification getMemSpec(const DRAMInterfaceParams* p);
public:
// Instance of DRAMPower Library
libDRAMPower powerlib;
DRAMPower(const DRAMCtrlParams* p, bool include_io);
DRAMPower(const DRAMInterfaceParams* p, bool include_io);
};

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2018 ARM Limited
# Copyright (c) 2018-2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
@@ -34,18 +34,21 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.params import *
from m5.objects.AbstractMemory import AbstractMemory
from m5.proxy import *
from m5.objects.ClockedObject import ClockedObject
from m5.objects.QoSTurnaround import *
# QoS Queue Selection policy used to select packets among same-QoS queues
class QoSQPolicy(Enum): vals = ["fifo", "lifo", "lrg"]
class QoSMemCtrl(AbstractMemory):
class QoSMemCtrl(ClockedObject):
type = 'QoSMemCtrl'
cxx_header = "mem/qos/mem_ctrl.hh"
cxx_class = 'QoS::MemCtrl'
abstract = True
system = Param.System(Parent.any, "System that the controller belongs to.")
##### QoS support parameters ####
# Number of priorities in the system

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2018 ARM Limited
# Copyright (c) 2018-2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
@@ -37,6 +37,7 @@
from m5.params import *
from m5.objects.QoSMemCtrl import *
from m5.objects.QoSMemSinkInterface import *
class QoSMemSinkCtrl(QoSMemCtrl):
type = 'QoSMemSinkCtrl'
@@ -44,6 +45,10 @@ class QoSMemSinkCtrl(QoSMemCtrl):
cxx_class = "QoS::MemSinkCtrl"
port = ResponsePort("Response ports")
interface = Param.QoSMemSinkInterface(QoSMemSinkInterface(),
"Interface to memory")
# the basic configuration of the controller architecture, note
# that each entry corresponds to a burst for the specific DRAM
# configuration (e.g. x32 with burst length 8 is 32 bytes) and not
@@ -59,5 +64,3 @@ class QoSMemSinkCtrl(QoSMemCtrl):
# response latency - time to issue a response once a request is serviced
response_latency = Param.Latency("20ns", "Memory response latency")

View File

@@ -0,0 +1,40 @@
# Copyright (c) 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.
#
# 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.
from m5.objects.AbstractMemory import AbstractMemory
class QoSMemSinkInterface(AbstractMemory):
type = 'QoSMemSinkInterface'
cxx_header = "mem/qos/mem_sink.hh"

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2018 ARM Limited
# Copyright (c) 2018-2020 ARM Limited
# All rights reserved
#
# The license below extends only to copyright in the software and shall
@@ -37,6 +37,7 @@ Import('*')
SimObject('QoSMemCtrl.py')
SimObject('QoSMemSinkCtrl.py')
SimObject('QoSMemSinkInterface.py')
SimObject('QoSPolicy.py')
SimObject('QoSTurnaround.py')

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019 ARM Limited
* Copyright (c) 2017-2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -42,7 +42,7 @@
namespace QoS {
MemCtrl::MemCtrl(const QoSMemCtrlParams * p)
: AbstractMemory(p),
: ClockedObject(p),
policy(p->qos_policy),
turnPolicy(p->qos_turnaround_policy),
queuePolicy(QueuePolicy::create(p)),
@@ -51,7 +51,8 @@ MemCtrl::MemCtrl(const QoSMemCtrlParams * p)
qosSyncroScheduler(p->qos_syncro_scheduler),
totalReadQueueSize(0), totalWriteQueueSize(0),
busState(READ), busStateNext(READ),
stats(*this)
stats(*this),
_system(p->system)
{
// Set the priority policy
if (policy) {
@@ -76,12 +77,6 @@ MemCtrl::MemCtrl(const QoSMemCtrlParams * p)
MemCtrl::~MemCtrl()
{}
void
MemCtrl::init()
{
AbstractMemory::init();
}
void
MemCtrl::logRequest(BusState dir, MasterID m_id, uint8_t qos,
Addr addr, uint64_t entries)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 ARM Limited
* Copyright (c) 2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -36,10 +36,10 @@
*/
#include "debug/QOS.hh"
#include "mem/abstract_mem.hh"
#include "mem/qos/q_policy.hh"
#include "mem/qos/policy.hh"
#include "mem/qos/q_policy.hh"
#include "params/QoSMemCtrl.hh"
#include "sim/clocked_object.hh"
#include "sim/system.hh"
#include <unordered_map>
@@ -56,7 +56,7 @@ namespace QoS {
* which support QoS - it provides access to a set of QoS
* scheduling policies
*/
class MemCtrl: public AbstractMemory
class MemCtrl : public ClockedObject
{
public:
/** Bus Direction */
@@ -151,6 +151,9 @@ class MemCtrl: public AbstractMemory
Stats::Scalar numStayWriteState;
} stats;
/** Pointer to the System object */
System* _system;
/**
* Initializes dynamically counters and
* statistics for a given Master
@@ -265,11 +268,6 @@ class MemCtrl: public AbstractMemory
virtual ~MemCtrl();
/**
* Initializes this object
*/
void init() override;
/**
* Gets the current bus state
*
@@ -346,6 +344,10 @@ class MemCtrl: public AbstractMemory
* @return total number of priority levels
*/
uint8_t numPriorities() const { return _numPriorities; }
/** read the system pointer
* @return pointer to the system object */
System* system() const { return _system; }
};
template<typename Queues>

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 ARM Limited
* Copyright (c) 2018-2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -40,6 +40,7 @@
#include "debug/Drain.hh"
#include "debug/QOS.hh"
#include "mem_sink.hh"
#include "params/QoSMemSinkInterface.hh"
#include "sim/system.hh"
namespace QoS {
@@ -50,12 +51,15 @@ MemSinkCtrl::MemSinkCtrl(const QoSMemSinkCtrlParams* p)
memoryPacketSize(p->memory_packet_size),
readBufferSize(p->read_buffer_size),
writeBufferSize(p->write_buffer_size), port(name() + ".port", *this),
interface(p->interface),
retryRdReq(false), retryWrReq(false), nextRequest(0), nextReqEvent(this)
{
// Resize read and write queue to allocate space
// for configured QoS priorities
readQueue.resize(numPriorities());
writeQueue.resize(numPriorities());
interface->setMemCtrl(this);
}
MemSinkCtrl::~MemSinkCtrl()
@@ -92,7 +96,7 @@ MemSinkCtrl::recvAtomic(PacketPtr pkt)
"%s Should not see packets where cache is responding\n",
__func__);
access(pkt);
interface->access(pkt);
return responseLatency;
}
@@ -101,7 +105,7 @@ MemSinkCtrl::recvFunctional(PacketPtr pkt)
{
pkt->pushLabel(name());
functionalAccess(pkt);
interface->functionalAccess(pkt);
pkt->popLabel();
}
@@ -279,7 +283,7 @@ MemSinkCtrl::processNextReqEvent()
// Do the actual memory access which also turns the packet
// into a response
access(pkt);
interface->access(pkt);
// Log the response
logResponse(pkt->isRead()? READ : WRITE,
@@ -351,7 +355,7 @@ AddrRangeList
MemSinkCtrl::MemoryPort::getAddrRanges() const
{
AddrRangeList ranges;
ranges.push_back(memory.getAddrRange());
ranges.push_back(memory.interface->getAddrRange());
return ranges;
}
@@ -390,3 +394,13 @@ QoSMemSinkCtrlParams::create()
return new QoS::MemSinkCtrl(this);
}
QoSMemSinkInterface::QoSMemSinkInterface(const QoSMemSinkInterfaceParams* _p)
: AbstractMemory(_p)
{
}
QoSMemSinkInterface*
QoSMemSinkInterfaceParams::create()
{
return new QoSMemSinkInterface(this);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 ARM Limited
* Copyright (c) 2018-2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -41,10 +41,14 @@
#ifndef __MEM_QOS_MEM_SINK_HH__
#define __MEM_QOS_MEM_SINK_HH__
#include "mem/abstract_mem.hh"
#include "mem/qos/mem_ctrl.hh"
#include "mem/qport.hh"
#include "params/QoSMemSinkCtrl.hh"
class QoSMemSinkInterfaceParams;
class QoSMemSinkInterface;
namespace QoS {
/**
@@ -163,6 +167,11 @@ class MemSinkCtrl : public MemCtrl
/** Memory slave port */
MemoryPort port;
/**
* Create pointer to interface of actual media
*/
QoSMemSinkInterface* const interface;
/** Read request pending */
bool retryRdReq;
@@ -244,4 +253,17 @@ class MemSinkCtrl : public MemCtrl
} // namespace QoS
class QoSMemSinkInterface : public AbstractMemory
{
public:
/** Setting a pointer to the interface */
void setMemCtrl(QoS::MemSinkCtrl* _ctrl) { ctrl = _ctrl; };
/** Pointer to the controller */
QoS::MemSinkCtrl* ctrl;
QoSMemSinkInterface(const QoSMemSinkInterfaceParams* _p);
};
#endif /* __MEM_QOS_MEM_SINK_HH__ */