# write-to-read turn around penalty, assumed same as read-to-write
tWTR = Param.Latency("1ns", "Write to read switching time")
- # Currently unimplemented, unused, deduced or rolled into other params
+ # time window in which a maximum number of activates are allowed
+ # to take place, set to 0 to disable
+ tXAW = Param.Latency("0ns", "X activation window")
+ activation_limit = Param.Unsigned(4, "Max number of activates in window")
+
+ # Currently rolled into other params
######################################################################
# the minimum amount of time between a row being activated, and
# tRC - assumed to be 4 * tRP
# burst length for an access derived from peerBlockSize
-
- # @todo: Implement tFAW in the model
- # minimum time window in which a maximum of four activates are
- # allowed to take place
- # tFAW = Param.Latency("30ns", "Four activation window")
-
-
AbstractMemory(p),
port(name() + ".port", *this),
retryRdReq(false), retryWrReq(false),
- rowHitFlag(false), stopReads(false),
+ rowHitFlag(false), stopReads(false), actTicks(p->activation_limit, 0),
writeEvent(this), respondEvent(this),
refreshEvent(this), nextReqEvent(this), drainManager(NULL),
bytesPerCacheLine(0),
tWTR(p->tWTR), tBURST(p->tBURST),
tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP),
tRFC(p->tRFC), tREFI(p->tREFI),
+ tXAW(p->tXAW), activationLimit(p->activation_limit),
memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping),
pageMgmt(p->page_policy),
busBusyUntil(0), prevdramaccess(0), writeStartTime(0),
if (!rowHitFlag) {
bank.tRASDoneAt = bank.freeAt + tRP;
+ recordActivate(bank.freeAt - tCL - tRCD);
busBusyUntil = bank.freeAt - tCL - tRCD;
}
} else if (pageMgmt == Enums::close) {
bank.freeAt = schedTime + tBURST + accessLat + tRP + tRP;
+ // Work backwards from bank.freeAt to determine activate time
+ recordActivate(bank.freeAt - tRP - tRP - tCL - tRCD);
busBusyUntil = bank.freeAt - tRP - tRP - tCL - tRCD;
DPRINTF(DRAMWR, "processWriteEvent::bank.freeAt for "
"banks_id %d is %lld\n",
scheduleNextReq();
}
+void
+SimpleDRAM::recordActivate(Tick act_tick)
+{
+ assert(actTicks.size() == activationLimit);
+
+ DPRINTF(DRAM, "Activate at tick %d\n", act_tick);
+
+ // sanity check
+ if (actTicks.back() && (act_tick - actTicks.back()) < tXAW) {
+ panic("Got %d activates in window %d (%d - %d) which is smaller "
+ "than %d\n", activationLimit, act_tick - actTicks.back(),
+ act_tick, actTicks.back(), tXAW);
+ }
+
+ // shift the times used for the book keeping, the last element
+ // (highest index) is the oldest one and hence the lowest value
+ actTicks.pop_back();
+
+ // record an new activation (in the future)
+ actTicks.push_front(act_tick);
+
+ // cannot activate more than X times in time window tXAW, push the
+ // next one (the X + 1'st activate) to be tXAW away from the
+ // oldest in our window of X
+ if (actTicks.back() && (act_tick - actTicks.back()) < tXAW) {
+ DPRINTF(DRAM, "Enforcing tXAW with X = %d, next activate no earlier "
+ "than %d\n", activationLimit, actTicks.back() + tXAW);
+ for(int i = 0; i < ranksPerChannel; i++)
+ for(int j = 0; j < banksPerRank; j++)
+ // next activate must not happen before end of window
+ banks[i][j].freeAt = std::max(banks[i][j].freeAt,
+ actTicks.back() + tXAW);
+ }
+}
+
void
SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
{
bank.openRow = dram_pkt->row;
bank.freeAt = curTick() + addDelay + accessLat;
// If you activated a new row do to this access, the next access
- // will have to respect tRAS for this bank. Assume tRAS ~= 3 * tRP
- if (!rowHitFlag)
+ // will have to respect tRAS for this bank. Assume tRAS ~= 3 * tRP.
+ // Also need to account for t_XAW
+ if (!rowHitFlag) {
bank.tRASDoneAt = bank.freeAt + tRP;
-
+ recordActivate(bank.freeAt - tCL - tRCD); //since this is open page,
+ //no tRP by default
+ }
} else if (pageMgmt == Enums::close) { // accounting for tRAS also
- // assuming that tRAS ~= 3 * tRP, and tRAS ~= 4 * tRP, as is common
+ // assuming that tRAS ~= 3 * tRP, and tRC ~= 4 * tRP, as is common
// (refer Jacob/Ng/Wang and Micron datasheets)
bank.freeAt = curTick() + addDelay + accessLat + tRP + tRP;
+ recordActivate(bank.freeAt - tRP - tRP - tCL - tRCD); //essentially (freeAt - tRC)
DPRINTF(DRAM,"doDRAMAccess::bank.freeAt is %lld\n",bank.freeAt);
} else
panic("No page management policy chosen\n");
#ifndef __MEM_SIMPLE_DRAM_HH__
#define __MEM_SIMPLE_DRAM_HH__
+#include <deque>
+
#include "base/statistics.hh"
#include "enums/AddrMap.hh"
#include "enums/MemSched.hh"
*/
bool stopReads;
+ /** List to keep track of activate ticks */
+ std::deque<Tick> actTicks;
+
/**
* A basic class to track the bank state indirectly via
* times "freeAt" and "tRASDoneAt" and what page is currently open
*/
Tick maxBankFreeAt() const;
+
+ /**
+ * Keep track of when row activations happen, in order to enforce
+ * the maximum number of activations in the activation window. The
+ * method updates the time that the banks become available based
+ * on the current limits.
+ */
+ void recordActivate(Tick act_tick);
+
void printParams() const;
void printQs() const;
const Tick tRP;
const Tick tRFC;
const Tick tREFI;
+ const Tick tXAW;
+ const uint32_t activationLimit;
/**
* Memory controller configuration initialized based on parameter