diff --git a/DRAMSys/library/resources/simulations/ddr3_postpone_ref_test.xml b/DRAMSys/library/resources/simulations/ddr3_postpone_ref_test.xml
index f9907ef1..d8944780 100644
--- a/DRAMSys/library/resources/simulations/ddr3_postpone_ref_test.xml
+++ b/DRAMSys/library/resources/simulations/ddr3_postpone_ref_test.xml
@@ -16,6 +16,6 @@
In library mode e.g. in Platform Architect the trace setup is ignored.
-->
- ddr3_postpone_ref_test_3.stl
+ ddr3_postpone_ref_test_1.stl
diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp b/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp
index 5613e7cd..96a24df7 100644
--- a/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp
+++ b/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp
@@ -45,24 +45,27 @@
using namespace tlm;
-RefreshManager::RefreshManager(sc_module_name, ControllerCore &controller) :
- controllerCore(controller),
- timing(controller.config.memSpec.refreshTimings[Bank(0)]),
- nextPlannedRefresh(SC_ZERO_TIME)
+RefreshManager::RefreshManager(sc_module_name,
+ ControllerCore &controller) : controllerCore(controller),
+ timing(controller.config.memSpec.refreshTimings[Bank(0)])
{
auto m = controllerCore.config.getRefMode();
tREFIx = timing.tREFI / m;
tRFCx = m == 4 ? timing.tRFC4 : m == 2 ? timing.tRFC2 : timing.tRFC;
- if (controllerCore.config.ControllerCoreRefEnablePostpone) {
- maxpostpone = controllerCore.config.ControllerCoreRefMaxPostponed * m;
- }
- if (controllerCore.config.ControllerCoreRefEnablePullIn) {
- maxpullin = controllerCore.config.ControllerCoreRefMaxPulledIn * m;
- }
+ postponeEnabled = controllerCore.config.ControllerCoreRefEnablePostpone;
+ pullInEnabled = controllerCore.config.ControllerCoreRefEnablePullIn;
+ maxpostpone = controllerCore.config.ControllerCoreRefMaxPostponed * m;
+ maxpullin = controllerCore.config.ControllerCoreRefMaxPulledIn * m;
+ pulledin = 0;
+ postponed = 0;
+ currentState = ST_REFRESH;
+ previousState = ST_REFRESH;
+ nextState = ST_REFRESH;
+ nextPlannedRefresh = SC_ZERO_TIME;
for (Bank bank : controller.getBanks()) {
setUpDummy(refreshPayloads[bank], bank);
}
- planNextRefresh(tREFIx);
+ planNextRefresh(tREFIx, false);
}
RefreshManager::~RefreshManager()
@@ -75,23 +78,27 @@ bool RefreshManager::hasCollision(const ScheduledCommand &command)
bool collisionWithPreviousRefEnd = command.getStart() <
controllerCore.state->getLastCommand(Command::AutoRefresh).getEnd();
bool collisionWithNextRefStart = command.getEnd() >= nextPlannedRefresh;
-
if (controllerCore.config.ControllerCoreRefEnablePostpone
- && (arCmdCounter < maxpostpone)) {
- // Flexible refresh is on and have "credits" to postpone
+ && (postponed < maxpostpone)) {
+ // Flexible refresh is on and have "credits" to postpone.
// Then there will not be a collision with next refresh because
- // nextPlannedRefresh will be updated
+ // nextPlannedRefresh will be updated.
collisionWithNextRefStart = false;
}
+ if (currentState == ST_BURST) {
+ // A burst due to postponed refreshes shall not be interrupted.
+ collisionWithNextRefStart = true;
+ }
return collisionWithPreviousRefEnd || collisionWithNextRefStart;
}
-void RefreshManager::doRefresh(tlm::tlm_generic_payload &payload, sc_time time)
+bool RefreshManager::doRefresh(tlm::tlm_generic_payload &payload, sc_time time)
{
sc_assert(!isInvalidated(payload, time));
- //Check if any row on all banks is activated and if so, a PrechargeAll
- //command must be scheduled before the refresh command.
+ bool pre = false;
+ // If any row is open, precharge all.
if (!controllerCore.state->rowBufferStates->allRowBuffersAreClosed()) {
+ pre = true;
ScheduledCommand prechargeAllMaster(Command::PrechargeAll, time,
getExecutionTime(Command::PrechargeAll, refreshPayloads[Bank(0)]),
refreshPayloads[Bank(0)]);
@@ -124,6 +131,7 @@ void RefreshManager::doRefresh(tlm::tlm_generic_payload &payload, sc_time time)
controllerCore.state->change(refreshAllMaster);
DramExtension::getExtension(refreshPayloads[Bank(0)]).incrementRow();
controllerCore.controller.send(refreshAllMaster, refreshPayloads[Bank(0)]);
+ return pre;
}
@@ -132,23 +140,29 @@ void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload &payload,
{
sc_time nextRefTiming;
bool pendingReq = controllerCore.hasPendingRequests();
- bool canPostpone = pendingReq && (arCmdCounter < maxpostpone);
- bool canPullIn = !pendingReq && (arCmdCounter < maxpullin);
+ bool canPostpone = postponeEnabled && pendingReq && (postponed < maxpostpone);
+ bool canPullIn = pullInEnabled && !pendingReq && (pulledin < maxpullin);
previousState = currentState;
currentState = nextState;
+ bool align = false;
+ sc_time nrt;
+ bool pre;
switch (currentState) {
case ST_REFRESH:
// Regular Refresh. It's possible to migrate from this to the flexible
// refresh states
- // The arCmdCounter should always be equal to zero here
- assert(arCmdCounter == 0);
+ assert(pulledin == 0 && postponed == 0);
if (canPostpone) {
- nextState = ST_POSTPONE;
nextRefTiming = SC_ZERO_TIME;
+ nextState = ST_POSTPONE;
} else if (canPullIn) {
+ pre = doRefresh(payload, time);
+ nrt = tRFCx;
+ if (pre)
+ nrt += controllerCore.config.memSpec.tRP;
+ nextRefTiming = nrt;
nextState = ST_PULLIN;
- nextRefTiming = SC_ZERO_TIME; // Attempt to burst pull-in
} else {
doRefresh(payload, time);
nextRefTiming = tREFIx;
@@ -156,89 +170,86 @@ void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload &payload,
}
break;
case ST_PULLIN:
- // Pull-In Refresh. Try to pull-in refreshes as long as the limit
- // hasn't been reached yet and has credits
+ // Pull-in a refresh. Try to pull-in refreshes as long it is possible.
if (canPullIn) {
- doRefresh(payload, time);
- arCmdCounter++;
+ pulledin++;
+ pre = doRefresh(payload, time);
+ nrt = tRFCx;
+ if (pre)
+ nrt += controllerCore.config.memSpec.tRP;
+ nextRefTiming = nrt;
nextState = ST_PULLIN;
- nextRefTiming = tRFCx;
} else {
- // Saving value to be used by ST_ALIGN
- alignValue = arCmdCounter;
- nextState = ST_ALIGN;
nextRefTiming = SC_ZERO_TIME;
+ nextState = ST_ALIGN;
}
break;
case ST_SKIP:
- // Skip Refresh. The arCmdCounter is used to skip the correct amount
- // of refreshes
- arCmdCounter--;
- if (arCmdCounter == 0) {
- nextState = ST_REFRESH;
+ // Skip the pulled-in refreshes.
+ if (pulledin == 0) {
nextRefTiming = SC_ZERO_TIME;
+ nextState = ST_REFRESH;
} else {
- nextState = ST_SKIP;
+ pulledin--;
nextRefTiming = tREFIx;
+ nextState = ST_SKIP;
}
break;
case ST_POSTPONE:
// Postpone Refresh. Delaying refreshes as long as there are pending
// requests and credits to postpone. Should be followed by a burst
- // refresh
- if ((arCmdCounter == maxpostpone) || ((!pendingReq)
- && !controllerCore.config.ControllerCoreRefForceMaxPostponeBurst)) {
- // Burst conditions met
- if (arCmdCounter < maxpostpone) {
- // In case the burst was started by inactivity, need to also
- // count the current REF
- arCmdCounter++;
- }
- // Will start a burst next, so the value is saved to be used by
- // ST_ALIGN
- alignValue = arCmdCounter;
- nextState = ST_BURST;
+ // refresh.
+ postponed++;
+ if ((postponed > maxpostpone) || (!pendingReq
+ && !controllerCore.config.ControllerCoreRefForceMaxPostponeBurst)) {
+ // Burst triggered by inactivity or max postpone value reached.
nextRefTiming = SC_ZERO_TIME;
+ nextState = ST_BURST;
} else {
- arCmdCounter++;
- nextState = ST_POSTPONE;
nextRefTiming = tREFIx;
+ nextState = ST_POSTPONE;
}
break;
case ST_BURST:
- // Burst Refresh. The arCmdCounter is used to issue the correct amount
- // of refreshes
- arCmdCounter--;
- doRefresh(payload, time);
- if (arCmdCounter == 0) {
- // All bursts issued, next state will align to tREFIx
- nextState = ST_ALIGN;
+ // Burst postponed refreshes.
+ pre = doRefresh(payload, time);
+ postponed--;
+ if (postponed == 0) {
+ // All refreshes issued, next state will align to tREFIx
nextRefTiming = SC_ZERO_TIME;
+ nextState = ST_ALIGN;
} else {
+ nrt = tRFCx;
+ if (pre)
+ nrt += controllerCore.config.memSpec.tRP;
+ nextRefTiming = nrt;
nextState = ST_BURST;
- nextRefTiming = tRFCx;
}
break;
case ST_ALIGN:
// Align Refresh. Adjusting the timing so the next REF timing will be
// a in a time multiple of tREFIx
+ nextRefTiming = tREFIx;
+ align = true;
if (previousState == ST_PULLIN) {
- nextRefTiming = tREFIx - (tRFCx * (alignValue));
nextState = ST_SKIP;
} else {
- nextRefTiming = tREFIx - (tRFCx * (alignValue - 1));
nextState = ST_REFRESH;
}
break;
default:
- SC_REPORT_FATAL(this->name(), "Invalid state in flexible refresh FSM. Stop.");
+ SC_REPORT_FATAL(this->name(), "Invalid state in flexible refresh FSM.");
break;
}
- planNextRefresh(nextRefTiming);
+ planNextRefresh(nextRefTiming, align);
}
-void RefreshManager::planNextRefresh(sc_time nextRefTiming)
+void RefreshManager::planNextRefresh(sc_time nextRefTiming, bool align)
{
+ if (align) {
+ nextPlannedRefresh = trunc(nextPlannedRefresh.to_double() / tREFIx.to_double())
+ * tREFIx;
+ }
nextPlannedRefresh += nextRefTiming;
controllerCore.controller.send(REFTrigger, nextPlannedRefresh,
refreshPayloads[Bank(0)]);
@@ -247,7 +258,7 @@ void RefreshManager::planNextRefresh(sc_time nextRefTiming)
void RefreshManager::reInitialize(Bank, sc_time time)
{
nextPlannedRefresh = clkAlign(time, Alignment::DOWN);
- planNextRefresh(tREFIx);
+ planNextRefresh(tREFIx, true);
}
bool RefreshManager::isInvalidated(tlm::tlm_generic_payload &payload
diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManager.h b/DRAMSys/library/src/controller/core/refresh/RefreshManager.h
index 33ec9861..c5fb5905 100644
--- a/DRAMSys/library/src/controller/core/refresh/RefreshManager.h
+++ b/DRAMSys/library/src/controller/core/refresh/RefreshManager.h
@@ -63,17 +63,18 @@ private:
sc_time tREFIx;
sc_time tRFCx;
std::map refreshPayloads;
- unsigned int maxpostpone = 0;
- unsigned int maxpullin = 0;
- unsigned int alignToTrefiValue = 0;
- unsigned int arCmdCounter = 0;
- unsigned int alignValue = 0;
- ref_fsm_state_t currentState = ST_REFRESH;
- ref_fsm_state_t previousState = ST_REFRESH;
- ref_fsm_state_t nextState = ST_REFRESH;
+ bool postponeEnabled;
+ bool pullInEnabled;
+ unsigned int maxpostpone;
+ unsigned int maxpullin;
+ unsigned int pulledin;
+ unsigned int postponed;
+ ref_fsm_state_t currentState;
+ ref_fsm_state_t previousState;
+ ref_fsm_state_t nextState;
- void doRefresh(tlm::tlm_generic_payload &payload, sc_time time);
- void planNextRefresh(sc_time time);
+ bool doRefresh(tlm::tlm_generic_payload &payload, sc_time time);
+ void planNextRefresh(sc_time time, bool align);
void printDebugMessage(std::string message);
};