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
35 *          Matthias Jung
36 *          Omar Naji
37 *          Subash Kannoth
38 *          Éder F. Zulian
39 *          Felipe S. Prado
40 *
41 */
42
43#include "MemoryPowerModel.h"
44
45#include <stdint.h>
46
47#include <cmath>  // For pow
48#include <iostream>  // fmtflags
49#include <algorithm>
50
51using namespace std;
52using namespace Data;
53
54MemoryPowerModel::MemoryPowerModel()
55{
56  total_cycles = 0;
57  energy.total_energy = 0;
58}
59
60// Calculate energy and average power consumption for the given command trace
61
62void MemoryPowerModel::power_calc(const MemorySpecification& memSpec,
63                                  const CommandAnalysis& c,
64                                  int term,
65                                  const MemBankWiseParams& bwPowerParams)
66{
67  const MemTimingSpec& t                 = memSpec.memTimingSpec;
68  const MemArchitectureSpec& memArchSpec = memSpec.memArchSpec;
69  const MemPowerSpec&  mps               = memSpec.memPowerSpec;
70  const int64_t nbrofBanks               = memSpec.memArchSpec.nbrOfBanks;
71
72  energy.act_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
73  energy.pre_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
74  energy.read_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
75  energy.write_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
76  energy.ref_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
77  energy.refb_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
78  energy.act_stdby_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
79  energy.pre_stdby_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
80  energy.idle_energy_act_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
81  energy.idle_energy_pre_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
82  energy.f_act_pd_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
83  energy.f_pre_pd_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
84  energy.s_act_pd_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
85  energy.s_pre_pd_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
86  energy.ref_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
87  energy.sref_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
88  energy.sref_ref_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
89  energy.sref_ref_act_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
90  energy.sref_ref_pre_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
91  energy.spup_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
92  energy.spup_ref_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
93  energy.spup_ref_act_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
94  energy.spup_ref_pre_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
95  energy.pup_act_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
96  energy.pup_pre_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
97  energy.total_energy_banks.assign(static_cast<size_t>(nbrofBanks), 0.0);
98
99  energy.act_energy          = 0.0;
100  energy.pre_energy          = 0.0;
101  energy.read_energy         = 0.0;
102  energy.write_energy        = 0.0;
103  energy.ref_energy          = 0.0;
104  energy.act_stdby_energy    = 0.0;
105  energy.pre_stdby_energy    = 0.0;
106  energy.idle_energy_act     = 0.0;
107  energy.idle_energy_pre     = 0.0;
108  energy.window_energy       = 0.0;
109  energy.f_act_pd_energy     = 0.0;
110  energy.f_pre_pd_energy     = 0.0;
111  energy.s_act_pd_energy     = 0.0;
112  energy.s_pre_pd_energy     = 0.0;
113  energy.sref_energy         = 0.0;
114  energy.sref_ref_energy     = 0.0;
115  energy.sref_ref_act_energy = 0.0;
116  energy.sref_ref_pre_energy = 0.0;
117  energy.spup_energy         = 0.0;
118  energy.spup_ref_energy     = 0.0;
119  energy.spup_ref_act_energy = 0.0;
120  energy.spup_ref_pre_energy = 0.0;
121  energy.pup_act_energy      = 0.0;
122  energy.pup_pre_energy      = 0.0;
123  power.IO_power             = 0.0;
124  power.WR_ODT_power         = 0.0;
125  power.TermRD_power         = 0.0;
126  power.TermWR_power         = 0.0;
127  energy.read_io_energy      = 0.0;
128  energy.write_term_energy   = 0.0;
129  energy.read_oterm_energy   = 0.0;
130  energy.write_oterm_energy  = 0.0;
131  energy.io_term_energy      = 0.0;
132
133  // How long a single burst takes, measured in command-clock cycles.
134  int64_t burstCc = memArchSpec.burstLength / memArchSpec.dataRate;
135
136  // IO and Termination Power measures are included, if required.
137  if (term) {
138    io_term_power(memSpec);
139
140    // memArchSpec.width represents the number of data (dq) pins.
141    // 1 DQS pin is associated with every data byte
142    int64_t dqPlusDqsBits = memArchSpec.width + memArchSpec.width / 8;
143    // 1 DQS and 1 DM pin is associated with every data byte
144    int64_t dqPlusDqsPlusMaskBits = memArchSpec.width + memArchSpec.width / 8 + memArchSpec.width / 8;
145    // Size of one clock period for the data bus.
146    double ddrPeriod = t.clkPeriod / static_cast<double>(memArchSpec.dataRate);
147
148    // Read IO power is consumed by each DQ (data) and DQS (data strobe) pin
149    energy.read_io_energy = calcIoTermEnergy(sum(c.numberofreadsBanks) * memArchSpec.burstLength,
150                                             ddrPeriod,
151                                             power.IO_power,
152                                             dqPlusDqsBits);
153
154    // Write ODT power is consumed by each DQ (data), DQS (data strobe) and DM
155    energy.write_term_energy = calcIoTermEnergy(sum(c.numberofwritesBanks) * memArchSpec.burstLength,
156                                                ddrPeriod,
157                                                power.WR_ODT_power,
158                                                dqPlusDqsPlusMaskBits);
159
160    if (memArchSpec.nbrOfRanks > 1) {
161      // Termination power consumed in the idle rank during reads on the active
162      // rank by each DQ (data) and DQS (data strobe) pin.
163      energy.read_oterm_energy = calcIoTermEnergy(sum(c.numberofreadsBanks) * memArchSpec.burstLength,
164                                                  ddrPeriod,
165                                                  power.TermRD_power,
166                                                  dqPlusDqsBits);
167
168      // Termination power consumed in the idle rank during writes on the active
169      // rank by each DQ (data), DQS (data strobe) and DM (data mask) pin.
170      energy.write_oterm_energy = calcIoTermEnergy(sum(c.numberofwritesBanks) * memArchSpec.burstLength,
171                                                   ddrPeriod,
172                                                   power.TermWR_power,
173                                                   dqPlusDqsPlusMaskBits);
174    }
175
176    // Sum of all IO and termination energy
177    energy.io_term_energy = energy.read_io_energy + energy.write_term_energy
178                            + energy.read_oterm_energy + energy.write_oterm_energy;
179  }
180
181  window_cycles = c.actcycles + c.precycles +
182                 c.f_act_pdcycles + c.f_pre_pdcycles +
183                 c.s_act_pdcycles + c.s_pre_pdcycles + c.sref_cycles
184                 + c.sref_ref_act_cycles + c.sref_ref_pre_cycles +
185                 c.spup_ref_act_cycles + c.spup_ref_pre_cycles;
186
187  EnergyDomain vdd0Domain(mps.vdd, t.clkPeriod);
188
189  energy.act_energy       = vdd0Domain.calcTivEnergy(sum(c.numberofactsBanks) * t.RAS          , mps.idd0 - mps.idd3n);
190  energy.pre_energy       = vdd0Domain.calcTivEnergy(sum(c.numberofpresBanks) * (t.RC - t.RAS) , mps.idd0 - mps.idd2n);
191  energy.read_energy      = vdd0Domain.calcTivEnergy(sum(c.numberofreadsBanks) * burstCc        , mps.idd4r - mps.idd3n);
192  energy.write_energy     = vdd0Domain.calcTivEnergy(sum(c.numberofwritesBanks) * burstCc        , mps.idd4w - mps.idd3n);
193  energy.ref_energy       = vdd0Domain.calcTivEnergy(c.numberofrefs   * t.RFC          , mps.idd5 - mps.idd3n);
194  energy.pre_stdby_energy = vdd0Domain.calcTivEnergy(c.precycles, mps.idd2n);
195  energy.act_stdby_energy = vdd0Domain.calcTivEnergy(c.actcycles, mps.idd3n);
196
197  // Using the number of cycles that at least one bank is active here
198  // But the current iddrho is less than idd3n
199  double iddrho = (static_cast<double>(bwPowerParams.bwPowerFactRho) / 100.0) * (mps.idd3n - mps.idd2n) + mps.idd2n;
200  double esharedActStdby = vdd0Domain.calcTivEnergy(c.actcycles, iddrho);
201  // Fixed componenent for PASR
202  double iddsigma = (static_cast<double>(bwPowerParams.bwPowerFactSigma) / 100.0) * mps.idd6;
203  double esharedPASR = vdd0Domain.calcTivEnergy(c.sref_cycles, iddsigma);
204  // ione is Active background current for a single bank. When a single bank is Active
205  //,all the other remainig (B-1) banks will consume  a current of iddrho (based on factor Rho)
206  // So to derrive ione we add (B-1)*iddrho to the idd3n and distribute it to each banks.
207  double ione = (mps.idd3n + (iddrho * (static_cast<double>(nbrofBanks - 1)))) / (static_cast<double>(nbrofBanks));
208  // If memory specification does not provide  bank wise refresh current,
209  // approximate it to single bank background current removed from
210  // single bank active current
211  double idd5Blocal = (mps.idd5B == 0.0) ? (mps.idd0 - ione) :(mps.idd5B);
212  // if memory specification does not provide the REFB timing approximate it
213  // to time of ACT + PRE
214  int64_t tRefBlocal = (t.REFB == 0) ? (t.RAS + t.RP) : (t.REFB);
215
216  //Distribution of energy componets to each banks
217  for (unsigned i = 0; i < nbrofBanks; i++) {
218    energy.act_energy_banks[i] = vdd0Domain.calcTivEnergy(c.numberofactsBanks[i] * t.RAS, mps.idd0 - ione);
219    energy.pre_energy_banks[i] = vdd0Domain.calcTivEnergy(c.numberofpresBanks[i] * (t.RP), mps.idd0 - ione);
220    energy.read_energy_banks[i] = vdd0Domain.calcTivEnergy(c.numberofreadsBanks[i] * burstCc, mps.idd4r - mps.idd3n);
221    energy.write_energy_banks[i] = vdd0Domain.calcTivEnergy(c.numberofwritesBanks[i] * burstCc, mps.idd4w - mps.idd3n);
222    energy.ref_energy_banks[i] = vdd0Domain.calcTivEnergy(c.numberofrefs * t.RFC, mps.idd5 - mps.idd3n) / static_cast<double>(nbrofBanks);
223    energy.refb_energy_banks[i] = vdd0Domain.calcTivEnergy(c.numberofrefbBanks[i] * tRefBlocal, idd5Blocal);
224    energy.pre_stdby_energy_banks[i] = vdd0Domain.calcTivEnergy(c.precycles, mps.idd2n) / static_cast<double>(nbrofBanks);
225    energy.act_stdby_energy_banks[i] = vdd0Domain.calcTivEnergy(c.actcyclesBanks[i], (mps.idd3n - iddrho) / static_cast<double>(nbrofBanks))
226                                        + esharedActStdby / static_cast<double>(nbrofBanks);
227    energy.idle_energy_act_banks[i] = vdd0Domain.calcTivEnergy(c.idlecycles_act, mps.idd3n) / static_cast<double>(nbrofBanks);
228    energy.idle_energy_pre_banks[i] = vdd0Domain.calcTivEnergy(c.idlecycles_pre, mps.idd2n) / static_cast<double>(nbrofBanks);
229    energy.f_act_pd_energy_banks[i] = vdd0Domain.calcTivEnergy(c.f_act_pdcycles, mps.idd3p1) / static_cast<double>(nbrofBanks);
230    energy.f_pre_pd_energy_banks[i] = vdd0Domain.calcTivEnergy(c.f_pre_pdcycles, mps.idd2p1) / static_cast<double>(nbrofBanks);
231    energy.s_act_pd_energy_banks[i] = vdd0Domain.calcTivEnergy(c.s_act_pdcycles, mps.idd3p0) / static_cast<double>(nbrofBanks);
232    energy.s_pre_pd_energy_banks[i] = vdd0Domain.calcTivEnergy(c.s_pre_pdcycles, mps.idd2p0) / static_cast<double>(nbrofBanks);
233
234    energy.sref_energy_banks[i] = engy_sref_banks(mps.idd6, mps.idd3n,
235                                            mps.idd5, mps.vdd,
236                                            static_cast<double>(c.sref_cycles), static_cast<double>(c.sref_ref_act_cycles),
237                                            static_cast<double>(c.sref_ref_pre_cycles), static_cast<double>(c.spup_ref_act_cycles),
238                                            static_cast<double>(c.spup_ref_pre_cycles), t.clkPeriod,esharedPASR,bwPowerParams,i,nbrofBanks
239                                            );
240    energy.sref_ref_act_energy_banks[i] = vdd0Domain.calcTivEnergy(c.sref_ref_act_cycles, mps.idd3p0) / static_cast<double>(nbrofBanks);
241    energy.sref_ref_pre_energy_banks[i] = vdd0Domain.calcTivEnergy(c.sref_ref_pre_cycles, mps.idd2p0) / static_cast<double>(nbrofBanks);
242    energy.sref_ref_energy_banks[i] = energy.sref_ref_act_energy_banks[i] + energy.sref_ref_pre_energy_banks[i] ;//
243
244    energy.spup_energy_banks[i] = vdd0Domain.calcTivEnergy(c.spup_cycles, mps.idd2n) / static_cast<double>(nbrofBanks);
245    energy.spup_ref_act_energy_banks[i] = vdd0Domain.calcTivEnergy(c.spup_ref_act_cycles, mps.idd3n) / static_cast<double>(nbrofBanks);//
246    energy.spup_ref_pre_energy_banks[i] = vdd0Domain.calcTivEnergy(c.spup_ref_pre_cycles, mps.idd2n) / static_cast<double>(nbrofBanks);
247    energy.spup_ref_energy_banks[i] = ( energy.spup_ref_act_energy + energy.spup_ref_pre_energy ) / static_cast<double>(nbrofBanks);
248    energy.pup_act_energy_banks[i] = vdd0Domain.calcTivEnergy(c.pup_act_cycles, mps.idd3n) / static_cast<double>(nbrofBanks);
249    energy.pup_pre_energy_banks[i] = vdd0Domain.calcTivEnergy(c.pup_pre_cycles, mps.idd2n) / static_cast<double>(nbrofBanks);
250  }
251
252  // Idle energy in the active standby clock cycles
253  energy.idle_energy_act  = vdd0Domain.calcTivEnergy(c.idlecycles_act, mps.idd3n);
254  // Idle energy in the precharge standby clock cycles
255  energy.idle_energy_pre  = vdd0Domain.calcTivEnergy(c.idlecycles_pre, mps.idd2n);
256  // fast-exit active power-down cycles energy
257  energy.f_act_pd_energy  = vdd0Domain.calcTivEnergy(c.f_act_pdcycles, mps.idd3p1);
258  // fast-exit precharged power-down cycles energy
259  energy.f_pre_pd_energy  = vdd0Domain.calcTivEnergy(c.f_pre_pdcycles, mps.idd2p1);
260  // slow-exit active power-down cycles energy
261  energy.s_act_pd_energy  = vdd0Domain.calcTivEnergy(c.s_act_pdcycles, mps.idd3p0);
262  // slow-exit precharged power-down cycles energy
263  energy.s_pre_pd_energy  = vdd0Domain.calcTivEnergy(c.s_pre_pdcycles, mps.idd2p0);
264
265  // self-refresh cycles energy including a refresh per self-refresh entry
266  energy.sref_energy = engy_sref(mps.idd6, mps.idd3n,
267                                 mps.idd5, mps.vdd,
268                                 static_cast<double>(c.sref_cycles), static_cast<double>(c.sref_ref_act_cycles),
269                                 static_cast<double>(c.sref_ref_pre_cycles), static_cast<double>(c.spup_ref_act_cycles),
270                                 static_cast<double>(c.spup_ref_pre_cycles), t.clkPeriod);
271
272  // background energy during active auto-refresh cycles in self-refresh
273  energy.sref_ref_act_energy = vdd0Domain.calcTivEnergy(c.sref_ref_act_cycles, mps.idd3p0);
274  // background energy during precharged auto-refresh cycles in self-refresh
275  energy.sref_ref_pre_energy = vdd0Domain.calcTivEnergy(c.sref_ref_pre_cycles, mps.idd2p0);
276  // background energy during active auto-refresh cycles in self-refresh exit
277  energy.spup_ref_act_energy = vdd0Domain.calcTivEnergy(c.spup_ref_act_cycles, mps.idd3n);
278  // background energy during precharged auto-refresh cycles in self-refresh exit
279  energy.spup_ref_pre_energy = vdd0Domain.calcTivEnergy(c.spup_ref_pre_cycles, mps.idd2n);
280  // self-refresh power-up cycles energy -- included
281  energy.spup_energy         = vdd0Domain.calcTivEnergy(c.spup_cycles, mps.idd2n);
282  // active power-up cycles energy - same as active standby -- included
283  energy.pup_act_energy      = vdd0Domain.calcTivEnergy(c.pup_act_cycles, mps.idd3n);
284  // precharged power-up cycles energy - same as precharged standby -- included
285  energy.pup_pre_energy      = vdd0Domain.calcTivEnergy(c.pup_pre_cycles, mps.idd2n);
286
287  // similar equations as before to support multiple voltage domains in LPDDR2
288  // and WIDEIO memories
289  if (memArchSpec.twoVoltageDomains) {
290    EnergyDomain vdd2Domain(mps.vdd2, t.clkPeriod);
291
292    energy.act_energy       += vdd2Domain.calcTivEnergy(sum(c.numberofactsBanks) * t.RAS          , mps.idd02 - mps.idd3n2);
293    energy.pre_energy       += vdd2Domain.calcTivEnergy(sum(c.numberofpresBanks) * (t.RC - t.RAS) , mps.idd02 - mps.idd2n2);
294    energy.read_energy      += vdd2Domain.calcTivEnergy(sum(c.numberofreadsBanks) * burstCc        , mps.idd4r2 - mps.idd3n2);
295    energy.write_energy     += vdd2Domain.calcTivEnergy(sum(c.numberofwritesBanks) * burstCc        , mps.idd4w2 - mps.idd3n2);
296    energy.ref_energy       += vdd2Domain.calcTivEnergy(c.numberofrefs   * t.RFC          , mps.idd52 - mps.idd3n2);
297    energy.pre_stdby_energy += vdd2Domain.calcTivEnergy(c.precycles, mps.idd2n2);
298    energy.act_stdby_energy += vdd2Domain.calcTivEnergy(c.actcycles, mps.idd3n2);
299
300    // Idle energy in the active standby clock cycles
301    energy.idle_energy_act  += vdd2Domain.calcTivEnergy(c.idlecycles_act, mps.idd3n2);
302    // Idle energy in the precharge standby clock cycles
303    energy.idle_energy_pre  += vdd2Domain.calcTivEnergy(c.idlecycles_pre, mps.idd2n2);
304    // fast-exit active power-down cycles energy
305    energy.f_act_pd_energy  += vdd2Domain.calcTivEnergy(c.f_act_pdcycles, mps.idd3p12);
306    // fast-exit precharged power-down cycles energy
307    energy.f_pre_pd_energy  += vdd2Domain.calcTivEnergy(c.f_pre_pdcycles, mps.idd2p12);
308    // slow-exit active power-down cycles energy
309    energy.s_act_pd_energy  += vdd2Domain.calcTivEnergy(c.s_act_pdcycles, mps.idd3p02);
310    // slow-exit precharged power-down cycles energy
311    energy.s_pre_pd_energy  += vdd2Domain.calcTivEnergy(c.s_pre_pdcycles, mps.idd2p02);
312
313    energy.sref_energy      += engy_sref(mps.idd62, mps.idd3n2,
314                                         mps.idd52, mps.vdd2,
315                                         static_cast<double>(c.sref_cycles), static_cast<double>(c.sref_ref_act_cycles),
316                                         static_cast<double>(c.sref_ref_pre_cycles), static_cast<double>(c.spup_ref_act_cycles),
317                                         static_cast<double>(c.spup_ref_pre_cycles), t.clkPeriod);
318
319    // background energy during active auto-refresh cycles in self-refresh
320    energy.sref_ref_act_energy += vdd2Domain.calcTivEnergy(c.sref_ref_act_cycles, mps.idd3p02);
321    // background energy during precharged auto-refresh cycles in self-refresh
322    energy.sref_ref_pre_energy += vdd2Domain.calcTivEnergy(c.sref_ref_pre_cycles, mps.idd2p02);
323    // background energy during active auto-refresh cycles in self-refresh exit
324    energy.spup_ref_act_energy += vdd2Domain.calcTivEnergy(c.spup_ref_act_cycles, mps.idd3n2);
325    // background energy during precharged auto-refresh cycles in self-refresh exit
326    energy.spup_ref_pre_energy += vdd2Domain.calcTivEnergy(c.spup_ref_pre_cycles, mps.idd2n2);
327    // self-refresh power-up cycles energy -- included
328    energy.spup_energy         += vdd2Domain.calcTivEnergy(c.spup_cycles, mps.idd2n2);
329    // active power-up cycles energy - same as active standby -- included
330    energy.pup_act_energy      += vdd2Domain.calcTivEnergy(c.pup_act_cycles, mps.idd3n2);
331    // precharged power-up cycles energy - same as precharged standby -- included
332    energy.pup_pre_energy      += vdd2Domain.calcTivEnergy(c.pup_pre_cycles, mps.idd2n2);
333  }
334
335  // auto-refresh energy during self-refresh cycles
336  energy.sref_ref_energy = energy.sref_ref_act_energy + energy.sref_ref_pre_energy;
337
338  // auto-refresh energy during self-refresh exit cycles
339  energy.spup_ref_energy = energy.spup_ref_act_energy + energy.spup_ref_pre_energy;
340
341  // adding all energy components for the active rank and all background and idle
342  // energy components for both ranks (in a dual-rank system)
343
344  if (bwPowerParams.bwMode) {
345        // Calculate total energy per bank.
346        for (unsigned i = 0; i < nbrofBanks; i++) {
347            energy.total_energy_banks[i] = energy.act_energy_banks[i] + energy.pre_energy_banks[i] + energy.read_energy_banks[i]
348                                            + energy.ref_energy_banks[i] + energy.write_energy_banks[i] + energy.refb_energy_banks[i]
349                                            + static_cast<double>(memArchSpec.nbrOfRanks) * energy.act_stdby_energy_banks[i]
350                                            + energy.pre_stdby_energy_banks[i] + energy.f_pre_pd_energy_banks[i] + energy.s_act_pd_energy_banks[i]
351                                            + energy.s_pre_pd_energy_banks[i]+ energy.sref_ref_energy_banks[i] + energy.spup_ref_energy_banks[i];
352      }
353      // Calculate total energy for all banks.
354      energy.window_energy = sum(energy.total_energy_banks) + energy.io_term_energy;
355
356  } else {
357    energy.window_energy = energy.act_energy + energy.pre_energy + energy.read_energy + energy.write_energy
358                          + energy.ref_energy + energy.io_term_energy + sum(energy.refb_energy_banks)
359                          + static_cast<double>(memArchSpec.nbrOfRanks) * (energy.act_stdby_energy
360                          + energy.pre_stdby_energy + energy.sref_energy + energy.f_act_pd_energy
361                          + energy.f_pre_pd_energy + energy.s_act_pd_energy + energy.s_pre_pd_energy
362                          + energy.sref_ref_energy + energy.spup_ref_energy);
363  }
364
365  power.window_average_power = energy.window_energy / (static_cast<double>(window_cycles) * t.clkPeriod);
366
367  total_cycles += window_cycles;
368
369  energy.total_energy += energy.window_energy;
370
371  // Calculate the average power consumption
372  power.average_power = energy.total_energy / (static_cast<double>(total_cycles) * t.clkPeriod);
373} // MemoryPowerModel::power_calc
374
375void MemoryPowerModel::power_print(const MemorySpecification& memSpec, int term, const CommandAnalysis& c, bool bankwiseMode) const
376{
377  const MemTimingSpec& memTimingSpec     = memSpec.memTimingSpec;
378  const MemArchitectureSpec& memArchSpec = memSpec.memArchSpec;
379  const uint64_t nRanks = static_cast<uint64_t>(memArchSpec.nbrOfRanks);
380  const char eUnit[] = " pJ";
381  const int64_t nbrofBanks = memSpec.memArchSpec.nbrOfBanks;
382  double nRanksDouble = static_cast<double>(nRanks);
383
384  ios_base::fmtflags flags = cout.flags();
385  streamsize precision = cout.precision();
386  cout.precision(0);
387
388  if (bankwiseMode) {
389    cout << endl << "* Bankwise Details:";
390    for (unsigned i = 0; i < nbrofBanks; i++) {
391      cout << endl << "## @ Bank " << i << fixed
392        << endl << "  #ACT commands: " << c.numberofactsBanks[i]
393        << endl << "  #RD + #RDA commands: " << c.numberofreadsBanks[i]
394        << endl << "  #WR + #WRA commands: " << c.numberofwritesBanks[i]
395        << endl << "  #PRE (+ PREA) commands: " << c.numberofpresBanks[i];
396    }
397    cout << endl;
398  }
399
400  cout << endl << "* Trace Details:" << fixed << endl
401       << endl << "#ACT commands: "                 << sum(c.numberofactsBanks)
402       << endl << "#RD + #RDA commands: "           << sum(c.numberofreadsBanks)
403       << endl << "#WR + #WRA commands: "           << sum(c.numberofwritesBanks)
404  /* #PRE commands (precharge all counts a number of #PRE commands equal to the number of active banks) */
405       << endl << "#PRE (+ PREA) commands: "        << sum(c.numberofpresBanks)
406       << endl << "#REF commands: "                 << c.numberofrefs
407       << endl << "#REFB commands: "                << sum(c.numberofrefbBanks)
408       << endl << "#Active Cycles: "                << c.actcycles
409       << endl << "  #Active Idle Cycles: "         << c.idlecycles_act
410       << endl << "  #Active Power-Up Cycles: "     << c.pup_act_cycles
411       << endl << "    #Auto-Refresh Active cycles during Self-Refresh Power-Up: " << c.spup_ref_act_cycles
412       << endl << "#Precharged Cycles: "            << c.precycles
413       << endl << "  #Precharged Idle Cycles: "     << c.idlecycles_pre
414       << endl << "  #Precharged Power-Up Cycles: " << c.pup_pre_cycles
415       << endl << "    #Auto-Refresh Precharged cycles during Self-Refresh Power-Up: " << c.spup_ref_pre_cycles
416       << endl << "  #Self-Refresh Power-Up Cycles: "                          << c.spup_cycles
417       << endl << "Total Idle Cycles (Active + Precharged): "                  << c.idlecycles_act + c.idlecycles_pre
418       << endl << "#Power-Downs: "                                             << c.f_act_pdns +  c.s_act_pdns + c.f_pre_pdns + c.s_pre_pdns
419       << endl << "  #Active Fast-exit Power-Downs: "                          << c.f_act_pdns
420       << endl << "  #Active Slow-exit Power-Downs: "                          << c.s_act_pdns
421       << endl << "  #Precharged Fast-exit Power-Downs: "                      << c.f_pre_pdns
422       << endl << "  #Precharged Slow-exit Power-Downs: "                      << c.s_pre_pdns
423       << endl << "#Power-Down Cycles: "                                       << c.f_act_pdcycles + c.s_act_pdcycles + c.f_pre_pdcycles + c.s_pre_pdcycles
424       << endl << "  #Active Fast-exit Power-Down Cycles: "                    << c.f_act_pdcycles
425       << endl << "  #Active Slow-exit Power-Down Cycles: "                    << c.s_act_pdcycles
426       << endl << "    #Auto-Refresh Active cycles during Self-Refresh: "      << c.sref_ref_act_cycles
427       << endl << "  #Precharged Fast-exit Power-Down Cycles: "                << c.f_pre_pdcycles
428       << endl << "  #Precharged Slow-exit Power-Down Cycles: "                << c.s_pre_pdcycles
429       << endl << "    #Auto-Refresh Precharged cycles during Self-Refresh: "  << c.sref_ref_pre_cycles
430       << endl << "#Auto-Refresh Cycles: "                                     << c.numberofrefs * memTimingSpec.RFC
431       << endl << "#Self-Refreshes: "                                          << c.numberofsrefs
432       << endl << "#Self-Refresh Cycles: "                                     << c.sref_cycles
433       << endl << "----------------------------------------"
434       << endl << "Total Trace Length (clock cycles): " << total_cycles
435       << endl << "----------------------------------------" << endl;
436
437  if (bankwiseMode) {
438    cout << endl << "* Bankwise Details:";
439    for (unsigned i = 0; i < nbrofBanks; i++) {
440      cout << endl << "## @ Bank " << i << fixed
441        << endl << "  ACT Cmd Energy: " << energy.act_energy_banks[i] << eUnit
442        << endl << "  PRE Cmd Energy: " << energy.pre_energy_banks[i] << eUnit
443        << endl << "  RD Cmd Energy: " << energy.read_energy_banks[i] << eUnit
444        << endl << "  WR Cmd Energy: " << energy.write_energy_banks[i] << eUnit
445        << endl << "  Auto-Refresh Energy: " << energy.ref_energy_banks[i] << eUnit
446        << endl << "  Bankwise-Refresh Energy: " << energy.refb_energy_banks[i] << eUnit
447        << endl << "  ACT Stdby Energy: " << nRanksDouble * energy.act_stdby_energy_banks[i] << eUnit
448        << endl << "  PRE Stdby Energy: " << nRanksDouble * energy.pre_stdby_energy_banks[i] << eUnit
449        << endl << "  Active Idle Energy: "<< nRanksDouble * energy.idle_energy_act_banks[i] << eUnit
450        << endl << "  Precharge Idle Energy: "<< nRanksDouble * energy.idle_energy_pre_banks[i] << eUnit
451        << endl << "  Fast-Exit Active Power-Down Energy: "<< nRanksDouble * energy.f_act_pd_energy_banks[i] << eUnit
452        << endl << "  Fast-Exit Precharged Power-Down Energy: "<< nRanksDouble * energy.f_pre_pd_energy_banks[i] << eUnit
453        << endl << "  Slow-Exit Active Power-Down Energy: "<< nRanksDouble * energy.s_act_pd_energy_banks[i] << eUnit
454        << endl << "  Slow-Exit Precharged Power-Down Energy: "<< nRanksDouble * energy.s_pre_pd_energy_banks[i] << eUnit
455        << endl << "  Self-Refresh Energy: "<< nRanksDouble * energy.sref_energy_banks[i] << eUnit
456        << endl << "  Slow-Exit Active Power-Down Energy during Auto-Refresh cycles in Self-Refresh: "<< nRanksDouble * energy.sref_ref_act_energy_banks[i] << eUnit
457        << endl << "  Slow-Exit Precharged Power-Down Energy during Auto-Refresh cycles in Self-Refresh: " << nRanksDouble * energy.sref_ref_pre_energy_banks[i] << eUnit
458        << endl << "  Self-Refresh Power-Up Energy: "<< nRanksDouble * energy.spup_energy_banks[i] << eUnit
459        << endl << "  Active Stdby Energy during Auto-Refresh cycles in Self-Refresh Power-Up: "<< nRanksDouble * energy.spup_ref_act_energy_banks[i] << eUnit
460        << endl << "  Precharge Stdby Energy during Auto-Refresh cycles in Self-Refresh Power-Up: "<< nRanksDouble * energy.spup_ref_pre_energy_banks[i] << eUnit
461        << endl << "  Active Power-Up Energy: "<< nRanksDouble * energy.pup_act_energy_banks[i] << eUnit
462        << endl << "  Precharged Power-Up Energy: "<< nRanksDouble * energy.pup_pre_energy_banks[i] << eUnit
463        << endl << "  Total Energy: "<< energy.total_energy_banks[i] << eUnit
464        << endl;
465    }
466    cout << endl;
467  }
468
469  cout.precision(2);
470  cout << endl << "* Trace Power and Energy Estimates:" << endl
471       << endl << "ACT Cmd Energy: " << energy.act_energy   << eUnit
472       << endl << "PRE Cmd Energy: " << energy.pre_energy   << eUnit
473       << endl << "RD Cmd Energy: "  << energy.read_energy  << eUnit
474       << endl << "WR Cmd Energy: "  << energy.write_energy << eUnit;
475
476  if (term) {
477    cout << endl << "RD I/O Energy: " << energy.read_io_energy << eUnit << endl;
478    // No Termination for LPDDR/2/3 and DDR memories
479    if (memSpec.memArchSpec.termination) {
480      cout << "WR Termination Energy: " << energy.write_term_energy << eUnit << endl;
481    }
482
483    if (nRanks > 1 && memSpec.memArchSpec.termination) {
484      cout <<         "RD Termination Energy (Idle rank): " << energy.read_oterm_energy << eUnit
485           << endl << "WR Termination Energy (Idle rank): " << energy.write_oterm_energy << eUnit << endl;
486    }
487  }
488
489  cout <<         "ACT Stdby Energy: "                                                                      << nRanksDouble * energy.act_stdby_energy << eUnit
490       << endl << "  Active Idle Energy: "                                                                  << nRanksDouble * energy.idle_energy_act << eUnit
491       << endl << "  Active Power-Up Energy: "                                                              << nRanksDouble * energy.pup_act_energy << eUnit
492       << endl << "    Active Stdby Energy during Auto-Refresh cycles in Self-Refresh Power-Up: "           << nRanksDouble * energy.spup_ref_act_energy << eUnit
493       << endl << "PRE Stdby Energy: "                                                                      << nRanksDouble * energy.pre_stdby_energy << eUnit
494       << endl << "  Precharge Idle Energy: "                                                               << nRanksDouble * energy.idle_energy_pre << eUnit
495       << endl << "  Precharged Power-Up Energy: "                                                          << nRanksDouble * energy.pup_pre_energy << eUnit
496       << endl << "    Precharge Stdby Energy during Auto-Refresh cycles in Self-Refresh Power-Up: "        << nRanksDouble * energy.spup_ref_pre_energy << eUnit
497       << endl << "  Self-Refresh Power-Up Energy: "                                                        << nRanksDouble * energy.spup_energy << eUnit
498       << endl << "Total Idle Energy (Active + Precharged): "                                               << nRanksDouble * (energy.idle_energy_act + energy.idle_energy_pre) << eUnit
499       << endl << "Total Power-Down Energy: "                                                               << nRanksDouble * (energy.f_act_pd_energy + energy.f_pre_pd_energy + energy.s_act_pd_energy + energy.s_pre_pd_energy) << eUnit
500       << endl << "  Fast-Exit Active Power-Down Energy: "                                                  << nRanksDouble * energy.f_act_pd_energy << eUnit
501       << endl << "  Slow-Exit Active Power-Down Energy: "                                                  << nRanksDouble * energy.s_act_pd_energy << eUnit
502       << endl << "    Slow-Exit Active Power-Down Energy during Auto-Refresh cycles in Self-Refresh: "     << nRanksDouble * energy.sref_ref_act_energy << eUnit
503       << endl << "  Fast-Exit Precharged Power-Down Energy: "                                              << nRanksDouble * energy.f_pre_pd_energy << eUnit
504       << endl << "  Slow-Exit Precharged Power-Down Energy: "                                              << nRanksDouble * energy.s_pre_pd_energy << eUnit
505       << endl << "    Slow-Exit Precharged Power-Down Energy during Auto-Refresh cycles in Self-Refresh: " << nRanksDouble * energy.sref_ref_pre_energy << eUnit
506       << endl << "Auto-Refresh Energy: "                                                                   << energy.ref_energy << eUnit
507       << endl << "Bankwise-Refresh Energy: "                                                               << sum(energy.refb_energy_banks) << eUnit
508       << endl << "Self-Refresh Energy: "                                                                   << nRanksDouble * energy.sref_energy << eUnit
509       << endl << "----------------------------------------"
510       << endl << "Total Trace Energy: "                                                                    << energy.total_energy << eUnit
511       << endl << "Average Power: "                                                                         << power.average_power << " mW"
512       << endl << "----------------------------------------" << endl;
513
514  cout.flags(flags);
515  cout.precision(precision);
516} // MemoryPowerModel::power_print
517
518// Self-refresh active energy estimation (not including background energy)
519double MemoryPowerModel::engy_sref(double idd6, double idd3n, double idd5,
520                                   double vdd, double sref_cycles, double sref_ref_act_cycles,
521                                   double sref_ref_pre_cycles, double spup_ref_act_cycles,
522                                   double spup_ref_pre_cycles, double clk)
523{
524  double sref_energy;
525
526  sref_energy = ((idd6 * sref_cycles) + ((idd5 - idd3n) * (sref_ref_act_cycles
527                                                           + spup_ref_act_cycles + sref_ref_pre_cycles + spup_ref_pre_cycles)))
528                * vdd * clk;
529  return sref_energy;
530}
531
532// Self-refresh active energy estimation per banks
533double MemoryPowerModel::engy_sref_banks(double idd6, double idd3n, double idd5,
534                                   double vdd, double sref_cycles, double sref_ref_act_cycles,
535                                   double sref_ref_pre_cycles, double spup_ref_act_cycles,
536                                   double spup_ref_pre_cycles, double clk,
537                                   double esharedPASR, const MemBankWiseParams& bwPowerParams,
538                                   unsigned bnkIdx, int64_t nbrofBanks)
539{
540    // Bankwise Self-refresh energy
541    double sref_energy_banks;
542    // Dynamic componenents for PASR energy varying based on PASR mode
543    double iddsigmaDynBanks;
544    double pasr_energy_dyn;
545    // This component is distributed among all banks
546    double sref_energy_shared;
547    //Is PASR Active
548    if (bwPowerParams.flgPASR){
549        sref_energy_shared = (((idd5 - idd3n) * (sref_ref_act_cycles
550                                                          + spup_ref_act_cycles + sref_ref_pre_cycles + spup_ref_pre_cycles)) * vdd * clk)
551                                                / static_cast<double>(nbrofBanks);
552        //if the bank is active under current PASR mode
553        if (bwPowerParams.isBankActiveInPasr(bnkIdx)){
554            // Distribute the sref energy to the active banks
555            iddsigmaDynBanks = (static_cast<double>(100 - bwPowerParams.bwPowerFactSigma) / (100.0 * static_cast<double>(nbrofBanks))) * idd6;
556            pasr_energy_dyn = vdd * iddsigmaDynBanks * sref_cycles;
557            // Add the static components
558            sref_energy_banks = sref_energy_shared + pasr_energy_dyn + (esharedPASR /static_cast<double>(nbrofBanks));
559
560        }else{
561            sref_energy_banks = (esharedPASR /static_cast<double>(nbrofBanks));
562        }
563    }
564    //When PASR is not active total all the banks are in Self-Refresh. Thus total Self-Refresh energy is distributed across all banks
565    else{
566
567
568            sref_energy_banks = (((idd6 * sref_cycles) + ((idd5 - idd3n) * (sref_ref_act_cycles
569                                                + spup_ref_act_cycles + sref_ref_pre_cycles + spup_ref_pre_cycles)))
570                                                * vdd * clk)
571                                                / static_cast<double>(nbrofBanks);
572    }
573    return sref_energy_banks;
574}
575
576
577// IO and Termination power calculation based on Micron Power Calculators
578// Absolute power measures are obtained from Micron Power Calculator (mentioned in mW)
579void MemoryPowerModel::io_term_power(const MemorySpecification& memSpec)
580{
581  const MemTimingSpec& memTimingSpec     = memSpec.memTimingSpec;
582  const MemArchitectureSpec& memArchSpec = memSpec.memArchSpec;
583  const MemPowerSpec&  memPowerSpec      = memSpec.memPowerSpec;
584
585  power.IO_power     = memPowerSpec.ioPower;    // in mW
586  power.WR_ODT_power = memPowerSpec.wrOdtPower; // in mW
587
588  if (memArchSpec.nbrOfRanks > 1) {
589    power.TermRD_power = memPowerSpec.termRdPower; // in mW
590    power.TermWR_power = memPowerSpec.termWrPower; // in mW
591  }
592
593  if (memPowerSpec.capacitance != 0.0) {
594    // If capacity is given, then IO Power depends on DRAM clock frequency.
595    power.IO_power = memPowerSpec.capacitance * 0.5 * pow(memPowerSpec.vdd2, 2.0) * memTimingSpec.clkMhz * 1000000;
596  }
597} // MemoryPowerModel::io_term_power
598
599
600double MemoryPowerModel::calcIoTermEnergy(int64_t cycles, double period, double power, int64_t numBits) const
601{
602  return static_cast<double>(cycles) * period * power * static_cast<double>(numBits);
603}
604
605// time (t) * current (I) * voltage (V) energy calculation
606double EnergyDomain::calcTivEnergy(int64_t cycles, double current) const
607{
608  return static_cast<double>(cycles) * clkPeriod * current * voltage;
609}
610
611