Refresh Manager - several improvements

Considering initial PRE time for planning next REF when necessary.
Postpone burst shall not be interrupted.
Correct number of additional REF are pulled-in/postponed.
Alignment to tREFI.
This commit is contained in:
Éder F. Zulian
2018-07-10 11:37:54 +02:00
parent c6e66305c1
commit 8faec705e0
3 changed files with 90 additions and 78 deletions

View File

@@ -16,6 +16,6 @@
In library mode e.g. in Platform Architect the trace setup is ignored.
-->
<tracesetup>
<device clkMhz="1000">ddr3_postpone_ref_test_3.stl</device>
<device clkMhz="1000">ddr3_postpone_ref_test_1.stl</device>
</tracesetup>
</simulation>

View File

@@ -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

View File

@@ -63,17 +63,18 @@ private:
sc_time tREFIx;
sc_time tRFCx;
std::map<Bank, tlm::tlm_generic_payload> 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);
};