summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mem/SimpleDRAM.py20
-rw-r--r--src/mem/simple_dram.cc86
-rw-r--r--src/mem/simple_dram.hh13
3 files changed, 56 insertions, 63 deletions
diff --git a/src/mem/SimpleDRAM.py b/src/mem/SimpleDRAM.py
index 7b8e506ac..1f44888e7 100644
--- a/src/mem/SimpleDRAM.py
+++ b/src/mem/SimpleDRAM.py
@@ -73,15 +73,17 @@ class SimpleDRAM(AbstractMemory):
write_buffer_size = Param.Unsigned(32, "Number of write queue entries")
read_buffer_size = Param.Unsigned(32, "Number of read queue entries")
- # threshold in percent for when to trigger writes and start
- # emptying the write buffer as it starts to get full
- write_high_thresh_perc = Param.Percent(70, "Threshold to trigger writes")
-
- # threshold in percentage for when to stop writes if the read
- # queue has an entry. An optimisaton to give reads priority if
- # sufficient number of writes are scheduled and write queue has
- # sufficient number of free entries
- write_low_thresh_perc = Param.Percent(0, "Threshold to stop writes")
+ # threshold in percent for when to forcefully trigger writes and
+ # start emptying the write buffer
+ write_high_thresh_perc = Param.Percent(85, "Threshold to force writes")
+
+ # threshold in percentage for when to start writes if the read
+ # queue is empty
+ write_low_thresh_perc = Param.Percent(50, "Threshold to start writes")
+
+ # minimum write bursts to schedule before switching back to reads
+ min_writes_per_switch = Param.Unsigned(16, "Minimum write bursts before "
+ "switching to reads")
# scheduler, address map and page policy
mem_sched_policy = Param.MemSched('frfcfs', "Memory scheduling policy")
diff --git a/src/mem/simple_dram.cc b/src/mem/simple_dram.cc
index 415f3dfcf..9a0008569 100644
--- a/src/mem/simple_dram.cc
+++ b/src/mem/simple_dram.cc
@@ -63,12 +63,14 @@ SimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
devicesPerRank(p->devices_per_rank),
burstSize((devicesPerRank * burstLength * deviceBusWidth) / 8),
rowBufferSize(devicesPerRank * deviceRowBufferSize),
+ columnsPerRowBuffer(rowBufferSize / burstSize),
ranksPerChannel(p->ranks_per_channel),
banksPerRank(p->banks_per_rank), channels(p->channels), rowsPerBank(0),
readBufferSize(p->read_buffer_size),
writeBufferSize(p->write_buffer_size),
- writeHighThresholdPerc(p->write_high_thresh_perc),
- writeLowThresholdPerc(p->write_low_thresh_perc),
+ 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),
tWTR(p->tWTR), tBURST(p->tBURST),
tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP), tRAS(p->tRAS),
tRFC(p->tRFC), tREFI(p->tREFI), tRRD(p->tRRD),
@@ -79,8 +81,7 @@ SimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
backendLatency(p->static_backend_latency),
busBusyUntil(0), writeStartTime(0),
prevArrival(0), numReqs(0),
- numWritesThisTime(0), newTime(0),
- startTickPrechargeAll(0), numBanksActive(0)
+ newTime(0), startTickPrechargeAll(0), numBanksActive(0)
{
// create the bank states based on the dimensions of the ranks and
// banks
@@ -91,24 +92,11 @@ SimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
actTicks[c].resize(activationLimit, 0);
}
- // round the write thresholds percent to a whole number of entries
- // in the buffer.
- writeHighThreshold = writeBufferSize * writeHighThresholdPerc / 100.0;
- writeLowThreshold = writeBufferSize * writeLowThresholdPerc / 100.0;
-}
-
-void
-SimpleDRAM::init()
-{
- if (!port.isConnected()) {
- fatal("SimpleDRAM %s is unconnected!\n", name());
- } else {
- port.sendRangeChange();
- }
-
- // we could deal with plenty options here, but for now do a quick
- // sanity check
- DPRINTF(DRAM, "Burst size %d bytes\n", burstSize);
+ // 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());
@@ -116,8 +104,6 @@ SimpleDRAM::init()
DPRINTF(DRAM, "Memory capacity %lld (%lld) bytes\n", capacity,
AbstractMemory::size());
- columnsPerRowBuffer = rowBufferSize / burstSize;
-
DPRINTF(DRAM, "Row buffer size %d bytes with %d columns per row buffer\n",
rowBufferSize, columnsPerRowBuffer);
@@ -147,6 +133,16 @@ SimpleDRAM::init()
}
void
+SimpleDRAM::init()
+{
+ if (!port.isConnected()) {
+ fatal("SimpleDRAM %s is unconnected!\n", name());
+ } else {
+ port.sendRangeChange();
+ }
+}
+
+void
SimpleDRAM::startup()
{
// print the configuration of the controller
@@ -397,29 +393,26 @@ SimpleDRAM::processWriteEvent()
writeQueue.pop_front();
delete dram_pkt;
- numWritesThisTime++;
- DPRINTF(DRAM, "Completed %d writes, bus busy for %lld ticks,"\
- "banks busy for %lld ticks\n", numWritesThisTime,
- busBusyUntil - temp1, maxBankFreeAt() - temp2);
+ ++writesThisTime;
+
+ DPRINTF(DRAM, "Writing, bus busy for %lld ticks, banks busy "
+ "for %lld ticks\n", busBusyUntil - temp1, maxBankFreeAt() - temp2);
// Update stats
avgWrQLen = writeQueue.size();
- if (numWritesThisTime >= writeHighThreshold) {
- DPRINTF(DRAM, "Hit write threshold %d\n", writeHighThreshold);
- }
-
- // If number of writes in the queue fall below the low thresholds and
- // read queue is not empty then schedule a request event else continue
- // with writes. The retry above could already have caused it to be
- // scheduled, so first check
- if (((writeQueue.size() <= writeLowThreshold) && !readQueue.empty()) ||
- writeQueue.empty()) {
- numWritesThisTime = 0;
+ // If we emptied the write queue, or got below the threshold and
+ // are not draining, or we have reads waiting and have done enough
+ // writes, then switch to reads. The retry above could already
+ // have caused it to be scheduled, so first check
+ if (writeQueue.empty() ||
+ (writeQueue.size() < writeLowThreshold && !drainManager) ||
+ (!readQueue.empty() && writesThisTime >= minWritesPerSwitch)) {
// turn the bus back around for reads again
busBusyUntil += tWTR;
stopReads = false;
+ writesThisTime = 0;
if (!nextReqEvent.scheduled())
schedule(nextReqEvent, busBusyUntil);
@@ -600,12 +593,13 @@ SimpleDRAM::printParams() const
"Memory controller %s characteristics\n" \
"Read buffer size %d\n" \
"Write buffer size %d\n" \
- "Write buffer thresh %d\n" \
+ "Write high thresh %d\n" \
+ "Write low thresh %d\n" \
"Scheduler %s\n" \
"Address mapping %s\n" \
"Page policy %s\n",
name(), readBufferSize, writeBufferSize, writeHighThreshold,
- scheduler, address_mapping, page_policy);
+ writeLowThreshold, scheduler, address_mapping, page_policy);
DPRINTF(DRAM, "Memory controller %s timing specs\n" \
"tRCD %d ticks\n" \
@@ -1258,11 +1252,11 @@ SimpleDRAM::scheduleNextReq()
// Figure out which read request goes next, and move it to the
// front of the read queue
if (!chooseNextRead()) {
- // In the case there is no read request to go next, see if we
- // are asked to drain, and if so trigger writes, this also
- // ensures that if we hit the write limit we will do this
- // multiple times until we are completely drained
- if (drainManager && !writeQueue.empty() && !writeEvent.scheduled())
+ // In the case there is no read request to go next, trigger
+ // writes if we have passed the low threshold (or if we are
+ // draining)
+ if (!writeQueue.empty() && !writeEvent.scheduled() &&
+ (writeQueue.size() > writeLowThreshold || drainManager))
triggerWrites();
} else {
doDRAMAccess(readQueue.front());
diff --git a/src/mem/simple_dram.hh b/src/mem/simple_dram.hh
index 0731b14bb..8ecce94b7 100644
--- a/src/mem/simple_dram.hh
+++ b/src/mem/simple_dram.hh
@@ -471,17 +471,17 @@ class SimpleDRAM : public AbstractMemory
const uint32_t devicesPerRank;
const uint32_t burstSize;
const uint32_t rowBufferSize;
+ const uint32_t columnsPerRowBuffer;
const uint32_t ranksPerChannel;
const uint32_t banksPerRank;
const uint32_t channels;
uint32_t rowsPerBank;
- uint32_t columnsPerRowBuffer;
const uint32_t readBufferSize;
const uint32_t writeBufferSize;
- const double writeHighThresholdPerc;
- uint32_t writeHighThreshold;
- const double writeLowThresholdPerc;
- uint32_t writeLowThreshold;
+ const uint32_t writeHighThreshold;
+ const uint32_t writeLowThreshold;
+ const uint32_t minWritesPerSwitch;
+ uint32_t writesThisTime;
/**
* Basic memory timing parameters initialized based on parameter
@@ -530,9 +530,6 @@ class SimpleDRAM : public AbstractMemory
Tick prevArrival;
int numReqs;
- // Tracks number of writes done to meet the write threshold
- uint32_t numWritesThisTime;
-
// The absolute soonest you have to start thinking about the
// next request is the longest access time that can occur before
// busBusyUntil. Assuming you need to precharge,