banksPerRank(p->banks_per_rank), channels(p->channels), rowsPerBank(0),
readBufferSize(p->read_buffer_size),
writeBufferSize(p->write_buffer_size),
- writeThresholdPerc(p->write_thresh_perc),
+ writeHighThresholdPerc(p->write_high_thresh_perc),
+ writeLowThresholdPerc(p->write_low_thresh_perc),
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),
frontendLatency(p->static_frontend_latency),
backendLatency(p->static_backend_latency),
busBusyUntil(0), writeStartTime(0),
- prevArrival(0), numReqs(0)
+ prevArrival(0), numReqs(0),
+ numWritesThisTime(0), newTime(0)
{
// create the bank states based on the dimensions of the ranks and
// banks
actTicks[c].resize(activationLimit, 0);
}
- // round the write threshold percent to a whole number of entries
- // in the buffer
- writeThreshold = writeBufferSize * writeThresholdPerc / 100.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::processWriteEvent()
{
assert(!writeQueue.empty());
- uint32_t numWritesThisTime = 0;
- DPRINTF(DRAM, "Beginning DRAM Writes\n");
+ DPRINTF(DRAM, "Beginning DRAM Write\n");
Tick temp1 M5_VAR_USED = std::max(curTick(), busBusyUntil);
Tick temp2 M5_VAR_USED = std::max(curTick(), maxBankFreeAt());
- // @todo: are there any dangers with the untimed while loop?
- while (!writeQueue.empty()) {
- if (numWritesThisTime >= writeThreshold) {
- DPRINTF(DRAM, "Hit write threshold %d\n", writeThreshold);
- break;
- }
-
- chooseNextWrite();
- DRAMPacket* dram_pkt = writeQueue.front();
- // sanity check
- assert(dram_pkt->size <= burstSize);
- doDRAMAccess(dram_pkt);
+ chooseNextWrite();
+ DRAMPacket* dram_pkt = writeQueue.front();
+ // sanity check
+ assert(dram_pkt->size <= burstSize);
+ doDRAMAccess(dram_pkt);
- writeQueue.pop_front();
- delete dram_pkt;
- numWritesThisTime++;
- }
+ writeQueue.pop_front();
+ delete dram_pkt;
+ numWritesThisTime++;
DPRINTF(DRAM, "Completed %d writes, bus busy for %lld ticks,"\
"banks busy for %lld ticks\n", numWritesThisTime,
// Update stats
avgWrQLen = writeQueue.size();
- // turn the bus back around for reads again
- busBusyUntil += tWTR;
- stopReads = false;
+ 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;
+ // turn the bus back around for reads again
+ busBusyUntil += tWTR;
+ stopReads = false;
+
+ if (!nextReqEvent.scheduled())
+ schedule(nextReqEvent, busBusyUntil);
+ } else {
+ assert(!writeEvent.scheduled());
+ DPRINTF(DRAM, "Next write scheduled at %lld\n", newTime);
+ schedule(writeEvent, newTime);
+ }
if (retryWrReq) {
retryWrReq = false;
drainManager->signalDrainDone();
drainManager = NULL;
}
-
- // Once you're done emptying the write queue, check if there's
- // anything in the read queue, and call schedule if required. The
- // retry above could already have caused it to be scheduled, so
- // first check
- if (!nextReqEvent.scheduled())
- schedule(nextReqEvent, busBusyUntil);
}
accessAndRespond(pkt, frontendLatency);
// If your write buffer is starting to fill up, drain it!
- if (writeQueue.size() >= writeThreshold && !stopReads){
+ if (writeQueue.size() >= writeHighThreshold && !stopReads){
triggerWrites();
}
}
"Scheduler %s\n" \
"Address mapping %s\n" \
"Page policy %s\n",
- name(), readBufferSize, writeBufferSize, writeThreshold,
+ name(), readBufferSize, writeBufferSize, writeHighThreshold,
scheduler, address_mapping, page_policy);
DPRINTF(DRAM, "Memory controller %s timing specs\n" \
writeRowHits++;
}
+ // Update the minimum timing between the requests
+ newTime = (busBusyUntil > tRP + tRCD + tCL) ?
+ std::max(busBusyUntil - (tRP + tRCD + tCL), curTick()) : curTick();
+
// At this point, commonality between reads and writes ends.
// For writes, we are done since we long ago responded to the
// requestor. We also don't care about stats for writes. For
//time
moveToRespQ();
- // 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,
- // open a new row, and access, it is tRP + tRCD + tCL
-
- Tick newTime = (busBusyUntil > tRP + tRCD + tCL ) ?
- std::max(busBusyUntil - (tRP + tRCD + tCL) , curTick()) :
- curTick();
-
+ // Schedule the next read event
if (!nextReqEvent.scheduled() && !stopReads){
schedule(nextReqEvent, newTime);
} else {
if (newTime < nextReqEvent.when())
reschedule(nextReqEvent, newTime);
}
-
-
}
void