667,670c667,668
< // if REF in progress, transition to LP state should not occur
< // until REF completes
< if ((dram_pkt->rankRef.refreshState == REF_IDLE) &&
< (dram_pkt->rankRef.lowPowerEntryReady())) {
---
> if (dram_pkt->rankRef.isQueueEmpty() &&
> dram_pkt->rankRef.outstandingEvents == 0) {
1671c1669
< DRAMCtrl::Rank::lowPowerEntryReady() const
---
> DRAMCtrl::Rank::isQueueEmpty() const
1672a1671
> // check commmands in Q based on current bus direction
1676,1685c1675
<
< if (refreshState == REF_RUN) {
< // have not decremented outstandingEvents for refresh command
< // still check if there are no commands queued to force PD
< // entry after refresh completes
< return no_queued_cmds;
< } else {
< // ensure no commands in Q and no commands scheduled
< return (no_queued_cmds && (outstandingEvents == 0));
< }
---
> return no_queued_cmds;
1755c1745
< if (lowPowerEntryReady()) {
---
> if (isQueueEmpty() && outstandingEvents == 0) {
1956c1946,1949
< } else if (lowPowerEntryReady()) {
---
> } else if (isQueueEmpty()) {
> // still have refresh event outstanding but there should
> // be no other events outstanding
> assert(outstandingEvents == 1);
1969,1974c1962,1967
< // if transitioning to self refresh do not schedule a new refresh;
< // when waking from self refresh, a refresh is scheduled again.
< if (pwrStateTrans != PWR_SREF) {
< // compensate for the delay in actually performing the refresh
< // when scheduling the next one
< schedule(refreshEvent, refreshDueAt - memory.tRP);
---
> // At this point, we have completed the current refresh.
> // In the SREF bypass case, we do not get to this state in the
> // refresh STM and therefore can always schedule next event.
> // Compensate for the delay in actually performing the refresh
> // when scheduling the next one
> schedule(refreshEvent, refreshDueAt - memory.tRP);
1976,1978c1969,1970
< DPRINTF(DRAMState, "Refresh done at %llu and next refresh"
< " at %llu\n", curTick(), refreshDueAt);
< }
---
> DPRINTF(DRAMState, "Refresh done at %llu and next refresh"
> " at %llu\n", curTick(), refreshDueAt);
2025c2017
< // if a refresh just occured
---
> // if a refresh just occurred
2027,2046c2019,2035
< // do not transition to SREF if commands are in Q; stay in PRE_PDN
< if (pwrStatePostRefresh == PWR_ACT_PDN || !lowPowerEntryReady()) {
< // prechage power down requires tCKE to enter. For simplicity
< // this is not considered.
< schedulePowerEvent(PWR_PRE_PDN, tick);
< //push Command to DRAMPower
< cmdList.push_back(Command(MemCommand::PDN_F_PRE, 0, tick));
< DPRINTF(DRAMPower, "%llu,PDN_F_PRE,0,%d\n", divCeil(tick,
< memory.tCK) - memory.timeStampOffset, rank);
< } else {
< // last low power State was power precharge
< assert(pwrStatePostRefresh == PWR_PRE_PDN);
< // self refresh requires time tCKESR to enter. For simplicity,
< // this is not considered.
< schedulePowerEvent(PWR_SREF, tick);
< // push Command to DRAMPower
< cmdList.push_back(Command(MemCommand::SREN, 0, tick));
< DPRINTF(DRAMPower, "%llu,SREN,0,%d\n", divCeil(tick,
< memory.tCK) - memory.timeStampOffset, rank);
< }
---
> // precharge power down requires tCKE to enter. For simplicity
> // this is not considered.
> schedulePowerEvent(PWR_PRE_PDN, tick);
> //push Command to DRAMPower
> cmdList.push_back(Command(MemCommand::PDN_F_PRE, 0, tick));
> DPRINTF(DRAMPower, "%llu,PDN_F_PRE,0,%d\n", divCeil(tick,
> memory.tCK) - memory.timeStampOffset, rank);
> } else if (pwr_state == PWR_SREF) {
> // should only enter SREF after PRE-PD wakeup to do a refresh
> assert(pwrStatePostRefresh == PWR_PRE_PDN);
> // self refresh requires time tCKESR to enter. For simplicity,
> // this is not considered.
> schedulePowerEvent(PWR_SREF, tick);
> // push Command to DRAMPower
> cmdList.push_back(Command(MemCommand::SREN, 0, tick));
> DPRINTF(DRAMPower, "%llu,SREN,0,%d\n", divCeil(tick,
> memory.tCK) - memory.timeStampOffset, rank);
2151c2140
< // REF complete, decrement count
---
> // REF complete, decrement count and go back to IDLE
2152a2142
> refreshState = REF_IDLE;
2155c2145
< // if sleeping after refresh
---
> // if moving back to power-down after refresh
2157c2147
< assert((pwrState == PWR_PRE_PDN) || (pwrState == PWR_SREF));
---
> assert(pwrState == PWR_PRE_PDN);
2161,2167c2151,2152
< if (pwrState != PWR_SREF) {
< // rank is not available in SREF
< // don't transition to IDLE in this case
< refreshState = REF_IDLE;
< }
< // a request event could be already scheduled by the state
< // machine of the other rank
---
>
> // completed refresh event, ensure next request is scheduled
2169,2170c2154,2155
< DPRINTF(DRAM, "Scheduling next request after refreshing rank %d\n",
< rank);
---
> DPRINTF(DRAM, "Scheduling next request after refreshing"
> " rank %d\n", rank);
2173,2176c2158
< } else if (pwrState == PWR_ACT) {
< if (refreshState == REF_PD_EXIT) {
< // kick the refresh event loop into action again
< assert(prev_state == PWR_ACT_PDN);
---
> }
2178,2181c2160,2166
< // go back to REF event and close banks
< refreshState = REF_PRE;
< schedule(refreshEvent, curTick());
< }
---
> if ((pwrState == PWR_ACT) && (refreshState == REF_PD_EXIT)) {
> // have exited ACT PD
> assert(prev_state == PWR_ACT_PDN);
>
> // go back to REF event and close banks
> refreshState = REF_PRE;
> schedule(refreshEvent, curTick());
2193c2178
< // the idle state, directly transition to a refresh
---
> // the idle state, directly transition to, or schedule refresh
2202,2203c2187,2195
< // update the state in zero time and proceed below
< pwrState = PWR_REF;
---
> if (refreshState == REF_PD_EXIT) {
> // exiting PRE PD, will be in IDLE until tXP expires
> // and then should transition to PWR_REF state
> assert(prev_state == PWR_PRE_PDN);
> schedulePowerEvent(PWR_REF, curTick() + memory.tXP);
> } else if (refreshState == REF_PRE) {
> // can directly move to PWR_REF state and proceed below
> pwrState = PWR_REF;
> }
2210c2202
< }
---
> }
2213,2216c2205,2206
< // we transition to the refresh state, let the refresh state
< // machine know of this state update and let it deal with the
< // scheduling of the next power state transition as well as the
< // following refresh
---
> // transition to the refresh state and re-start refresh process
> // refresh state machine will schedule the next power state transition
2217a2208
> // completed final PRE for refresh or exiting power-down
2219d2209
< DPRINTF(DRAMState, "Refreshing\n");
2221,2226c2211,2228
< // kick the refresh event loop into action again, and that
< // in turn will schedule a transition to the idle power
< // state once the refresh is done
< if (refreshState == REF_PD_EXIT) {
< // Wait for PD exit timing to complete before issuing REF
< schedule(refreshEvent, curTick() + memory.tXP);
---
> // exited PRE PD for refresh, with no pending commands
> // bypass auto-refresh and go straight to SREF, where memory
> // will issue refresh immediately upon entry
> if (pwrStatePostRefresh == PWR_PRE_PDN && isQueueEmpty() &&
> (memory.drainState() != DrainState::Draining) &&
> (memory.drainState() != DrainState::Drained)) {
> DPRINTF(DRAMState, "Rank %d bypassing refresh and transitioning "
> "to self refresh at %11u tick\n", rank, curTick());
> powerDownSleep(PWR_SREF, curTick());
>
> // Since refresh was bypassed, remove event by decrementing count
> assert(outstandingEvents == 1);
> --outstandingEvents;
>
> // reset state back to IDLE temporarily until SREF is entered
> pwrState = PWR_IDLE;
>
> // Not bypassing refresh for SREF entry
2227a2230,2237
> DPRINTF(DRAMState, "Refreshing\n");
>
> // there should be nothing waiting at this point
> assert(!powerEvent.scheduled());
>
> // kick the refresh event loop into action again, and that
> // in turn will schedule a transition to the idle power
> // state once the refresh is done
2228a2239,2241
>
> // Banks transitioned to IDLE, start REF
> refreshState = REF_START;
2230,2231d2242
< // Banks transitioned to IDLE, start REF
< refreshState = REF_START;
2232a2244
>