stats: update stats for mmap() change.
[gem5.git] / ext / drampower / src / CmdScheduler.cc
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 *
36 */
37 #include "CmdScheduler.h"
38
39 #include <cassert>
40 #include <cmath> // For log2
41
42 #include <algorithm> // For max
43
44
45 using namespace std;
46 using namespace Data;
47
48 // Read the traces and get the transaction. Each transaction is executed by
49 // scheduling a number of commands to the memory. Hence, the transactions are
50 // translated into a sequence of commands which will be used for power analysis.
51 void cmdScheduler::transTranslation(MemorySpecification memSpec,
52 ifstream& trans_trace, int grouping, int interleaving, int burst, int powerdown)
53 {
54 commands.open("commands.trace", ifstream::out);
55 MemArchitectureSpec& memArchSpec = memSpec.memArchSpec;
56 nBanks = memArchSpec.nbrOfBanks;
57 nColumns = memArchSpec.nbrOfColumns;
58 burstLength = memArchSpec.burstLength;
59 nbrOfBankGroups = memArchSpec.nbrOfBankGroups;
60
61 BGI = grouping;
62 BI = interleaving;
63 BC = burst;
64 power_down = powerdown;
65
66 schedulingInitialization(memSpec);
67 getTrans(trans_trace, memSpec);
68
69 trans_trace.close();
70 commands.close();
71 ACT.erase(ACT.begin(), ACT.end());
72 PRE.erase(PRE.begin(), PRE.end());
73 RDWR.erase(RDWR.begin(), RDWR.end());
74 cmdScheduling.erase(cmdScheduling.begin(), cmdScheduling.end());
75 cmdList.erase(cmdList.begin(), cmdList.end());
76 transTrace.erase(transTrace.begin(), transTrace.end());
77 } // cmdScheduler::transTranslation
78
79 // initialize the variables and vectors for starting command scheduling.
80 void cmdScheduler::schedulingInitialization(MemorySpecification memSpec)
81 {
82 MemTimingSpec& memTimingSpec = memSpec.memTimingSpec;
83
84 ACT.resize(2 * memSpec.memArchSpec.nbrOfBanks);
85 RDWR.resize(2 * memSpec.memArchSpec.nbrOfBanks);
86 PRE.resize(memSpec.memArchSpec.nbrOfBanks);
87 bankaccess = memSpec.memArchSpec.nbrOfBanks;
88 if (!ACT.empty()) {
89 ACT.erase(ACT.begin(), ACT.end());
90 }
91 if (!PRE.empty()) {
92 PRE.erase(PRE.begin(), PRE.end());
93 }
94 if (!RDWR.empty()) {
95 RDWR.erase(RDWR.begin(), RDWR.end());
96 }
97
98 ///////////////initialization//////////////
99 for (unsigned i = 0; i < memSpec.memArchSpec.nbrOfBanks; i++) {
100 cmd.Type = PRECHARGE;
101 cmd.bank = i;
102 cmd.name = "PRE";
103 if (memSpec.id == "WIDEIO_SDR")
104 cmd.time = 1 - static_cast<double>(memSpec.memTimingSpec.TAW);
105 else
106 cmd.time = 1 - static_cast<double>(memSpec.memTimingSpec.FAW);
107
108 PRE.push_back(cmd);
109
110 cmd.Type = ACTIVATE;
111 cmd.name = "ACT";
112 ACT.push_back(cmd);
113
114 cmd.Type = WRITE;
115 cmd.name = "WRITE";
116 cmd.time = -1;
117 RDWR[i].push_back(cmd);
118 }
119 tREF = memTimingSpec.REFI;
120 transFinish.time = 0;
121 transFinish.bank = 0;
122
123 PreRDWR.bank = -1;
124 PreRDWR.Type = READ;
125 PreRDWR.name = "RD";
126 PreRDWR.time = -1;
127 startTime = 0;
128 } // cmdScheduler::schedulingInitialization
129
130 // transactions are generated according to the information read from the traces.
131 // Then the command scheduling function is triggered to generate commands and
132 // schedule them to the memory according to the timing constraints.
133 void cmdScheduler::getTrans(std::ifstream& trans_trace, MemorySpecification memSpec)
134 {
135 std::string line;
136
137 transTime = 0;
138 unsigned newtranstime;
139 unsigned transAddr;
140 unsigned transType = 1;
141 trans TransItem;
142
143 if (!transTrace.empty()) {
144 transTrace.erase(transTrace.begin(), transTrace.end());
145 }
146
147 while (getline(trans_trace, line)) {
148 istringstream linestream(line);
149 string item;
150 unsigned itemnum = 0;
151 while (getline(linestream, item, ',')) {
152 if (itemnum == 0) {
153 stringstream timestamp(item);
154 timestamp >> newtranstime;
155 transTime = transTime + newtranstime;
156 } else if (itemnum == 1) {
157 if (item == "write" || item == "WRITE") {
158 transType = WRITE;
159 } else {
160 transType = READ;
161 }
162 } else if (itemnum == 2) {
163 stringstream timestamp(item);
164 timestamp >> std::hex >> transAddr;
165 }
166 itemnum++;
167 }
168 // generate a transaction
169 TransItem.timeStamp = transTime;
170 TransItem.logicalAddress = transAddr;
171 TransItem.type = transType;
172
173 transTrace.push_back(TransItem);
174
175 if (transTrace.size() == MILLION) {
176 // The scheduling is implemented for every MILLION transactions.
177 // It is used to reduce the used memory during the running of this tool.
178 analyticalScheduling(memSpec);
179 transTrace.erase(transTrace.begin(), transTrace.end());
180 }
181 }
182
183 if ((transTrace.size() < MILLION) && (!transTrace.empty())) {
184 analyticalScheduling(memSpec);
185 transTrace.erase(transTrace.begin(), transTrace.end());
186 }
187 } // cmdScheduler::getTrans
188
189 // Transactions are executed individually and the command scheduling is
190 // independent between transactions. The commands for a new transaction cannot
191 // be scheduled until all the commands for the current one are scheduled.
192 // After the scheduling, a sequence of commands are obtained and they are written
193 // into commands.txt which will be used for power analysis.
194 void cmdScheduler::analyticalScheduling(MemorySpecification memSpec)
195 {
196 int Bs = -1;
197 int transType = -1;
198 double timer = 0;
199 int bankGroupPointer = 0;
200 int bankGroupAddr = 0;
201 bool collisionFound;
202 physicalAddr PhysicalAddress;
203 bool bankGroupSwitch = false;
204 std::vector<unsigned> bankPointer(nbrOfBankGroups, 0);
205 std::vector<int> bankAccessNum(nBanks, -1);
206 std::vector<bool> ACTSchedule(nBanks, false);
207 int bankAddr = -1;
208 double endTime = 0;
209 double tComing_REF = 0;
210
211 Inselfrefresh = 0;
212
213 MemTimingSpec& memTimingSpec = memSpec.memTimingSpec;
214
215 for (unsigned t = 0; t < transTrace.size(); t++) {
216 cmdScheduling.erase(cmdScheduling.begin(), cmdScheduling.end());
217
218 for (unsigned i = 0; i < nBanks; i++) {
219 ACTSchedule[i] = false;
220 bankAccessNum[i] = -1;
221 }
222
223 timingsGet = false;
224 timer = transTrace[t].timeStamp;
225
226 PhysicalAddress = memoryMap(transTrace[t], memSpec);
227
228 for (unsigned i = 0; i < nbrOfBankGroups; i++) {
229 bankPointer[i] = PhysicalAddress.bankAddr; // the bank pointer per group.
230 }
231 bankGroupPointer = PhysicalAddress.bankGroupAddr;
232
233 endTime = max(transFinish.time, PRE[transFinish.bank].time +
234 static_cast<int>(memTimingSpec.RP));
235
236 // Before starting the scheduling for the next transaction, it has to
237 // check whether it is necessary for implementing power down.
238 if (power_down == SELF_REFRESH)
239 pdScheduling(endTime, timer, memSpec);
240 else if (power_down == POWER_DOWN)
241 pdScheduling(endTime, min(timer, tREF), memSpec);
242
243 tComing_REF = tREF;
244
245 ///////////////Scheduling Refresh////////////////////////
246 if (((transFinish.time >= tREF) || (timer >= tREF))) {
247 for (double i = 0; i <= ((timer - tComing_REF) > 0 ? (timer - tComing_REF) /
248 memTimingSpec.REFI : 0); i++) {
249 cmd.bank = 0;
250 cmd.name = "REF";
251 cmd.time = max(max(max(transFinish.time, PRE[transFinish.bank].time
252 + static_cast<int>(memTimingSpec.RP)), tREF), startTime);
253 if (((power_down == SELF_REFRESH) && !Inselfrefresh) ||
254 (power_down != SELF_REFRESH)) {
255 cmdScheduling.push_back(cmd);
256 startTime = cmd.time + memTimingSpec.RFC;
257 }
258 tREF = tREF + memTimingSpec.REFI;
259 // during the refreshing, power down should be taken into account.
260 if (!Inselfrefresh)
261 pdScheduling(endTime, min(timer, tREF), memSpec);
262 }
263 }
264 ///////////////Execution Transactions///////////////////
265 Bs = PhysicalAddress.bankAddr;
266 transType = transTrace[t].type;
267
268 tRWTP = getRWTP(transType, memSpec);
269
270 for (int i = 0; i < BI; i++) {
271 for (int k = 0; k < BC; k++) {
272 if (memSpec.memoryType == MemoryType::DDR4) {
273 bankGroupPointer = PhysicalAddress.bankGroupAddr;
274 }
275
276 for (int j = 0; j < BGI; j++) {
277 bankGroupSwitch = false;
278 if (memSpec.memoryType == MemoryType::DDR4) {
279 if (bankGroupPointer != bankGroupAddr) {
280 bankGroupSwitch = true;
281 }
282 // update to the current bank group address.
283 bankGroupAddr = PhysicalAddress.bankGroupAddr + j;
284 bankAddr = bankGroupAddr * nBanks / nbrOfBankGroups +
285 bankPointer[bankGroupAddr];
286 } else {
287 bankAddr = Bs + i;
288 }
289
290 if (!timingsGet) {
291 getTimingConstraints(bankGroupSwitch, memSpec,
292 PreRDWR.Type, transType);
293 }
294
295 ////////////////ACT Scheduling///////////////////
296 if (!ACTSchedule[bankAddr]) {
297 cmd.bank = bankAddr;
298 cmd.PhysicalAddr.bankAddr = cmd.bank;
299 cmd.PhysicalAddr.rowAddr = PhysicalAddress.rowAddr;
300 cmd.Type = ACTIVATE;
301 cmd.name = "ACT";
302 Inselfrefresh = 0;
303 cmd.time = max(max(ACT[bankaccess - 1].time + tRRD_init,
304 PRE[cmd.bank].time + static_cast<int>(memTimingSpec.RP)),
305 ACT[bankaccess - 4].time +
306 static_cast<int>(memTimingSpec.FAW));
307
308 if (memSpec.memoryType == MemoryType::WIDEIO_SDR) {
309 cmd.time = max(max(ACT[bankaccess - 1].time + tRRD_init,
310 PRE[cmd.bank].time + static_cast<int>(memTimingSpec.RP)),
311 ACT[bankaccess - 2].time +
312 static_cast<int>(memTimingSpec.TAW));
313 }
314
315 if ((i == 0) && (j == 0)) {
316 cmd.time = max(cmd.time, PreRDWR.time + 1);
317 cmd.time = max(cmd.time, timer);
318 cmd.time = max(startTime, cmd.time);
319 }
320
321 //////////collision detection////////////////////
322 for (int n = 1; n <= i * BGI + j; n++) {
323 collisionFound = false;
324 for (unsigned m = 0; m < RDWR[bankaccess - n].size(); m++) {
325 if (RDWR[bankaccess - n][m].time == cmd.time) {
326 cmd.time += 1; // ACT is shifted
327 collisionFound = true;
328 break;
329 }
330 }
331 if (collisionFound) {
332 break;
333 }
334 }
335
336 ACT.push_back(cmd);
337 cmdScheduling.push_back(cmd);
338
339 ACTSchedule[bankAddr] = true;
340 bankAccessNum[bankAddr] = bankaccess;
341 bankaccess++;
342 }
343
344 /////RDWR Scheduling//////
345 cmd.bank = bankAddr;
346 cmd.PhysicalAddr.bankAddr = cmd.bank;
347 cmd.PhysicalAddr.rowAddr = PhysicalAddress.rowAddr;
348 cmd.PhysicalAddr.colAddr = PhysicalAddress.colAddr + k * burstLength;
349 cmd.Type = transType;
350 switch (transType) {
351 case READ:
352 cmd.name = "RD";
353 break;
354
355 case WRITE:
356 cmd.name = "WR";
357 break;
358 }
359 for (int ACTBank = static_cast<int>(ACT.size() - 1);
360 ACTBank >= 0; ACTBank--) {
361 if (ACT[ACTBank].bank == bankAddr) {
362 cmd.time = max(PreRDWR.time + tSwitch_init, ACT.back().time
363 + static_cast<int>(memTimingSpec.RCD));
364 break;
365 }
366 }
367
368 if ((i == BI - 1) && (k == BC - 1) && (j == BGI - 1)) {
369 transFinish.time = cmd.time + 1;
370 transFinish.bank = bankAddr;
371 }
372 if (k == BC - 1) {
373 switch (transType) {
374 case READ:
375 cmd.name = "RDA";
376 break;
377
378 case WRITE:
379 cmd.name = "WRA";
380 break;
381 }
382 }
383 PreRDWR = cmd;
384
385 RDWR[bankAccessNum[bankAddr]].push_back(cmd);
386 cmdScheduling.push_back(cmd);
387
388 ////////////////PRE Scheduling////////////////////
389 if (k == BC - 1) {
390 PRE[bankAddr].bank = bankAddr;
391 PRE[bankAddr].Type = PRECHARGE;
392 PRE[bankAddr].name = "PRE";
393 for (int ACTBank = static_cast<int>(ACT.size() - 1);
394 ACTBank >= 0; ACTBank--) {
395 if (ACT[ACTBank].bank == bankAddr) {
396 PRE[bankAddr].time = max(ACT.back().time +
397 static_cast<int>(memTimingSpec.RAS),
398 PreRDWR.time + tRWTP);
399 break;
400 }
401 }
402 bankPointer[bankGroupAddr] = bankPointer[bankGroupAddr] + 1;
403 }
404
405 bankGroupPointer++;
406 }
407 }
408 }
409
410 // make sure the scheduled commands are stored with an ascending scheduling time
411 sort(cmdScheduling.begin(), cmdScheduling.end(),
412 commandItem::commandItemSorter());
413
414 // write the scheduled commands into commands.txt.
415 for (unsigned i = 0; i < cmdScheduling.size(); i++) {
416 cmdList.push_back(cmdScheduling[i]);
417 }
418
419 /////////////Update Vector Length/////////////////
420 // the vector length is reduced so that less memory is used for running
421 // this tool.
422 if (ACT.size() >= memSpec.memArchSpec.nbrOfBanks) {
423 for (int m = 0; m < BI * BGI; m++) {
424 ACT.erase(ACT.begin());
425 RDWR[0].erase(RDWR[0].begin(), RDWR[0].end());
426 for (int h = 0; h < bankaccess - 1 - m; h++) {
427 RDWR[h].insert(RDWR[h].begin(), RDWR[h + 1].begin(), RDWR[h + 1].end());
428 RDWR[h + 1].resize(0);
429 }
430 }
431 bankaccess = bankaccess - (BI * BGI);
432 }
433 }
434
435 for (unsigned j = 0; j < cmdList.size(); j++) {
436 commands.precision(0);
437 commands << fixed << cmdList[j].time << "," << cmdList[j].name << "," <<
438 cmdList[j].bank << endl;
439 }
440 cmdList.erase(cmdList.begin(), cmdList.end());
441 } // cmdScheduler::analyticalScheduling
442
443 // to add the power down/up during the command scheduling for transactions.
444 // It is called when the command scheduling for a transaction is finished, and it
445 // is also called if there is a refresh.
446 void cmdScheduler::pdScheduling(double endTime, double timer,
447 MemorySpecification memSpec)
448 {
449 double ZERO = 0;
450 MemTimingSpec& memTimingSpec = memSpec.memTimingSpec;
451
452 endTime = max(endTime, startTime);
453 double pdTime = max(ZERO, timer - endTime);
454
455 if ((timer > (endTime + memTimingSpec.CKE)) && (power_down == POWER_DOWN)) {
456 cmd.bank = 0;
457 cmd.name = "PDN_S_PRE";
458 cmd.time = endTime;
459 cmdScheduling.push_back(cmd);
460 cmd.name = "PUP_PRE";
461
462 if (pdTime > memTimingSpec.REFI)
463 cmd.time = cmd.time + memTimingSpec.REFI;
464 else
465 cmd.time = cmd.time + pdTime;
466
467 if (memSpec.memoryType.isLPDDRFamily())
468 startTime = cmd.time + memTimingSpec.XP;
469 else
470 startTime = cmd.time + memTimingSpec.XPDLL - memTimingSpec.RCD;
471
472 cmdScheduling.push_back(cmd);
473 } else if ((timer > (endTime + memTimingSpec.CKESR)) && (power_down == SELF_REFRESH)) {
474 cmd.bank = 0;
475 cmd.name = "SREN";
476 cmd.time = endTime;
477 cmdScheduling.push_back(cmd);
478 Inselfrefresh = 1;
479 cmd.name = "SREX";
480 cmd.time = cmd.time + pdTime;
481
482 if (memSpec.memoryType.isLPDDRFamily())
483 startTime = cmd.time + memTimingSpec.XS;
484 else
485 startTime = cmd.time + memTimingSpec.XSDLL - memTimingSpec.RCD;
486
487 cmdScheduling.push_back(cmd);
488 }
489 } // cmdScheduler::pdScheduling
490
491 // get the time when a precharge occurs after a read/write command is scheduled.
492 // In addition, it copes with different kind of memories.
493 int cmdScheduler::getRWTP(int transType, MemorySpecification memSpec)
494 {
495 int tRWTP_init = 0;
496 MemTimingSpec& memTimingSpec = memSpec.memTimingSpec;
497 MemArchitectureSpec& memArchSpec = memSpec.memArchSpec;
498
499 if (transType == READ) {
500 switch (memSpec.memoryType) {
501 case MemoryType::LPDDR:
502 case MemoryType::WIDEIO_SDR:
503 tRWTP_init = memArchSpec.burstLength / memArchSpec.dataRate;
504 break;
505
506 case MemoryType::LPDDR2:
507 case MemoryType::LPDDR3:
508 tRWTP_init = memArchSpec.burstLength / memArchSpec.dataRate +
509 max(0, static_cast<int>(memTimingSpec.RTP - 2));
510 break;
511
512 case MemoryType::DDR2:
513 tRWTP_init = memTimingSpec.AL + memArchSpec.burstLength /
514 memArchSpec.dataRate +
515 max(static_cast<int>(memTimingSpec.RTP), 2) - 2;
516 break;
517
518 case MemoryType::DDR3:
519 case MemoryType::DDR4:
520 tRWTP_init = memTimingSpec.RTP;
521 break;
522 default:
523 assert("Unknown memory type" && false);
524 } // switch
525 } else if (transType == WRITE) {
526 if (memSpec.memoryType == MemoryType::WIDEIO_SDR) {
527 tRWTP_init = memTimingSpec.WL + memArchSpec.burstLength /
528 memArchSpec.dataRate - 1 + memSpec.memTimingSpec.WR;
529 } else {
530 tRWTP_init = memTimingSpec.WL + memArchSpec.burstLength /
531 memArchSpec.dataRate + memSpec.memTimingSpec.WR;
532 }
533 if ((memSpec.memoryType == MemoryType::LPDDR2) ||
534 (memSpec.memoryType == MemoryType::LPDDR3)) {
535 tRWTP_init = tRWTP_init + 1;
536 }
537 }
538
539 return tRWTP_init;
540 } // cmdScheduler::getRWTP
541
542 // get the timings for command scheduling according to different memories.
543 // In particular, tSwitch_init is generally used to provide the timings for
544 // scheduling a read/write command after a read/write command which have been
545 // scheduled to any possible banks within any possible bank groups (DDR4).
546 void cmdScheduler::getTimingConstraints(bool BGSwitch, MemorySpecification memSpec,
547 int PreType, int CurrentType)
548 {
549 MemTimingSpec& memTimingSpec = memSpec.memTimingSpec;
550 MemArchitectureSpec& memArchSpec = memSpec.memArchSpec;
551
552 if (memSpec.memoryType != MemoryType::DDR4) {
553 tRRD_init = memTimingSpec.RRD;
554 if (PreType == CurrentType) {
555 tSwitch_init = memTimingSpec.CCD;
556 timingsGet = true;
557 }
558
559 if ((PreType == WRITE) && (CurrentType == READ)) {
560 if (memSpec.memoryType == MemoryType::WIDEIO_SDR) {
561 tSwitch_init = memTimingSpec.WL + memArchSpec.burstLength /
562 memArchSpec.dataRate - 1 + memTimingSpec.WTR;
563 } else {
564 tSwitch_init = memTimingSpec.WL + memArchSpec.burstLength /
565 memArchSpec.dataRate + memTimingSpec.WTR;
566 }
567
568 if ((memSpec.memoryType == MemoryType::LPDDR2) ||
569 (memSpec.memoryType == MemoryType::LPDDR3)) {
570 tSwitch_init = tSwitch_init + 1;
571 }
572 }
573 }
574
575 if (memSpec.memoryType == MemoryType::DDR4) {
576 if (BGSwitch) {
577 tCCD_init = memTimingSpec.CCD_S;
578 tRRD_init = memTimingSpec.RRD_S;
579 tWTR_init = memTimingSpec.WTR_S;
580 } else {
581 tCCD_init = memTimingSpec.CCD_L;
582 tRRD_init = memTimingSpec.RRD_L;
583 tWTR_init = memTimingSpec.WTR_L;
584 }
585
586 if (PreType == CurrentType) {
587 tSwitch_init = tCCD_init;
588 timingsGet = true;
589 } else if ((PreType == WRITE) && (CurrentType == READ)) {
590 tSwitch_init = memTimingSpec.WL + memArchSpec.burstLength /
591 memArchSpec.dataRate + tWTR_init;
592 }
593 }
594
595 if ((PreType == READ) && (CurrentType == WRITE)) {
596 tSwitch_init = memTimingSpec.RL + memArchSpec.burstLength /
597 memArchSpec.dataRate + 2 - memTimingSpec.WL;
598 }
599 } // cmdScheduler::getTimingConstraints
600
601 // The logical address of each transaction is translated into a physical address
602 // which consists of bank group (for DDR4), bank, row and column addresses.
603 cmdScheduler::physicalAddr cmdScheduler::memoryMap(trans Trans,
604 MemorySpecification memSpec)
605 {
606 int DecLogic;
607 physicalAddr PhysicalAddr;
608
609 DecLogic = Trans.logicalAddress;
610
611 // row-bank-column-BI-BC-BGI-BL
612 if ((BGI > 1) && (memSpec.memoryType == MemoryType::DDR4)) {
613 unsigned colBits = static_cast<unsigned>(log2(nColumns));
614 unsigned bankShift = static_cast<unsigned>(colBits + ((BI > 1) ? log2(BI) : 0)
615 + ((BGI > 1) ? log2(BGI) : 0));
616 unsigned bankMask = static_cast<unsigned>(nBanks / (BI * nbrOfBankGroups) - 1)
617 << bankShift;
618 unsigned bankAddr = (DecLogic & bankMask) >>
619 static_cast<unsigned>(colBits + ((BGI > 1) ? log2(BGI) : 0));
620 PhysicalAddr.bankAddr = bankAddr;
621
622 unsigned bankGroupShift = static_cast<unsigned>(log2(burstLength));
623 unsigned bankGroupMask = (nbrOfBankGroups / BGI - 1) << bankGroupShift;
624 unsigned bankGroupAddr = (DecLogic & bankGroupMask) >> bankGroupShift;
625 PhysicalAddr.bankGroupAddr = bankGroupAddr;
626
627 unsigned colShift = static_cast<unsigned>(log2(BC * burstLength) +
628 ((BI > 1) ? log2(BI) : 0) + ((BGI > 1) ? log2(BGI) : 0));
629 unsigned colMask = static_cast<unsigned>(nColumns / (BC * burstLength) - 1)
630 << colShift;
631 unsigned colAddr = (DecLogic & colMask) >>
632 static_cast<unsigned>((colShift - log2(static_cast<unsigned>(BC) * burstLength)));
633 PhysicalAddr.colAddr = colAddr;
634 } else {
635 unsigned colBits = static_cast<unsigned>(log2(nColumns));
636 unsigned bankShift = static_cast<unsigned>(colBits + ((BI > 1) ? log2(BI) : 0));
637 unsigned bankMask = static_cast<unsigned>(nBanks / BI - 1) << bankShift;
638 unsigned bankAddr = (DecLogic & bankMask) >> colBits;
639 PhysicalAddr.bankAddr = bankAddr;
640
641 unsigned colShift = static_cast<unsigned>(log2(BC * burstLength) +
642 ((BI > 1) ? log2(BI) : 0));
643 unsigned colMask = static_cast<unsigned>(nColumns / (BC * burstLength) - 1)
644 << colShift;
645 unsigned colAddr = (DecLogic & colMask) >>
646 static_cast<unsigned>((colShift - log2(static_cast<unsigned>(BC) * burstLength)));
647 PhysicalAddr.colAddr = colAddr;
648
649 PhysicalAddr.bankGroupAddr = 0;
650 }
651
652 unsigned rowShift = static_cast<unsigned>(log2(nColumns * nBanks));
653 unsigned rowMask = static_cast<unsigned>(memSpec.memArchSpec.nbrOfRows - 1)
654 << rowShift;
655 unsigned rowAddr = (DecLogic & rowMask) >> rowShift;
656 PhysicalAddr.rowAddr = rowAddr;
657
658 return PhysicalAddr;
659 } // cmdScheduler::memoryMap