2 * Copyright (c) 2012-2014, TU Delft
3 * Copyright (c) 2012-2014, TU Eindhoven
4 * Copyright (c) 2012-2014, TU Kaiserslautern
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 * Authors: Karthik Chandrasekar
37 #include "CmdScheduler.h"
40 #include <cmath> // For log2
42 #include <algorithm> // For max
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
)
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
;
64 power_down
= powerdown
;
66 schedulingInitialization(memSpec
);
67 getTrans(trans_trace
, memSpec
);
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
79 // initialize the variables and vectors for starting command scheduling.
80 void cmdScheduler::schedulingInitialization(MemorySpecification memSpec
)
82 MemTimingSpec
& memTimingSpec
= memSpec
.memTimingSpec
;
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
;
89 ACT
.erase(ACT
.begin(), ACT
.end());
92 PRE
.erase(PRE
.begin(), PRE
.end());
95 RDWR
.erase(RDWR
.begin(), RDWR
.end());
98 ///////////////initialization//////////////
99 for (unsigned i
= 0; i
< memSpec
.memArchSpec
.nbrOfBanks
; i
++) {
100 cmd
.Type
= PRECHARGE
;
103 if (memSpec
.id
== "WIDEIO_SDR")
104 cmd
.time
= 1 - static_cast<double>(memSpec
.memTimingSpec
.TAW
);
106 cmd
.time
= 1 - static_cast<double>(memSpec
.memTimingSpec
.FAW
);
117 RDWR
[i
].push_back(cmd
);
119 tREF
= memTimingSpec
.REFI
;
120 transFinish
.time
= 0;
121 transFinish
.bank
= 0;
128 } // cmdScheduler::schedulingInitialization
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
)
138 unsigned newtranstime
;
140 unsigned transType
= 1;
143 if (!transTrace
.empty()) {
144 transTrace
.erase(transTrace
.begin(), transTrace
.end());
147 while (getline(trans_trace
, line
)) {
148 istringstream
linestream(line
);
150 unsigned itemnum
= 0;
151 while (getline(linestream
, item
, ',')) {
153 stringstream
timestamp(item
);
154 timestamp
>> newtranstime
;
155 transTime
= transTime
+ newtranstime
;
156 } else if (itemnum
== 1) {
157 if (item
== "write" || item
== "WRITE") {
162 } else if (itemnum
== 2) {
163 stringstream
timestamp(item
);
164 timestamp
>> std::hex
>> transAddr
;
168 // generate a transaction
169 TransItem
.timeStamp
= transTime
;
170 TransItem
.logicalAddress
= transAddr
;
171 TransItem
.type
= transType
;
173 transTrace
.push_back(TransItem
);
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());
183 if ((transTrace
.size() < MILLION
) && (!transTrace
.empty())) {
184 analyticalScheduling(memSpec
);
185 transTrace
.erase(transTrace
.begin(), transTrace
.end());
187 } // cmdScheduler::getTrans
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
)
199 int bankGroupPointer
= 0;
200 int bankGroupAddr
= 0;
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);
209 double tComing_REF
= 0;
213 MemTimingSpec
& memTimingSpec
= memSpec
.memTimingSpec
;
215 for (unsigned t
= 0; t
< transTrace
.size(); t
++) {
216 cmdScheduling
.erase(cmdScheduling
.begin(), cmdScheduling
.end());
218 for (unsigned i
= 0; i
< nBanks
; i
++) {
219 ACTSchedule
[i
] = false;
220 bankAccessNum
[i
] = -1;
224 timer
= transTrace
[t
].timeStamp
;
226 PhysicalAddress
= memoryMap(transTrace
[t
], memSpec
);
228 for (unsigned i
= 0; i
< nbrOfBankGroups
; i
++) {
229 bankPointer
[i
] = PhysicalAddress
.bankAddr
; // the bank pointer per group.
231 bankGroupPointer
= PhysicalAddress
.bankGroupAddr
;
233 endTime
= max(transFinish
.time
, PRE
[transFinish
.bank
].time
+
234 static_cast<int>(memTimingSpec
.RP
));
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
);
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
++) {
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
;
258 tREF
= tREF
+ memTimingSpec
.REFI
;
259 // during the refreshing, power down should be taken into account.
261 pdScheduling(endTime
, min(timer
, tREF
), memSpec
);
264 ///////////////Execution Transactions///////////////////
265 Bs
= PhysicalAddress
.bankAddr
;
266 transType
= transTrace
[t
].type
;
268 tRWTP
= getRWTP(transType
, memSpec
);
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
;
276 for (int j
= 0; j
< BGI
; j
++) {
277 bankGroupSwitch
= false;
278 if (memSpec
.memoryType
== MemoryType::DDR4
) {
279 if (bankGroupPointer
!= bankGroupAddr
) {
280 bankGroupSwitch
= true;
282 // update to the current bank group address.
283 bankGroupAddr
= PhysicalAddress
.bankGroupAddr
+ j
;
284 bankAddr
= bankGroupAddr
* nBanks
/ nbrOfBankGroups
+
285 bankPointer
[bankGroupAddr
];
291 getTimingConstraints(bankGroupSwitch
, memSpec
,
292 PreRDWR
.Type
, transType
);
295 ////////////////ACT Scheduling///////////////////
296 if (!ACTSchedule
[bankAddr
]) {
298 cmd
.PhysicalAddr
.bankAddr
= cmd
.bank
;
299 cmd
.PhysicalAddr
.rowAddr
= PhysicalAddress
.rowAddr
;
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
));
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
));
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
);
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;
331 if (collisionFound
) {
337 cmdScheduling
.push_back(cmd
);
339 ACTSchedule
[bankAddr
] = true;
340 bankAccessNum
[bankAddr
] = bankaccess
;
344 /////RDWR Scheduling//////
346 cmd
.PhysicalAddr
.bankAddr
= cmd
.bank
;
347 cmd
.PhysicalAddr
.rowAddr
= PhysicalAddress
.rowAddr
;
348 cmd
.PhysicalAddr
.colAddr
= PhysicalAddress
.colAddr
+ k
* burstLength
;
349 cmd
.Type
= transType
;
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
));
368 if ((i
== BI
- 1) && (k
== BC
- 1) && (j
== BGI
- 1)) {
369 transFinish
.time
= cmd
.time
+ 1;
370 transFinish
.bank
= bankAddr
;
385 RDWR
[bankAccessNum
[bankAddr
]].push_back(cmd
);
386 cmdScheduling
.push_back(cmd
);
388 ////////////////PRE Scheduling////////////////////
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
);
402 bankPointer
[bankGroupAddr
] = bankPointer
[bankGroupAddr
] + 1;
410 // make sure the scheduled commands are stored with an ascending scheduling time
411 sort(cmdScheduling
.begin(), cmdScheduling
.end(),
412 commandItem::commandItemSorter());
414 // write the scheduled commands into commands.txt.
415 for (unsigned i
= 0; i
< cmdScheduling
.size(); i
++) {
416 cmdList
.push_back(cmdScheduling
[i
]);
419 /////////////Update Vector Length/////////////////
420 // the vector length is reduced so that less memory is used for running
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);
431 bankaccess
= bankaccess
- (BI
* BGI
);
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
;
440 cmdList
.erase(cmdList
.begin(), cmdList
.end());
441 } // cmdScheduler::analyticalScheduling
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
)
450 MemTimingSpec
& memTimingSpec
= memSpec
.memTimingSpec
;
452 endTime
= max(endTime
, startTime
);
453 double pdTime
= max(ZERO
, timer
- endTime
);
455 if ((timer
> (endTime
+ memTimingSpec
.CKE
)) && (power_down
== POWER_DOWN
)) {
457 cmd
.name
= "PDN_S_PRE";
459 cmdScheduling
.push_back(cmd
);
460 cmd
.name
= "PUP_PRE";
462 if (pdTime
> memTimingSpec
.REFI
)
463 cmd
.time
= cmd
.time
+ memTimingSpec
.REFI
;
465 cmd
.time
= cmd
.time
+ pdTime
;
467 if (memSpec
.memoryType
.isLPDDRFamily())
468 startTime
= cmd
.time
+ memTimingSpec
.XP
;
470 startTime
= cmd
.time
+ memTimingSpec
.XPDLL
- memTimingSpec
.RCD
;
472 cmdScheduling
.push_back(cmd
);
473 } else if ((timer
> (endTime
+ memTimingSpec
.CKESR
)) && (power_down
== SELF_REFRESH
)) {
477 cmdScheduling
.push_back(cmd
);
480 cmd
.time
= cmd
.time
+ pdTime
;
482 if (memSpec
.memoryType
.isLPDDRFamily())
483 startTime
= cmd
.time
+ memTimingSpec
.XS
;
485 startTime
= cmd
.time
+ memTimingSpec
.XSDLL
- memTimingSpec
.RCD
;
487 cmdScheduling
.push_back(cmd
);
489 } // cmdScheduler::pdScheduling
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
)
496 MemTimingSpec
& memTimingSpec
= memSpec
.memTimingSpec
;
497 MemArchitectureSpec
& memArchSpec
= memSpec
.memArchSpec
;
499 if (transType
== READ
) {
500 switch (memSpec
.memoryType
) {
501 case MemoryType::LPDDR
:
502 case MemoryType::WIDEIO_SDR
:
503 tRWTP_init
= memArchSpec
.burstLength
/ memArchSpec
.dataRate
;
506 case MemoryType::LPDDR2
:
507 case MemoryType::LPDDR3
:
508 tRWTP_init
= memArchSpec
.burstLength
/ memArchSpec
.dataRate
+
509 max(0, static_cast<int>(memTimingSpec
.RTP
- 2));
512 case MemoryType::DDR2
:
513 tRWTP_init
= memTimingSpec
.AL
+ memArchSpec
.burstLength
/
514 memArchSpec
.dataRate
+
515 max(static_cast<int>(memTimingSpec
.RTP
), 2) - 2;
518 case MemoryType::DDR3
:
519 case MemoryType::DDR4
:
520 tRWTP_init
= memTimingSpec
.RTP
;
523 assert("Unknown memory type" && false);
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
;
530 tRWTP_init
= memTimingSpec
.WL
+ memArchSpec
.burstLength
/
531 memArchSpec
.dataRate
+ memSpec
.memTimingSpec
.WR
;
533 if ((memSpec
.memoryType
== MemoryType::LPDDR2
) ||
534 (memSpec
.memoryType
== MemoryType::LPDDR3
)) {
535 tRWTP_init
= tRWTP_init
+ 1;
540 } // cmdScheduler::getRWTP
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
)
549 MemTimingSpec
& memTimingSpec
= memSpec
.memTimingSpec
;
550 MemArchitectureSpec
& memArchSpec
= memSpec
.memArchSpec
;
552 if (memSpec
.memoryType
!= MemoryType::DDR4
) {
553 tRRD_init
= memTimingSpec
.RRD
;
554 if (PreType
== CurrentType
) {
555 tSwitch_init
= memTimingSpec
.CCD
;
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
;
564 tSwitch_init
= memTimingSpec
.WL
+ memArchSpec
.burstLength
/
565 memArchSpec
.dataRate
+ memTimingSpec
.WTR
;
568 if ((memSpec
.memoryType
== MemoryType::LPDDR2
) ||
569 (memSpec
.memoryType
== MemoryType::LPDDR3
)) {
570 tSwitch_init
= tSwitch_init
+ 1;
575 if (memSpec
.memoryType
== MemoryType::DDR4
) {
577 tCCD_init
= memTimingSpec
.CCD_S
;
578 tRRD_init
= memTimingSpec
.RRD_S
;
579 tWTR_init
= memTimingSpec
.WTR_S
;
581 tCCD_init
= memTimingSpec
.CCD_L
;
582 tRRD_init
= memTimingSpec
.RRD_L
;
583 tWTR_init
= memTimingSpec
.WTR_L
;
586 if (PreType
== CurrentType
) {
587 tSwitch_init
= tCCD_init
;
589 } else if ((PreType
== WRITE
) && (CurrentType
== READ
)) {
590 tSwitch_init
= memTimingSpec
.WL
+ memArchSpec
.burstLength
/
591 memArchSpec
.dataRate
+ tWTR_init
;
595 if ((PreType
== READ
) && (CurrentType
== WRITE
)) {
596 tSwitch_init
= memTimingSpec
.RL
+ memArchSpec
.burstLength
/
597 memArchSpec
.dataRate
+ 2 - memTimingSpec
.WL
;
599 } // cmdScheduler::getTimingConstraints
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
)
607 physicalAddr PhysicalAddr
;
609 DecLogic
= Trans
.logicalAddress
;
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)
618 unsigned bankAddr
= (DecLogic
& bankMask
) >>
619 static_cast<unsigned>(colBits
+ ((BGI
> 1) ? log2(BGI
) : 0));
620 PhysicalAddr
.bankAddr
= bankAddr
;
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
;
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)
631 unsigned colAddr
= (DecLogic
& colMask
) >>
632 static_cast<unsigned>((colShift
- log2(static_cast<unsigned>(BC
) * burstLength
)));
633 PhysicalAddr
.colAddr
= colAddr
;
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
;
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)
645 unsigned colAddr
= (DecLogic
& colMask
) >>
646 static_cast<unsigned>((colShift
- log2(static_cast<unsigned>(BC
) * burstLength
)));
647 PhysicalAddr
.colAddr
= colAddr
;
649 PhysicalAddr
.bankGroupAddr
= 0;
652 unsigned rowShift
= static_cast<unsigned>(log2(nColumns
* nBanks
));
653 unsigned rowMask
= static_cast<unsigned>(memSpec
.memArchSpec
.nbrOfRows
- 1)
655 unsigned rowAddr
= (DecLogic
& rowMask
) >> rowShift
;
656 PhysicalAddr
.rowAddr
= rowAddr
;
659 } // cmdScheduler::memoryMap