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