CommandAnalysis.cc revision 10428
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 * Authors: Karthik Chandrasekar, Matthias Jung, Omar Naji, Sven Goossens
35 *
36 */
37
38#include <fstream>
39#include <algorithm>
40#include <sstream>
41
42#include "CommandAnalysis.h"
43#include "CmdScheduler.h"
44
45using namespace Data;
46using namespace std;
47
48CommandAnalysis::CommandAnalysis()
49{
50}
51
52CommandAnalysis::CommandAnalysis(const int nbrofBanks)
53{
54  // Initializing all counters and variables
55
56  numberofacts        = 0;
57  numberofpres        = 0;
58  numberofreads       = 0;
59  numberofwrites      = 0;
60  numberofrefs        = 0;
61  f_act_pdns          = 0;
62  s_act_pdns          = 0;
63  f_pre_pdns          = 0;
64  s_pre_pdns          = 0;
65  numberofsrefs       = 0;
66
67  pop                 = 0;
68  init                = 0;
69  zero                = 0;
70
71  actcycles           = 0;
72  precycles           = 0;
73  f_act_pdcycles      = 0;
74  s_act_pdcycles      = 0;
75  f_pre_pdcycles      = 0;
76  s_pre_pdcycles      = 0;
77  pup_act_cycles      = 0;
78  pup_pre_cycles      = 0;
79  sref_cycles         = 0;
80  spup_cycles         = 0;
81  sref_ref_act_cycles = 0;
82  sref_ref_pre_cycles = 0;
83  spup_ref_act_cycles = 0;
84  spup_ref_pre_cycles = 0;
85  idlecycles_act      = 0;
86  idlecycles_pre      = 0;
87
88  latest_act_cycle    = -1;
89  latest_pre_cycle    = -1;
90  latest_read_cycle   = -1;
91  latest_write_cycle  = -1;
92  end_read_op         = 0;
93  end_write_op        = 0;
94  end_act_op          = 0;
95
96  first_act_cycle     = 0;
97  last_pre_cycle      = 0;
98
99  bankstate.resize(nbrofBanks, 0);
100  last_states.resize(nbrofBanks);
101  mem_state  = 0;
102
103  sref_cycle = 0;
104  pdn_cycle  = 0;
105
106  cmd_list.clear();
107  full_cmd_list.resize(1, MemCommand::PRE);
108  cached_cmd.clear();
109  activation_cycle.resize(nbrofBanks, 0);
110}
111
112// function to clear all arrays
113void CommandAnalysis::clear()
114{
115  cached_cmd.clear();
116  cmd_list.clear();
117  full_cmd_list.clear();
118  last_states.clear();
119  bankstate.clear();
120}
121
122// Reads through the trace file, identifies the timestamp, command and bank
123// If the issued command includes an auto-precharge, adds an explicit
124// precharge to a cached command list and computes the precharge offset from the
125// issued command timestamp, when the auto-precharge would kick in
126
127void CommandAnalysis::getCommands(const Data::MemorySpecification& memSpec,
128                                  const int nbrofBanks, std::vector<MemCommand>& list, bool lastupdate)
129{
130  for (vector<MemCommand>::const_iterator i = list.begin(); i != list.end(); ++i) {
131    const MemCommand& cmd = *i;
132    cmd_list.push_back(cmd);
133
134    MemCommand::cmds cmdType = cmd.getType();
135    if (cmdType == MemCommand::ACT) {
136      activation_cycle[cmd.getBank()] = cmd.getTimeInt64();
137    } else if (cmdType == MemCommand::RDA || cmdType == MemCommand::WRA) {
138      // Remove auto-precharge flag from command
139      cmd_list.back().setType(cmd.typeWithoutAutoPrechargeFlag());
140
141      // Add the auto precharge to the list of cached_cmds
142      int64_t preTime = max(cmd.getTimeInt64() + cmd.getPrechargeOffset(memSpec, cmdType),
143                           activation_cycle[cmd.getBank()] + memSpec.memTimingSpec.RAS);
144      cached_cmd.push_back(MemCommand(MemCommand::PRE, cmd.getBank(), static_cast<double>(preTime)));
145    }
146  }
147  pop = 0;
148  // Note: the extra pre-cmds at the end of the lists, and the cast to double
149  // of the size vector is probably not desirable.
150  cmd_list.push_back(MemCommand::PRE);
151  cached_cmd.push_back(MemCommand::PRE);
152  analyse_commands(nbrofBanks, memSpec, cmd_list.size()-1,
153                                        cached_cmd.size()-1, lastupdate);
154  cmd_list.clear();
155  cached_cmd.clear();
156} // CommandAnalysis::getCommands
157
158// Checks the auto-precharge cached command list and inserts the explicit
159// precharges with the appropriate timestamp in the original command list
160// (by merging) based on their offset from the issuing command. Calls the
161// evaluate function to analyse this expanded list of commands.
162
163void CommandAnalysis::analyse_commands(const int nbrofBanks,
164                                       Data::MemorySpecification memSpec, int64_t nCommands, int64_t nCached, bool lastupdate)
165{
166  full_cmd_list.resize(1, MemCommand::PRE);
167  unsigned mCommands = 0;
168  unsigned mCached   = 0;
169  for (unsigned i = 0; i < nCommands + nCached + 1; i++) {
170    if (cached_cmd.size() > 1) {
171      if ((cmd_list[mCommands].getTime() > 1) && (init == 0)) {
172        full_cmd_list[i].setType(MemCommand::PREA);
173        init = 1;
174        pop  = 1;
175      } else {
176        init = 1;
177        if ((cached_cmd[mCached].getTime() > 0) && (cmd_list.
178                                                    at(mCommands).getTime() < cached_cmd[mCached].
179                                                    getTime()) && ((cmd_list[mCommands].getTime() > 0) ||
180                                                                   ((cmd_list[mCommands].getTime() == 0) && (cmd_list[mCommands].
181                                                                                                             getType() != MemCommand::PRE)))) {
182          full_cmd_list[i] = cmd_list[mCommands];
183          mCommands++;
184        } else if ((cached_cmd[mCached].getTime() > 0) && (cmd_list[mCommands].
185                                                           getTime() >= cached_cmd[mCached].getTime())) {
186          full_cmd_list[i] = cached_cmd[mCached];
187          mCached++;
188        } else if (cached_cmd[mCached].getTime() == 0) {
189          if ((cmd_list[mCommands].getTime() > 0) || ((cmd_list[mCommands].
190                                                       getTime() == 0) && (cmd_list[mCommands].
191                                                                           getType() != MemCommand::PRE))) {
192            full_cmd_list[i] = cmd_list[mCommands];
193            mCommands++;
194          }
195        } else if (cmd_list[mCommands].getTime() == 0) {
196          full_cmd_list[i] = cached_cmd[mCached];
197          mCached++;
198        }
199      }
200    } else {
201      if ((cmd_list[mCommands].getTime() > 1) && (init == 0)) {
202        full_cmd_list[i].setType(MemCommand::PREA);
203        init = 1;
204        pop  = 1;
205      } else {
206        init = 1;
207        if ((cmd_list[mCommands].getTime() > 0) || ((cmd_list.
208                                                     at(mCommands).getTime() == 0) && (cmd_list[mCommands].
209                                                                                       getType() != MemCommand::PRE))) {
210          full_cmd_list[i] = cmd_list[mCommands];
211          mCommands++;
212        }
213      }
214    }
215    full_cmd_list.resize(full_cmd_list.size() + 1, MemCommand::PRE);
216  }
217
218  full_cmd_list.pop_back();
219  if (pop == 0) {
220    full_cmd_list.pop_back();
221  }
222  if (lastupdate) {
223    full_cmd_list.resize(full_cmd_list.size() + 1, MemCommand::NOP);
224    full_cmd_list[full_cmd_list.size() - 1].setTime(full_cmd_list
225                                                    [full_cmd_list.size() - 2].getTime() + timeToCompletion(memSpec,
226                                                                                                            full_cmd_list[full_cmd_list.size() - 2].getType()) - 1);
227  }
228
229  evaluate(memSpec, full_cmd_list, nbrofBanks);
230} // CommandAnalysis::analyse_commands
231
232// To get the time of completion of the issued command
233// Derived based on JEDEC specifications
234
235int CommandAnalysis::timeToCompletion(const MemorySpecification&
236                                      memSpec, MemCommand::cmds type)
237{
238  int offset = 0;
239  const MemTimingSpec& memTimingSpec     = memSpec.memTimingSpec;
240  const MemArchitectureSpec& memArchSpec = memSpec.memArchSpec;
241
242  if (type == MemCommand::RD) {
243    offset = static_cast<int>(memTimingSpec.RL +
244                              memTimingSpec.DQSCK + 1 + (memArchSpec.burstLength /
245                                                         memArchSpec.dataRate));
246  } else if (type == MemCommand::WR) {
247    offset = static_cast<int>(memTimingSpec.WL +
248                              (memArchSpec.burstLength / memArchSpec.dataRate) +
249                              memTimingSpec.WR);
250  } else if (type == MemCommand::ACT) {
251    offset = static_cast<int>(memTimingSpec.RCD);
252  } else if ((type == MemCommand::PRE) || (type == MemCommand::PREA)) {
253    offset = static_cast<int>(memTimingSpec.RP);
254  }
255  return offset;
256} // CommandAnalysis::timeToCompletion
257
258// Used to analyse a given list of commands and identify command timings
259// and memory state transitions
260void CommandAnalysis::evaluate(const MemorySpecification& memSpec,
261                               vector<MemCommand>& cmd_list, int nbrofBanks)
262{
263  // for each command identify timestamp, type and bank
264  for (unsigned cmd_list_counter = 0; cmd_list_counter < cmd_list.size();
265       cmd_list_counter++) {
266    // For command type
267    int type = cmd_list[cmd_list_counter].getType();
268    // For command bank
269    int bank = cmd_list[cmd_list_counter].getBank();
270    // Command Issue timestamp in clock cycles (cc)
271    int64_t timestamp = cmd_list[cmd_list_counter].getTimeInt64();
272
273    if (type == MemCommand::ACT) {
274      // If command is ACT - update number of acts, bank state of the
275      // target bank, first and latest activation cycle and the memory
276      // state. Update the number of precharged/idle-precharged cycles.
277      numberofacts++;
278      if (bankstate[bank] == 1) {
279        printWarning("Bank is already active!", type, timestamp, bank);
280      }
281      bankstate[bank] = 1;
282      if (mem_state == 0) {
283        first_act_cycle = timestamp;
284        precycles      += max(zero, timestamp - last_pre_cycle);
285        idle_pre_update(memSpec, timestamp, latest_pre_cycle);
286      }
287      latest_act_cycle = timestamp;
288      mem_state++;
289    } else if (type == MemCommand::RD) {
290      // If command is RD - update number of reads and read cycle. Check
291      // for active idle cycles (if any).
292      if (bankstate[bank] == 0) {
293        printWarning("Bank is not active!", type, timestamp, bank);
294      }
295      numberofreads++;
296      idle_act_update(memSpec, latest_read_cycle, latest_write_cycle,
297                      latest_act_cycle, timestamp);
298      latest_read_cycle = timestamp;
299    } else if (type == MemCommand::WR) {
300      // If command is WR - update number of writes and write cycle. Check
301      // for active idle cycles (if any).
302      if (bankstate[bank] == 0) {
303        printWarning("Bank is not active!", type, timestamp, bank);
304      }
305      numberofwrites++;
306      idle_act_update(memSpec, latest_read_cycle, latest_write_cycle,
307                      latest_act_cycle, timestamp);
308      latest_write_cycle = timestamp;
309    } else if (type == MemCommand::REF) {
310      // If command is REF - update number of refreshes, set bank state of
311      // all banks to ACT, set the last PRE cycles at RFC-RP cycles from
312      // timestamp, set the number of active cycles to RFC-RP and check
313      // for active and precharged cycles and idle active and idle
314      // precharged cycles before refresh. Change memory state to 0.
315      printWarningIfActive("One or more banks are active! REF requires all banks to be precharged.", type, timestamp, bank);
316      numberofrefs++;
317      idle_pre_update(memSpec, timestamp, latest_pre_cycle);
318      first_act_cycle  = timestamp;
319      precycles       += max(zero, timestamp - last_pre_cycle);
320      last_pre_cycle   = timestamp + memSpec.memTimingSpec.RFC -
321                         memSpec.memTimingSpec.RP;
322      latest_pre_cycle = last_pre_cycle;
323      actcycles       += memSpec.memTimingSpec.RFC - memSpec.memTimingSpec.RP;
324      mem_state        = 0;
325      for (int j = 0; j < nbrofBanks; j++) {
326        bankstate[j] = 0;
327      }
328    } else if (type == MemCommand::PRE) {
329      // If command is explicit PRE - update number of precharges, bank
330      // state of the target bank and last and latest precharge cycle.
331      // Calculate the number of active cycles if the memory was in the
332      // active state before, but there is a state transition to PRE now.
333      // If not, update the number of precharged cycles and idle cycles.
334      // Update memory state if needed.
335      if (bankstate[bank] == 1) {
336        numberofpres++;
337      }
338      bankstate[bank] = 0;
339
340      if (mem_state == 1) {
341        actcycles     += max(zero, timestamp - first_act_cycle);
342        last_pre_cycle = timestamp;
343        idle_act_update(memSpec, latest_read_cycle, latest_write_cycle,
344                        latest_act_cycle, timestamp);
345      } else if (mem_state == 0) {
346        precycles     += max(zero, timestamp - last_pre_cycle);
347        idle_pre_update(memSpec, timestamp, latest_pre_cycle);
348        last_pre_cycle = timestamp;
349      }
350      latest_pre_cycle = timestamp;
351      if (mem_state > 0) {
352        mem_state--;
353      } else {
354        mem_state = 0;
355      }
356    } else if (type == MemCommand::PREA) {
357      // If command is explicit PREA (precharge all banks) - update
358      // number of precharges by the number of banks, update the bank
359      // state of all banks to PRE and set the precharge cycle.
360      // Calculate the number of active cycles if the memory was in the
361      // active state before, but there is a state transition to PRE now.
362      // If not, update the number of precharged cycles and idle cycles.
363      if (timestamp == 0) {
364        numberofpres += 0;
365      } else {
366        numberofpres += mem_state;
367      }
368
369      if (mem_state > 0) {
370        actcycles += max(zero, timestamp - first_act_cycle);
371        idle_act_update(memSpec, latest_read_cycle, latest_write_cycle,
372                        latest_act_cycle, timestamp);
373      } else if (mem_state == 0) {
374        precycles += max(zero, timestamp - last_pre_cycle);
375        idle_pre_update(memSpec, timestamp, latest_pre_cycle);
376      }
377
378      latest_pre_cycle = timestamp;
379      last_pre_cycle   = timestamp;
380
381      mem_state        = 0;
382
383      for (int j = 0; j < nbrofBanks; j++) {
384        bankstate[j] = 0;
385      }
386    } else if (type == MemCommand::PDN_F_ACT) {
387      // If command is fast-exit active power-down - update number of
388      // power-downs, set the power-down cycle and the memory mode to
389      // fast-exit active power-down. Save states of all the banks from
390      // the cycle before entering active power-down, to be returned to
391      // after powering-up. Update active and active idle cycles.
392      printWarningIfNotActive("All banks are precharged! Incorrect use of Active Power-Down.", type, timestamp, bank);
393      f_act_pdns++;
394      for (int j = 0; j < nbrofBanks; j++) {
395        last_states[j] = bankstate[j];
396      }
397      pdn_cycle  = timestamp;
398      actcycles += max(zero, timestamp - first_act_cycle);
399      idle_act_update(memSpec, latest_read_cycle, latest_write_cycle,
400                      latest_act_cycle, timestamp);
401      mem_state  = CommandAnalysis::MS_PDN_F_ACT;
402    } else if (type == MemCommand::PDN_S_ACT) {
403      // If command is slow-exit active power-down - update number of
404      // power-downs, set the power-down cycle and the memory mode to
405      // slow-exit active power-down. Save states of all the banks from
406      // the cycle before entering active power-down, to be returned to
407      // after powering-up. Update active and active idle cycles.
408      printWarningIfNotActive("All banks are precharged! Incorrect use of Active Power-Down.", type, timestamp, bank);
409      s_act_pdns++;
410      for (int j = 0; j < nbrofBanks; j++) {
411        last_states[j] = bankstate[j];
412      }
413      pdn_cycle  = timestamp;
414      actcycles += max(zero, timestamp - first_act_cycle);
415      idle_act_update(memSpec, latest_read_cycle, latest_write_cycle,
416                      latest_act_cycle, timestamp);
417      mem_state  = CommandAnalysis::MS_PDN_S_ACT;
418    } else if (type == MemCommand::PDN_F_PRE) {
419      // If command is fast-exit precharged power-down - update number of
420      // power-downs, set the power-down cycle and the memory mode to
421      // fast-exit precahrged power-down. Update precharged and precharged
422      // idle cycles.
423      printWarningIfActive("One or more banks are active! Incorrect use of Precharged Power-Down.", type, timestamp, bank);
424      f_pre_pdns++;
425      pdn_cycle  = timestamp;
426      precycles += max(zero, timestamp - last_pre_cycle);
427      idle_pre_update(memSpec, timestamp, latest_pre_cycle);
428      mem_state  = CommandAnalysis::MS_PDN_F_PRE;
429    } else if (type == MemCommand::PDN_S_PRE) {
430      // If command is slow-exit precharged power-down - update number of
431      // power-downs, set the power-down cycle and the memory mode to
432      // slow-exit precahrged power-down. Update precharged and precharged
433      // idle cycles.
434      printWarningIfActive("One or more banks are active! Incorrect use of Precharged Power-Down.", type, timestamp, bank);
435      s_pre_pdns++;
436      pdn_cycle  = timestamp;
437      precycles += max(zero, timestamp - last_pre_cycle);
438      idle_pre_update(memSpec, timestamp, latest_pre_cycle);
439      mem_state  = CommandAnalysis::MS_PDN_S_PRE;
440    } else if (type == MemCommand::PUP_ACT) {
441      // If command is power-up in the active mode - check the power-down
442      // exit-mode employed (fast or slow), update the number of power-down
443      // and power-up cycles and the latest and first act cycle. Also, reset
444      // all the individual bank states to the respective saved states
445      // before entering power-down.
446      if (mem_state == CommandAnalysis::MS_PDN_F_ACT) {
447        f_act_pdcycles  += max(zero, timestamp - pdn_cycle);
448        pup_act_cycles  += memSpec.memTimingSpec.XP;
449        latest_act_cycle = max(timestamp, timestamp +
450                               memSpec.memTimingSpec.XP - memSpec.memTimingSpec.RCD);
451      } else if (mem_state == CommandAnalysis::MS_PDN_S_ACT) {
452        s_act_pdcycles += max(zero, timestamp - pdn_cycle);
453        if (memSpec.memArchSpec.dll == false) {
454          pup_act_cycles  += memSpec.memTimingSpec.XP;
455          latest_act_cycle = max(timestamp, timestamp +
456                                 memSpec.memTimingSpec.XP - memSpec.memTimingSpec.RCD);
457        } else {
458          pup_act_cycles  += memSpec.memTimingSpec.XPDLL -
459                             memSpec.memTimingSpec.RCD;
460          latest_act_cycle = max(timestamp, timestamp +
461                                 memSpec.memTimingSpec.XPDLL -
462                                 (2 * memSpec.memTimingSpec.RCD));
463        }
464      } else if ((mem_state != CommandAnalysis::MS_PDN_S_ACT) || (mem_state !=
465                                                                  CommandAnalysis::MS_PDN_F_ACT)) {
466        cerr << "Incorrect use of Active Power-Up!" << endl;
467      }
468      mem_state = 0;
469      for (int j = 0; j < nbrofBanks; j++) {
470        bankstate[j] = last_states[j];
471        mem_state   += last_states[j];
472      }
473      first_act_cycle = timestamp;
474    } else if (type == MemCommand::PUP_PRE) {
475      // If command is power-up in the precharged mode - check the power-down
476      // exit-mode employed (fast or slow), update the number of power-down
477      // and power-up cycles and the latest and last pre cycle.
478      if (mem_state == CommandAnalysis::MS_PDN_F_PRE) {
479        f_pre_pdcycles  += max(zero, timestamp - pdn_cycle);
480        pup_pre_cycles  += memSpec.memTimingSpec.XP;
481        latest_pre_cycle = max(timestamp, timestamp +
482                               memSpec.memTimingSpec.XP - memSpec.memTimingSpec.RP);
483      } else if (mem_state == CommandAnalysis::MS_PDN_S_PRE) {
484        s_pre_pdcycles += max(zero, timestamp - pdn_cycle);
485        if (memSpec.memArchSpec.dll == false) {
486          pup_pre_cycles  += memSpec.memTimingSpec.XP;
487          latest_pre_cycle = max(timestamp, timestamp +
488                                 memSpec.memTimingSpec.XP - memSpec.memTimingSpec.RP);
489        } else {
490          pup_pre_cycles  += memSpec.memTimingSpec.XPDLL -
491                             memSpec.memTimingSpec.RCD;
492          latest_pre_cycle = max(timestamp, timestamp +
493                                 memSpec.memTimingSpec.XPDLL - memSpec.memTimingSpec.RCD -
494                                 memSpec.memTimingSpec.RP);
495        }
496      } else if ((mem_state != CommandAnalysis::MS_PDN_S_PRE) || (mem_state !=
497                                                                  CommandAnalysis::MS_PDN_F_PRE)) {
498        cerr << "Incorrect use of Precharged Power-Up!" << endl;
499      }
500      mem_state      = 0;
501      last_pre_cycle = timestamp;
502    } else if (type == MemCommand::SREN) {
503      // If command is self-refresh - update number of self-refreshes,
504      // set memory state to SREF, update precharge and idle precharge
505      // cycles and set the self-refresh cycle.
506      printWarningIfActive("One or more banks are active! SREF requires all banks to be precharged.", type, timestamp, bank);
507      numberofsrefs++;
508      sref_cycle = timestamp;
509      precycles += max(zero, timestamp - last_pre_cycle);
510      idle_pre_update(memSpec, timestamp, latest_pre_cycle);
511      mem_state  = CommandAnalysis::MS_SREF;
512    } else if (type == MemCommand::SREX) {
513      // If command is self-refresh exit - update the number of self-refresh
514      // clock cycles, number of active and precharged auto-refresh clock
515      // cycles during self-refresh and self-refresh exit based on the number
516      // of cycles in the self-refresh mode and auto-refresh duration (RFC).
517      // Set the last and latest precharge cycle accordingly and set the
518      // memory state to 0.
519      if (mem_state != CommandAnalysis::MS_SREF) {
520        cerr << "Incorrect use of Self-Refresh Power-Up!" << endl;
521      }
522      if (max(zero, timestamp - sref_cycle) >= memSpec.memTimingSpec.RFC) {
523        sref_cycles         += max(zero, timestamp - sref_cycle
524                                   - memSpec.memTimingSpec.RFC);
525        sref_ref_act_cycles += memSpec.memTimingSpec.RFC -
526                               memSpec.memTimingSpec.RP;
527        sref_ref_pre_cycles += memSpec.memTimingSpec.RP;
528        last_pre_cycle       = timestamp;
529        if (memSpec.memArchSpec.dll == false) {
530          spup_cycles     += memSpec.memTimingSpec.XS;
531          latest_pre_cycle = max(timestamp, timestamp +
532                                 memSpec.memTimingSpec.XS - memSpec.memTimingSpec.RP);
533        } else {
534          spup_cycles     += memSpec.memTimingSpec.XSDLL -
535                             memSpec.memTimingSpec.RCD;
536          latest_pre_cycle = max(timestamp, timestamp +
537                                 memSpec.memTimingSpec.XSDLL - memSpec.memTimingSpec.RCD
538                                 - memSpec.memTimingSpec.RP);
539        }
540      } else {
541        int64_t sref_diff = memSpec.memTimingSpec.RFC - memSpec.memTimingSpec.RP;
542        int64_t sref_pre  = max(zero, timestamp - sref_cycle - sref_diff);
543        int64_t spup_pre  = memSpec.memTimingSpec.RP - sref_pre;
544        int64_t sref_act  = max(zero, timestamp - sref_cycle);
545        int64_t spup_act  = memSpec.memTimingSpec.RFC - sref_act;
546
547        if (max(zero, timestamp - sref_cycle) >= sref_diff) {
548          sref_ref_act_cycles += sref_diff;
549          sref_ref_pre_cycles += sref_pre;
550          spup_ref_pre_cycles += spup_pre;
551          last_pre_cycle       = timestamp + spup_pre;
552          if (memSpec.memArchSpec.dll == false) {
553            spup_cycles     += memSpec.memTimingSpec.XS - spup_pre;
554            latest_pre_cycle = max(timestamp, timestamp +
555                                   memSpec.memTimingSpec.XS - spup_pre -
556                                   memSpec.memTimingSpec.RP);
557          } else {
558            spup_cycles     += memSpec.memTimingSpec.XSDLL -
559                               memSpec.memTimingSpec.RCD - spup_pre;
560            latest_pre_cycle = max(timestamp, timestamp +
561                                   memSpec.memTimingSpec.XSDLL - memSpec.memTimingSpec.RCD -
562                                   spup_pre - memSpec.memTimingSpec.RP);
563          }
564        } else {
565          sref_ref_act_cycles += sref_act;
566          spup_ref_act_cycles += spup_act;
567          spup_ref_pre_cycles += memSpec.memTimingSpec.RP;
568          last_pre_cycle       = timestamp + spup_act + memSpec.memTimingSpec.RP;
569          if (memSpec.memArchSpec.dll == false) {
570            spup_cycles     += memSpec.memTimingSpec.XS - spup_act -
571                               memSpec.memTimingSpec.RP;
572            latest_pre_cycle = max(timestamp, timestamp +
573                                   memSpec.memTimingSpec.XS - spup_act -
574                                   (2 * memSpec.memTimingSpec.RP));
575          } else {
576            spup_cycles     += memSpec.memTimingSpec.XSDLL -
577                               memSpec.memTimingSpec.RCD - spup_act -
578                               memSpec.memTimingSpec.RP;
579            latest_pre_cycle = max(timestamp, timestamp +
580                                   memSpec.memTimingSpec.XSDLL - memSpec.memTimingSpec.RCD -
581                                   spup_act - (2 * memSpec.memTimingSpec.RP));
582          }
583        }
584      }
585      mem_state = 0;
586    } else if ((type == MemCommand::END) || (type == MemCommand::NOP)) {
587      // May be optionally used at the end of memory trace for better accuracy
588      // Update all counters based on completion of operations.
589      if ((mem_state > 0) && (mem_state < 9)) {
590        actcycles += max(zero, timestamp - first_act_cycle);
591        idle_act_update(memSpec, latest_read_cycle, latest_write_cycle,
592                        latest_act_cycle, timestamp);
593      } else if (mem_state == 0) {
594        precycles += max(zero, timestamp - last_pre_cycle);
595        idle_pre_update(memSpec, timestamp, latest_pre_cycle);
596      } else if (mem_state == CommandAnalysis::MS_PDN_F_ACT) {
597        f_act_pdcycles += max(zero, timestamp - pdn_cycle);
598      } else if (mem_state == CommandAnalysis::MS_PDN_S_ACT) {
599        s_act_pdcycles += max(zero, timestamp - pdn_cycle);
600      } else if (mem_state == CommandAnalysis::MS_PDN_F_PRE) {
601        f_pre_pdcycles += max(zero, timestamp - pdn_cycle);
602      } else if (mem_state == CommandAnalysis::MS_PDN_S_PRE) {
603        s_pre_pdcycles += max(zero, timestamp - pdn_cycle);
604      } else if (mem_state == CommandAnalysis::MS_SREF) {
605        sref_cycles += max(zero, timestamp - sref_cycle);
606      }
607    }
608  }
609} // CommandAnalysis::evaluate
610
611// To update idle period information whenever active cycles may be idle
612void CommandAnalysis::idle_act_update(const MemorySpecification& memSpec,
613                                      int64_t latest_read_cycle, int64_t latest_write_cycle,
614                                      int64_t latest_act_cycle, int64_t timestamp)
615{
616  if (latest_read_cycle >= 0) {
617    end_read_op = latest_read_cycle + timeToCompletion(memSpec,
618                                                       MemCommand::RD) - 1;
619  }
620
621  if (latest_write_cycle >= 0) {
622    end_write_op = latest_write_cycle + timeToCompletion(memSpec,
623                                                         MemCommand::WR) - 1;
624  }
625
626  if (latest_act_cycle >= 0) {
627    end_act_op = latest_act_cycle + timeToCompletion(memSpec,
628                                                     MemCommand::ACT) - 1;
629  }
630
631  idlecycles_act += max(zero, timestamp - max(max(end_read_op, end_write_op),
632                                              end_act_op));
633} // CommandAnalysis::idle_act_update
634
635// To update idle period information whenever precharged cycles may be idle
636void CommandAnalysis::idle_pre_update(const MemorySpecification& memSpec,
637                                      int64_t timestamp, int64_t latest_pre_cycle)
638{
639  if (latest_pre_cycle > 0) {
640    idlecycles_pre += max(zero, timestamp - latest_pre_cycle -
641                          memSpec.memTimingSpec.RP);
642  } else if (latest_pre_cycle == 0) {
643    idlecycles_pre += max(zero, timestamp - latest_pre_cycle);
644  }
645}
646
647void CommandAnalysis::printWarningIfActive(const string& warning, int type, int64_t timestamp, int bank)
648{
649  if (mem_state != 0) {
650    printWarning(warning, type, timestamp, bank);
651  }
652}
653
654void CommandAnalysis::printWarningIfNotActive(const string& warning, int type, int64_t timestamp, int bank)
655{
656  if (mem_state == 0) {
657    printWarning(warning, type, timestamp, bank);
658  }
659}
660
661void CommandAnalysis::printWarning(const string& warning, int type, int64_t timestamp, int bank)
662{
663  cerr << "WARNING: " << warning << endl;
664  cerr << "Command: " << type << ", Timestamp: " << timestamp <<
665    ", Bank: " << bank << endl;
666}
667