From 8faec705e0b0ef4d5bccebb0ff37cf0e76ea2c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 10 Jul 2018 11:37:54 +0200 Subject: [PATCH] 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. --- .../simulations/ddr3_postpone_ref_test.xml | 2 +- .../core/refresh/RefreshManager.cpp | 145 ++++++++++-------- .../controller/core/refresh/RefreshManager.h | 21 +-- 3 files changed, 90 insertions(+), 78 deletions(-) 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); };