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:
@@ -41,7 +41,6 @@
|
||||
#include "../ControllerCore.h"
|
||||
#include "../TimingCalculation.h"
|
||||
#include "../../../common/Utils.h"
|
||||
#include "../TimingCalculation.h"
|
||||
|
||||
using namespace tlm;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user