Refresh Manager Bankwise - several improvements

Considering initial PRE time for planning next REF when necessary.
Postpone burst for a bank shall not be interrupted.
Correct number of additional REF are pulled-in/postponed for a bank.
Alignment to tREFI.
This commit is contained in:
Éder F. Zulian
2018-07-10 12:50:22 +02:00
parent 8faec705e0
commit 7c538cdcd0
3 changed files with 80 additions and 72 deletions

View File

@@ -41,7 +41,6 @@
#include "../ControllerCore.h"
#include "../TimingCalculation.h"
#include "../../../common/Utils.h"
#include "../TimingCalculation.h"
using namespace tlm;

View File

@@ -49,19 +49,19 @@ RefreshManagerBankwise::RefreshManagerBankwise(sc_module_name,
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;
for (Bank bank : controller.getBanks()) {
nextPlannedRefreshs[bank] = SC_ZERO_TIME;
arCmdCounter[bank] = 0;
alignValue[bank] = 0;
pulledin[bank] = 0;
postponed[bank] = 0;
currentState[bank] = ST_REFRESH;
previousState[bank] = ST_REFRESH;
nextState[bank] = ST_REFRESH;
setUpDummy(refreshPayloads[bank], bank);
planNextRefresh(bank, tREFIx);
planNextRefresh(bank, tREFIx, false);
}
}
@@ -76,22 +76,31 @@ bool RefreshManagerBankwise::hasCollision(const ScheduledCommand &command)
controllerCore.state->getLastCommand(Command::AutoRefresh, bank).getEnd();
bool collisionWithNextRefStart = command.getEnd() >= nextPlannedRefreshs[bank];
if (controllerCore.config.ControllerCoreRefEnablePostpone
&& (arCmdCounter[bank] < maxpostpone)) {
&& (postponed[bank] < 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.
collisionWithNextRefStart = false;
}
if (currentState[bank] == ST_BURST) {
// A burst due to postponed refreshes shall not be interrupted.
collisionWithNextRefStart = true;
}
return collisionWithPreviousRefEnd || collisionWithNextRefStart;
}
void RefreshManagerBankwise::doRefresh(tlm::tlm_generic_payload &payload,
bool RefreshManagerBankwise::doRefresh(tlm::tlm_generic_payload &payload,
sc_time time)
{
sc_assert(!isInvalidated(payload, time));
bool pre = false;
tlm::tlm_generic_payload &refreshPayload =
refreshPayloads[DramExtension::getExtension(payload).getBank()];
DramExtension &extension = DramExtension::getExtension(refreshPayload);
if (controllerCore.state->rowBufferStates->rowBufferIsOpen(
extension.getBank())) {
pre = true;
ScheduledCommand precharge(Command::Precharge, time,
getExecutionTime(Command::Precharge, refreshPayload), extension);
controllerCore.getCommandChecker(Command::Precharge).delayToSatisfyConstraints(
@@ -107,6 +116,7 @@ void RefreshManagerBankwise::doRefresh(tlm::tlm_generic_payload &payload,
controllerCore.state->change(refresh);
extension.incrementRow();
controllerCore.controller.send(refresh, refreshPayload);
return pre;
}
void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload &payload,
@@ -115,24 +125,29 @@ void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload &payload,
sc_time nextRefTiming;
Bank bank = DramExtension::getExtension(payload).getBank();
bool pendingReq = controllerCore.hasPendingRequests(bank);
bool canPostpone = pendingReq && (arCmdCounter[bank] < maxpostpone);
bool canPullIn = !pendingReq && (arCmdCounter[bank] < maxpullin);
bool canPostpone = postponeEnabled && pendingReq && (postponed[bank] < maxpostpone);
bool canPullIn = pullInEnabled && !pendingReq && (pulledin[bank] < maxpullin);
previousState[bank] = currentState[bank];
currentState[bank] = nextState[bank];
bool align = false;
sc_time nrt;
bool pre;
switch (currentState[bank]) {
case ST_REFRESH:
// Regular Refresh. It's possible to migrate from this to the flexible
// refresh states
// The arCmdCounter[bank] should always be equal to zero here
assert(arCmdCounter[bank] == 0);
assert(pulledin[bank] == 0 && postponed[bank] == 0);
if (canPostpone) {
nextState[bank] = ST_POSTPONE;
nextRefTiming = SC_ZERO_TIME;
nextState[bank] = ST_POSTPONE;
} else if (canPullIn) {
pre = doRefresh(payload, time);
nrt = tRFCx;
if (pre)
nrt += controllerCore.config.memSpec.tRP;
nextRefTiming = nrt;
nextState[bank] = ST_PULLIN;
nextRefTiming = SC_ZERO_TIME; // Attempt to burst pull-in
} else {
doRefresh(payload, time);
nextRefTiming = tREFIx;
@@ -140,93 +155,85 @@ void RefreshManagerBankwise::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[bank]++;
pulledin[bank]++;
pre = doRefresh(payload, time);
nrt = tRFCx;
if (pre)
nrt += controllerCore.config.memSpec.tRP;
nextRefTiming = nrt;
nextState[bank] = ST_PULLIN;
nextRefTiming = tRFCx;
} else {
// Saving value to be used by ST_ALIGN
alignValue[bank] = arCmdCounter[bank];
nextState[bank] = ST_ALIGN;
nextRefTiming = SC_ZERO_TIME;
nextState[bank] = ST_ALIGN;
}
break;
case ST_SKIP:
// Skip Refresh. The arCmdCounter[bank] is used to skip the correct
// amount of refreshes
arCmdCounter[bank]--;
if (arCmdCounter[bank] == 0) {
nextState[bank] = ST_REFRESH;
// Skip the pulled-in refreshes.
if (pulledin[bank] == 0) {
nextRefTiming = SC_ZERO_TIME;
nextState[bank] = ST_REFRESH;
} else {
nextState[bank] = ST_SKIP;
pulledin[bank]--;
nextRefTiming = tREFIx;
nextState[bank] = 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[bank] == maxpostpone) || ((!pendingReq)
&& !controllerCore.config.ControllerCoreRefForceMaxPostponeBurst)) {
// Burst conditions met
if (arCmdCounter[bank] < maxpostpone) {
// In case the burst was started by inactivity, need to also
// count the current REF
arCmdCounter[bank]++;
}
// Will start a burst next, so the value is saved to be used by
// ST_ALIGN
alignValue[bank] = arCmdCounter[bank];
nextState[bank] = ST_BURST;
postponed[bank]++;
if ((postponed[bank] > maxpostpone) || (!pendingReq && !controllerCore.config.ControllerCoreRefForceMaxPostponeBurst)) {
// Burst triggered by inactivity or max postpone value reached.
nextRefTiming = SC_ZERO_TIME;
nextState[bank] = ST_BURST;
} else {
arCmdCounter[bank]++;
nextState[bank] = ST_POSTPONE;
nextRefTiming = tREFIx;
nextState[bank] = ST_POSTPONE;
}
break;
case ST_BURST:
// Burst Refresh. The arCmdCounter[bank] is used to issue the correct
// amount of refreshes
arCmdCounter[bank]--;
doRefresh(payload, time);
if (arCmdCounter[bank] == 0) {
// All bursts issued, next state will align to tREFIx
nextState[bank] = ST_ALIGN;
// Burst postponed refreshes.
pre = doRefresh(payload, time);
postponed[bank]--;
if (postponed[bank] == 0) {
// All refreshes issued, next state will align to tREFIx
nextRefTiming = SC_ZERO_TIME;
nextState[bank] = ST_ALIGN;
} else {
nrt = tRFCx;
if (pre)
nrt += controllerCore.config.memSpec.tRP;
nextRefTiming = nrt;
nextState[bank] = 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.
// a in a time multiple of tREFIx
nextRefTiming = tREFIx;
align = true;
if (previousState[bank] == ST_PULLIN) {
nextRefTiming = tREFIx - (tRFCx * (alignValue[bank]));
nextState[bank] = ST_SKIP;
} else {
nextRefTiming = tREFIx - (tRFCx * (alignValue[bank] - 1));
nextState[bank] = ST_REFRESH;
}
break;
default:
SC_REPORT_FATAL(this->name(),
"Invalid state in bankwise flexible refresh FSM. Stop.");
SC_REPORT_FATAL(this->name(), "Invalid state in bw flex. ref. FSM.");
break;
}
planNextRefresh(bank, nextRefTiming);
planNextRefresh(bank, nextRefTiming, align);
}
void RefreshManagerBankwise::planNextRefresh(Bank bank, sc_time nextRefTiming)
void RefreshManagerBankwise::planNextRefresh(Bank bank, sc_time nextRefTiming, bool align)
{
if (align) {
nextPlannedRefreshs[bank] = trunc(nextPlannedRefreshs[bank].to_double() / tREFIx.to_double()) * tREFIx;
}
nextPlannedRefreshs[bank] += nextRefTiming;
controllerCore.controller.send(REFTrigger, nextPlannedRefreshs[bank],
refreshPayloads[bank]);
@@ -235,7 +242,7 @@ void RefreshManagerBankwise::planNextRefresh(Bank bank, sc_time nextRefTiming)
void RefreshManagerBankwise::reInitialize(Bank bank, sc_time time)
{
nextPlannedRefreshs[bank] = clkAlign(time, Alignment::DOWN);
planNextRefresh(bank, tREFIx);
planNextRefresh(bank, tREFIx, true);
}
bool RefreshManagerBankwise::isInvalidated(tlm::tlm_generic_payload &payload,

View File

@@ -38,9 +38,9 @@
#ifndef BANKWISEREFRESHMANAGER_H_
#define BANKWISEREFRESHMANAGER_H_
#include "../../../common/dramExtension.h"
#include "../configuration/MemSpec.h"
//#include "../../../common/dramExtension.h"
#include "IRefreshManager.h"
#include "../configuration/MemSpec.h"
class ControllerCore;
@@ -60,20 +60,22 @@ public:
private:
ControllerCore &controllerCore;
RefreshTiming &timing;
std::map<Bank, sc_time> nextPlannedRefreshs;
sc_time tREFIx;
sc_time tRFCx;
std::map<Bank, tlm::tlm_generic_payload> refreshPayloads;
std::map<Bank, sc_time> nextPlannedRefreshs;
unsigned int maxpostpone = 0;
unsigned int maxpullin = 0;
std::map<Bank, unsigned int> arCmdCounter;
std::map<Bank, unsigned int> alignValue;
bool postponeEnabled;
bool pullInEnabled;
unsigned int maxpostpone;
unsigned int maxpullin;
std::map<Bank, unsigned int> pulledin;
std::map<Bank, unsigned int> postponed;
std::map<Bank, ref_fsm_state_t> currentState;
std::map<Bank, ref_fsm_state_t> previousState;
std::map<Bank, ref_fsm_state_t> nextState;
void doRefresh(tlm::tlm_generic_payload &payload, sc_time time);
void planNextRefresh(Bank bank, sc_time nextRefTiming);
bool doRefresh(tlm::tlm_generic_payload &payload, sc_time time);
void planNextRefresh(Bank bank, sc_time time, bool align);
void printDebugMessage(std::string message);
};