1/*
2 * Copyright (c) 2012-2014, TU Delft
3 * Copyright (c) 2012-2014, TU Eindhoven
4 * Copyright (c) 2012-2014, TU Kaiserslautern
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
23 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35
36#include "CommandAnalysis.h"
37
38using std::cerr;
39using std::endl;
40using std::max;
41
42using namespace Data;
43
44
45int64_t zero_guard(int64_t cycles_in, const char* warning)
46{
47  // Calculate max(0, cycles_in)
48  int64_t zero = 0;
49  if (warning != nullptr && cycles_in < 0) {
50    // This line is commented out for now, we will attempt to remove the situations where
51    // these warnings trigger later.
52    // cerr << "WARNING: " << warning << endl;
53  }
54  return max(zero, cycles_in);
55}
56
57void CommandAnalysis::handleAct(unsigned bank, int64_t timestamp)
58{
59  printWarningIfPoweredDown("Command issued while in power-down mode.", MemCommand::ACT, timestamp, bank);
60  // If command is ACT - update number of acts, bank state of the
61  // target bank, first and latest activation cycle and the memory
62  // state. Update the number of precharged/idle-precharged cycles.
63  // If the bank is already active ignore the command and generate a
64  // warning.
65  if (isPrecharged(bank)) {
66    numberofactsBanks[bank]++;
67
68    if (nActiveBanks() == 0) {
69      // Here a memory state transition to ACT is happening. Save the
70      // number of cycles in precharge state (increment the counter).
71      first_act_cycle = timestamp;
72      precycles += zero_guard(timestamp - last_pre_cycle, "1 last_pre_cycle is in the future.");
73      idle_pre_update(timestamp, latest_pre_cycle);
74    }
75
76    bank_state[bank] = BANK_ACTIVE;
77    latest_act_cycle = timestamp;
78  } else {
79    printWarning("Bank is already active!", MemCommand::ACT, timestamp, bank);
80  }
81}
82
83void CommandAnalysis::handleRd(unsigned bank, int64_t timestamp)
84{
85  printWarningIfPoweredDown("Command issued while in power-down mode.", MemCommand::RD, timestamp, bank);
86  // If command is RD - update number of reads and read cycle. Check
87  // for active idle cycles (if any).
88  if (isPrecharged(bank)) {
89    printWarning("Bank is not active!", MemCommand::RD, timestamp, bank);
90  }
91  numberofreadsBanks[bank]++;
92  idle_act_update(latest_read_cycle, latest_write_cycle, latest_act_cycle, timestamp);
93  latest_read_cycle = timestamp;
94}
95
96void CommandAnalysis::handleWr(unsigned bank, int64_t timestamp)
97{
98  printWarningIfPoweredDown("Command issued while in power-down mode.", MemCommand::WR, timestamp, bank);
99  // If command is WR - update number of writes and write cycle. Check
100  // for active idle cycles (if any).
101  if (isPrecharged(bank)) {
102    printWarning("Bank is not active!", MemCommand::WR, timestamp, bank);
103  }
104  numberofwritesBanks[bank]++;
105  idle_act_update(latest_read_cycle, latest_write_cycle, latest_act_cycle, timestamp);
106  latest_write_cycle = timestamp;
107}
108
109void CommandAnalysis::handleRef(unsigned bank, int64_t timestamp)
110{
111  printWarningIfPoweredDown("Command issued while in power-down mode.", MemCommand::REF, timestamp, bank);
112  // If command is REF - update number of refreshes, set bank state of
113  // all banks to ACT, set the last PRE cycles at RFC-RP cycles from
114  // timestamp, set the number of active cycles to RFC-RP and check
115  // for active and precharged cycles and idle active and idle
116  // precharged cycles before refresh. Change memory state to 0.
117  printWarningIfActive("One or more banks are active! REF requires all banks to be precharged.", MemCommand::REF, timestamp, bank);
118  numberofrefs++;
119  idle_pre_update(timestamp, latest_pre_cycle);
120  first_act_cycle  = timestamp;
121  std::fill(first_act_cycle_banks.begin(), first_act_cycle_banks.end(), timestamp);
122  precycles       += zero_guard(timestamp - last_pre_cycle, "2 last_pre_cycle is in the future.");
123  last_pre_cycle   = timestamp + memSpec.memTimingSpec.RFC - memSpec.memTimingSpec.RP;
124  latest_pre_cycle = last_pre_cycle;
125  actcycles       += memSpec.memTimingSpec.RFC - memSpec.memTimingSpec.RP;
126  for (auto &e : actcyclesBanks) {
127    e += memSpec.memTimingSpec.RFC - memSpec.memTimingSpec.RP;
128  }
129  for (auto& bs : bank_state) {
130    bs = BANK_PRECHARGED;
131  }
132}
133
134void CommandAnalysis::handleRefB(unsigned bank, int64_t timestamp)
135{
136  // A REFB command requires a previous PRE command.
137  if (isPrecharged(bank)) {
138    // This previous PRE command handler is also responsible for keeping the
139    // memory state updated.
140    // Here we consider that the memory state is not changed in order to keep
141    // things simple, since the transition from PRE to ACT state takes time.
142    numberofrefbBanks[bank]++;
143    // Length of the refresh: here we have an approximation, we consider tRP
144    // also as act cycles because the bank will be precharged (stable) after
145    // tRP.
146    actcyclesBanks[bank] += memSpec.memTimingSpec.RAS + memSpec.memTimingSpec.RP;
147  } else {
148    printWarning("Bank must be precharged for REFB!", MemCommand::REFB, timestamp, bank);
149  }
150}
151
152void CommandAnalysis::handlePre(unsigned bank, int64_t timestamp)
153{
154  printWarningIfPoweredDown("Command issued while in power-down mode.", MemCommand::PRE, timestamp, bank);
155  // If command is explicit PRE - update number of precharges, bank
156  // state of the target bank and last and latest precharge cycle.
157  // Calculate the number of active cycles if the memory was in the
158  // active state before, but there is a state transition to PRE now
159  // (i.e., this is the last active bank).
160  // If the bank is already precharged ignore the command and generate a
161  // warning.
162
163  // Precharge only if the target bank is active
164  if (bank_state[bank] == BANK_ACTIVE) {
165    numberofpresBanks[bank]++;
166    actcyclesBanks[bank] += zero_guard(timestamp - first_act_cycle_banks[bank], "first_act_cycle is in the future (bank).");
167    // Since we got here, at least one bank is active
168    assert(nActiveBanks() != 0);
169
170    if (nActiveBanks() == 1) {
171      // This is the last active bank. Therefore, here a memory state
172      // transition to PRE is happening. Let's increment the active cycle
173      // counter.
174      actcycles += zero_guard(timestamp - first_act_cycle, "first_act_cycle is in the future.");
175      last_pre_cycle = timestamp;
176      idle_act_update(latest_read_cycle, latest_write_cycle, latest_act_cycle, timestamp);
177    }
178
179    bank_state[bank] = BANK_PRECHARGED;
180    latest_pre_cycle = timestamp;
181  } else {
182    printWarning("Bank is already precharged!", MemCommand::PRE, timestamp, bank);
183  }
184}
185
186void CommandAnalysis::handlePreA(unsigned bank, int64_t timestamp)
187{
188  printWarningIfPoweredDown("Command issued while in power-down mode.", MemCommand::PREA, timestamp, bank);
189  // If command is explicit PREA (precharge all banks) - update
190  // number of precharges by the number of active banks, update the bank
191  // state of all banks to PRE and set the precharge cycle (the cycle in
192  // which the memory state changes from ACT to PRE, aka last_pre_cycle).
193  // Calculate the number of active cycles if the memory was in the
194  // active state before, but there is a state transition to PRE now.
195
196  if (nActiveBanks() > 0) {
197    // Active banks are being precharged
198    // At least one bank was active, therefore the current memory state is
199    // ACT. Since all banks are being precharged a memory state transition
200    // to PRE is happening. Add to the counter the amount of cycles the
201    // memory remained in the ACT state.
202
203    actcycles += zero_guard(timestamp - first_act_cycle, "first_act_cycle is in the future.");
204    last_pre_cycle = timestamp;
205
206    for (unsigned b = 0; b < num_banks; b++) {
207      if (bank_state[b] == BANK_ACTIVE) {
208        // Active banks are being precharged
209        numberofpresBanks[b] += 1;
210        actcyclesBanks[b] += zero_guard(timestamp - first_act_cycle_banks[b], "first_act_cycle is in the future (bank).");
211      }
212    }
213
214    idle_act_update(latest_read_cycle, latest_write_cycle, latest_act_cycle, timestamp);
215
216    latest_pre_cycle = timestamp;
217    // Reset the state for all banks to precharged.
218    for (auto& bs : bank_state) {
219      bs = BANK_PRECHARGED;
220    }
221  } else {
222    printWarning("All banks are already precharged!", MemCommand::PREA, timestamp, bank);
223  }
224}
225
226void CommandAnalysis::handlePdnFAct(unsigned bank, int64_t timestamp)
227{
228  // If command is fast-exit active power-down - update number of
229  // power-downs, set the power-down cycle and the memory mode to
230  // fast-exit active power-down. Save states of all the banks from
231  // the cycle before entering active power-down, to be returned to
232  // after powering-up. Update active and active idle cycles.
233  printWarningIfNotActive("All banks are precharged! Incorrect use of Active Power-Down.", MemCommand::PDN_F_ACT, timestamp, bank);
234  f_act_pdns++;
235  last_bank_state = bank_state;
236  pdn_cycle  = timestamp;
237  actcycles += zero_guard(timestamp - first_act_cycle, "first_act_cycle is in the future.");
238  for (unsigned b = 0; b < num_banks; b++) {
239    if (bank_state[b] == BANK_ACTIVE) {
240      actcyclesBanks[b] += zero_guard(timestamp - first_act_cycle_banks[b], "first_act_cycle is in the future (bank).");
241    }
242  }
243  idle_act_update(latest_read_cycle, latest_write_cycle, latest_act_cycle, timestamp);
244  mem_state  = CommandAnalysis::MS_PDN_F_ACT;
245}
246
247void CommandAnalysis::handlePdnSAct(unsigned bank, int64_t timestamp)
248{
249  // If command is slow-exit active power-down - update number of
250  // power-downs, set the power-down cycle and the memory mode to
251  // slow-exit active power-down. Save states of all the banks from
252  // the cycle before entering active power-down, to be returned to
253  // after powering-up. Update active and active idle cycles.
254  printWarningIfNotActive("All banks are precharged! Incorrect use of Active Power-Down.", MemCommand::PDN_S_ACT, timestamp, bank);
255  s_act_pdns++;
256  last_bank_state = bank_state;
257  pdn_cycle  = timestamp;
258  actcycles += zero_guard(timestamp - first_act_cycle, "first_act_cycle is in the future.");
259  for (unsigned b = 0; b < num_banks; b++) {
260    if (bank_state[b] == BANK_ACTIVE) {
261      actcyclesBanks[b] += zero_guard(timestamp - first_act_cycle_banks[b], "first_act_cycle is in the future (bank).");
262    }
263  }
264  idle_act_update(latest_read_cycle, latest_write_cycle, latest_act_cycle, timestamp);
265  mem_state  = CommandAnalysis::MS_PDN_S_ACT;
266}
267
268void CommandAnalysis::handlePdnFPre(unsigned bank, int64_t timestamp)
269{
270  // If command is fast-exit precharged power-down - update number of
271  // power-downs, set the power-down cycle and the memory mode to
272  // fast-exit precahrged power-down. Update precharged and precharged
273  // idle cycles.
274  printWarningIfActive("One or more banks are active! Incorrect use of Precharged Power-Down.", MemCommand::PDN_F_PRE, timestamp, bank);
275  f_pre_pdns++;
276  pdn_cycle  = timestamp;
277  precycles += zero_guard(timestamp - last_pre_cycle, "3 last_pre_cycle is in the future.");
278  idle_pre_update(timestamp, latest_pre_cycle);
279  mem_state  = CommandAnalysis::MS_PDN_F_PRE;
280}
281
282void CommandAnalysis::handlePdnSPre(unsigned bank, int64_t timestamp)
283{
284  // If command is slow-exit precharged power-down - update number of
285  // power-downs, set the power-down cycle and the memory mode to
286  // slow-exit precahrged power-down. Update precharged and precharged
287  // idle cycles.
288  printWarningIfActive("One or more banks are active! Incorrect use of Precharged Power-Down.",  MemCommand::PDN_S_PRE, timestamp, bank);
289  s_pre_pdns++;
290  pdn_cycle  = timestamp;
291  precycles += zero_guard(timestamp - last_pre_cycle, "4 last_pre_cycle is in the future.");
292  idle_pre_update(timestamp, latest_pre_cycle);
293  mem_state  = CommandAnalysis::MS_PDN_S_PRE;
294}
295
296void CommandAnalysis::handlePupAct(int64_t timestamp)
297{
298  // If command is power-up in the active mode - check the power-down
299  // exit-mode employed (fast or slow), update the number of power-down
300  // and power-up cycles and the latest and first act cycle. Also, reset
301  // all the individual bank states to the respective saved states
302  // before entering power-down.
303  const MemTimingSpec& t = memSpec.memTimingSpec;
304
305  if (mem_state == CommandAnalysis::MS_PDN_F_ACT) {
306    f_act_pdcycles  += zero_guard(timestamp - pdn_cycle, "pdn_cycle is in the future.");
307    pup_act_cycles  += t.XP;
308    latest_act_cycle = timestamp;
309  } else if (mem_state == CommandAnalysis::MS_PDN_S_ACT) {
310    s_act_pdcycles += zero_guard(timestamp - pdn_cycle, "pdn_cycle is in the future.");
311    if (memSpec.memArchSpec.dll == false) {
312      pup_act_cycles  += t.XP;
313      latest_act_cycle = timestamp;
314    } else {
315      pup_act_cycles  += t.XPDLL - t.RCD;
316      latest_act_cycle = timestamp + zero_guard(t.XPDLL - (2 * t.RCD), "t.XPDLL - (2 * t.RCD) < 0");
317    }
318  } else {
319    cerr << "Incorrect use of Active Power-Up!" << endl;
320  }
321  mem_state = MS_NOT_IN_PD;
322  bank_state = last_bank_state;
323  first_act_cycle = timestamp;
324  std::fill(first_act_cycle_banks.begin(), first_act_cycle_banks.end(), timestamp);
325}
326
327void CommandAnalysis::handlePupPre(int64_t timestamp)
328{
329  // If command is power-up in the precharged mode - check the power-down
330  // exit-mode employed (fast or slow), update the number of power-down
331  // and power-up cycles and the latest and last pre cycle.
332  const MemTimingSpec& t = memSpec.memTimingSpec;
333  if (mem_state == CommandAnalysis::MS_PDN_F_PRE) {
334    f_pre_pdcycles  += zero_guard(timestamp - pdn_cycle, "pdn_cycle is in the future.");
335    pup_pre_cycles  += t.XP;
336    latest_pre_cycle = timestamp;
337  } else if (mem_state == CommandAnalysis::MS_PDN_S_PRE) {
338    s_pre_pdcycles += zero_guard(timestamp - pdn_cycle, "pdn_cycle is in the future.");
339    if (memSpec.memArchSpec.dll == false) {
340      pup_pre_cycles  += t.XP;
341      latest_pre_cycle = timestamp;
342    } else {
343      pup_pre_cycles  += t.XPDLL - t.RCD;
344      latest_pre_cycle = timestamp + zero_guard(t.XPDLL - t.RCD - t.RP, "t.XPDLL - t.RCD - t.RP");
345    }
346  } else {
347    cerr << "Incorrect use of Precharged Power-Up!" << endl;
348  }
349  mem_state      = MS_NOT_IN_PD;
350  last_pre_cycle = timestamp;
351}
352
353void CommandAnalysis::handleSREn(unsigned bank, int64_t timestamp)
354{
355  // If command is self-refresh - update number of self-refreshes,
356  // set memory state to SREF, update precharge and idle precharge
357  // cycles and set the self-refresh cycle.
358  printWarningIfActive("One or more banks are active! SREF requires all banks to be precharged.", MemCommand::SREN, timestamp, bank);
359  numberofsrefs++;
360  sref_cycle = timestamp;
361  sref_cycle_window = timestamp;
362  sref_ref_pre_cycles_window = 0;
363  sref_ref_act_cycles_window = 0;
364  precycles += zero_guard(timestamp - last_pre_cycle, "5  last_pre_cycle is in the future.");
365  idle_pre_update(timestamp, latest_pre_cycle);
366  mem_state  = CommandAnalysis::MS_SREF;
367}
368
369void CommandAnalysis::handleSREx(unsigned bank, int64_t timestamp)
370{
371  // If command is self-refresh exit - update the number of self-refresh
372  // clock cycles, number of active and precharged auto-refresh clock
373  // cycles during self-refresh and self-refresh exit based on the number
374  // of cycles in the self-refresh mode and auto-refresh duration (RFC).
375  // Set the last and latest precharge cycle accordingly and set the
376  // memory state to 0.
377  const MemTimingSpec& t = memSpec.memTimingSpec;
378  if (mem_state != CommandAnalysis::MS_SREF) {
379    cerr << "Incorrect use of Self-Refresh Power-Up!" << endl;
380  }
381  // The total duration of self-refresh is given by the difference between
382  // the current clock cycle and the clock cycle of entering self-refresh.
383  int64_t sref_duration = timestamp - sref_cycle;
384
385  // Negative or zero duration should never happen.
386  if (sref_duration <= 0) {
387    printWarning("Invalid Self-Refresh duration!", MemCommand::SREX, timestamp, bank);
388    sref_duration = 0;
389  }
390
391  // The minimum time that the DRAM must remain in Self-Refresh is CKESR.
392  if (sref_duration < t.CKESR) {
393    printWarning("Self-Refresh duration < CKESR!", MemCommand::SREX, timestamp, bank);
394  }
395
396  if (sref_duration >= t.RFC) {
397    /*
398     * Self-refresh Exit Context 1 (tSREF >= tRFC):
399     * The memory remained in self-refresh for a certain number of clock
400     * cycles greater than a refresh cycle time (RFC). Consequently, the
401     * initial auto-refresh accomplished.
402     *
403     *
404     *  SREN                                #              SREX
405     *  |                                   #                ^
406     *  |                                   #                |
407     *  |<------------------------- tSREF ----------...----->|
408     *  |                                   #                |
409     *  |      Initial Auto-Refresh         #                |
410     *  v                                   #                |
411     *  ------------------------------------#-------...-----------------> t
412     *                                      #
413     *   <------------- tRFC -------------->#
414     *   <---- (tRFC - tRP) ----><-- tRP -->#
415     *               |                |
416     *               v                v
417     *     sref_ref_act_cycles     sref_ref_pre_cycles
418     *
419     *
420     * Summary:
421     * sref_cycles += tSREF – tRFC
422     * sref_ref_act_cycles += tRFC - tRP
423     * sref_ref_pre_cycles += tRP
424     * spup_ref_act_cycles += 0
425     * spup_ref_pre_cycles += 0
426     *
427     */
428
429    // The initial auto-refresh consumes (IDD5 − IDD3N) over one refresh
430    // period (RFC) from the start of the self-refresh.
431    sref_ref_act_cycles += t.RFC -
432                           t.RP - sref_ref_act_cycles_window;
433    sref_ref_pre_cycles += t.RP - sref_ref_pre_cycles_window;
434    last_pre_cycle       = timestamp;
435
436    // The IDD6 current is consumed for the time period spent in the
437    // self-refresh mode, which excludes the time spent in finishing the
438    // initial auto-refresh.
439    if (sref_cycle_window > sref_cycle + t.RFC) {
440        sref_cycles += zero_guard(timestamp - sref_cycle_window, "sref_cycle_window is in the future.");
441    } else {
442        sref_cycles += zero_guard(timestamp - sref_cycle - t.RFC, "sref_cycle - t.RFC < 0");
443    }
444
445    // IDD2N current is consumed when exiting the self-refresh state.
446    if (memSpec.memArchSpec.dll == false) {
447      spup_cycles     += t.XS;
448      latest_pre_cycle = timestamp + zero_guard(t.XS - t.RP, "t.XS - t.RP < 0");
449    } else {
450      spup_cycles     += t.XSDLL - t.RCD;
451      latest_pre_cycle = timestamp + zero_guard(t.XSDLL - t.RCD  - t.RP, "t.XSDLL - t.RCD  - t.RP < 0");
452    }
453
454  } else {
455    // Self-refresh Exit Context 2 (tSREF < tRFC):
456    // Exit self-refresh before the completion of the initial
457    // auto-refresh.
458
459    // Number of active cycles needed by an auto-refresh.
460    int64_t ref_act_cycles = t.RFC - t.RP;
461
462    if (sref_duration >= ref_act_cycles) {
463      /*
464       * Self-refresh Exit Context 2A (tSREF < tRFC && tSREF >= tRFC - tRP):
465       * The duration of self-refresh is equal or greater than the number
466       * of active cycles needed by the initial auto-refresh.
467       *
468       *
469       *  SREN                                           SREX
470       *  |                                                ^         #
471       *  |                                                |         #
472       *  |<------------------ tSREF --------------------->|         #
473       *  |                                                |         #
474       *  |                                  Initial Auto-Refresh    #
475       *  v                                                |         #
476       *  -----------------------------------------------------------#--> t
477       *                                                             #
478       *   <------------------------ tRFC -------------------------->#
479       *   <------------- (tRFC - tRP)--------------><----- tRP ---->#
480       *           |                                 <-----><------->
481       *           v                                  |         |
482       *     sref_ref_act_cycles                      v         v
483       *                             sref_ref_pre_cycles spup_ref_pre_cycles
484       *
485       *
486       * Summary:
487       * sref_cycles += 0
488       * sref_ref_act_cycles += tRFC - tRP
489       * sref_ref_pre_cycles += tSREF – (tRFC – tRP)
490       * spup_ref_act_cycles += 0
491       * spup_ref_pre_cycles += tRP – sref_ref_pre_cycles
492       *
493       */
494
495      // Number of precharged cycles (zero <= pre_cycles < RP)
496      int64_t pre_cycles = sref_duration - ref_act_cycles - sref_ref_pre_cycles_window;
497
498      sref_ref_act_cycles += ref_act_cycles - sref_ref_act_cycles_window;
499      sref_ref_pre_cycles += pre_cycles;
500
501      // Number of precharged cycles during the self-refresh power-up. It
502      // is at maximum tRP (if pre_cycles is zero).
503      int64_t spup_pre = t.RP - pre_cycles;
504
505      spup_ref_pre_cycles += spup_pre;
506
507      last_pre_cycle       = timestamp + spup_pre;
508
509      if (memSpec.memArchSpec.dll == false) {
510        spup_cycles     += t.XS - spup_pre;
511        latest_pre_cycle = timestamp + zero_guard(t.XS - spup_pre - t.RP, "t.XS - spup_pre - t.RP < 0");
512      } else {
513        spup_cycles     += t.XSDLL - t.RCD - spup_pre;
514        latest_pre_cycle = timestamp + zero_guard(t.XSDLL - t.RCD - spup_pre - t.RP, "t.XSDLL - t.RCD - spup_pre - t.RP");
515      }
516    } else {
517      /*
518       * Self-refresh Exit Context 2B (tSREF < tRFC - tRP):
519       * self-refresh duration is shorter than the number of active cycles
520       * needed by the initial auto-refresh.
521       *
522       *
523       *  SREN                             SREX
524       *  |                                  ^                        #
525       *  |                                  |                        #
526       *  |<-------------- tSREF ----------->|                        #
527       *  |                                  |                        #
528       *  |                       Initial Auto-Refresh                #
529       *  v                                  |                        #
530       *  ------------------------------------------------------------#--> t
531       *                                                              #
532       *   <------------------------ tRFC --------------------------->#
533       *   <-------------- (tRFC - tRP)-------------><------ tRP ---->#
534       *   <--------------------------------><------><--------------->
535       *               |                        |             |
536       *               v                        v             v
537       *     sref_ref_act_cycles    spup_ref_act_cycles spup_ref_pre_cycles
538       *
539       *
540       * Summary:
541       * sref_cycles += 0
542       * sref_ref_act_cycles += tSREF
543       * sref_ref_pre_cycles += 0
544       * spup_ref_act_cycles += (tRFC – tRP) - tSREF
545       * spup_ref_pre_cycles += tRP
546       *
547       */
548
549      sref_ref_act_cycles += sref_duration - sref_ref_act_cycles_window;
550
551      int64_t spup_act = (t.RFC - t.RP) - sref_duration;
552
553      spup_ref_act_cycles += spup_act;
554      spup_ref_pre_cycles += t.RP;
555
556      last_pre_cycle       = timestamp + spup_act + t.RP;
557      if (memSpec.memArchSpec.dll == false) {
558        spup_cycles     += t.XS - spup_act - t.RP;
559        latest_pre_cycle = timestamp + zero_guard(t.XS - spup_act - (2 * t.RP), "t.XS - spup_act - (2 * t.RP) < 0");
560      } else {
561        spup_cycles     += t.XSDLL - t.RCD - spup_act - t.RP;
562        latest_pre_cycle = timestamp + zero_guard(t.XSDLL - t.RCD - spup_act - (2 * t.RP), "t.XSDLL - t.RCD - spup_act - (2 * t.RP) < 0");
563      }
564    }
565  }
566  mem_state = MS_NOT_IN_PD;
567}
568
569
570void CommandAnalysis::handleNopEnd(int64_t timestamp)
571{
572  // May be optionally used at the end of memory trace for better accuracy
573  // Update all counters based on completion of operations.
574  const MemTimingSpec& t = memSpec.memTimingSpec;
575  for (unsigned b = 0; b < num_banks; b++) {
576    if (bank_state[b] == BANK_ACTIVE) {
577      actcyclesBanks[b] += zero_guard(timestamp - first_act_cycle_banks[b], "first_act_cycle is in the future (bank)");
578    }
579  }
580
581  if (nActiveBanks() > 0 && mem_state == MS_NOT_IN_PD) {
582    actcycles += zero_guard(timestamp - first_act_cycle, "first_act_cycle is in the future");
583    idle_act_update(latest_read_cycle, latest_write_cycle,
584                    latest_act_cycle, timestamp);
585  } else if (nActiveBanks() == 0 && mem_state == MS_NOT_IN_PD) {
586    precycles += zero_guard(timestamp - last_pre_cycle, "6 last_pre_cycle is in the future");
587    idle_pre_update(timestamp, latest_pre_cycle);
588  } else if (mem_state == CommandAnalysis::MS_PDN_F_ACT) {
589    f_act_pdcycles += zero_guard(timestamp - pdn_cycle, "pdn_cycle is in the future");
590  } else if (mem_state == CommandAnalysis::MS_PDN_S_ACT) {
591    s_act_pdcycles += zero_guard(timestamp - pdn_cycle, "pdn_cycle is in the future");
592  } else if (mem_state == CommandAnalysis::MS_PDN_F_PRE) {
593    f_pre_pdcycles += zero_guard(timestamp - pdn_cycle, "pdn_cycle is in the future");
594  } else if (mem_state == CommandAnalysis::MS_PDN_S_PRE) {
595    s_pre_pdcycles += zero_guard(timestamp - pdn_cycle, "pdn_cycle is in the future");
596  } else if (mem_state == CommandAnalysis::MS_SREF) {
597    auto rfc_minus_rp = (t.RFC - t.RP);
598
599    if (timestamp > sref_cycle + t.RFC) {
600      if (sref_cycle_window <= sref_cycle + rfc_minus_rp) {
601        sref_ref_act_cycles += rfc_minus_rp - sref_ref_act_cycles_window;
602        sref_ref_act_cycles_window = rfc_minus_rp;
603        sref_cycle_window = sref_cycle + rfc_minus_rp;
604      }
605      if (sref_cycle_window <= sref_cycle + t.RFC) {
606        sref_ref_pre_cycles += t.RP - sref_ref_pre_cycles_window;
607        sref_ref_pre_cycles_window = t.RP;
608        sref_cycle_window = sref_cycle + t.RFC;
609      }
610      sref_cycles += zero_guard(timestamp - sref_cycle_window, "sref_cycle_window is in the future");
611    } else if (timestamp > sref_cycle + rfc_minus_rp) {
612
613      if (sref_cycle_window <= sref_cycle + rfc_minus_rp) {
614        sref_ref_act_cycles += rfc_minus_rp - sref_ref_act_cycles_window;
615        sref_ref_act_cycles_window = rfc_minus_rp;
616        sref_cycle_window = sref_cycle + rfc_minus_rp;
617      }
618      sref_ref_pre_cycles_window += timestamp - sref_cycle_window;
619      sref_ref_pre_cycles += timestamp - sref_cycle_window;
620    } else {
621      sref_ref_act_cycles_window += timestamp - sref_cycle_window;
622      sref_ref_act_cycles += timestamp - sref_cycle_window;
623    }
624  }
625}
626