CmdScheduler.cc revision 10428:0caf62b57dfd
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 45using namespace std; 46using 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. 51void 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. 80void 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. 133void 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. 194void 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. 446void 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. 493int 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). 546void 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. 603cmdScheduler::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 660