dram_ctrl.cc (12823:ba630bc7a36d) | dram_ctrl.cc (12969:52de9d619ce6) |
---|---|
1/* 2 * Copyright (c) 2010-2018 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 39 unchanged lines hidden (view full) --- 48#include "mem/dram_ctrl.hh" 49 50#include "base/bitfield.hh" 51#include "base/trace.hh" 52#include "debug/DRAM.hh" 53#include "debug/DRAMPower.hh" 54#include "debug/DRAMState.hh" 55#include "debug/Drain.hh" | 1/* 2 * Copyright (c) 2010-2018 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 39 unchanged lines hidden (view full) --- 48#include "mem/dram_ctrl.hh" 49 50#include "base/bitfield.hh" 51#include "base/trace.hh" 52#include "debug/DRAM.hh" 53#include "debug/DRAMPower.hh" 54#include "debug/DRAMState.hh" 55#include "debug/Drain.hh" |
56#include "debug/QOS.hh" |
|
56#include "sim/system.hh" 57 58using namespace std; 59using namespace Data; 60 61DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) : | 57#include "sim/system.hh" 58 59using namespace std; 60using namespace Data; 61 62DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) : |
62 AbstractMemory(p), | 63 QoS::MemCtrl(p), |
63 port(name() + ".port", *this), isTimingMode(false), 64 retryRdReq(false), retryWrReq(false), | 64 port(name() + ".port", *this), isTimingMode(false), 65 retryRdReq(false), retryWrReq(false), |
65 busState(READ), 66 busStateNext(READ), | |
67 nextReqEvent([this]{ processNextReqEvent(); }, name()), 68 respondEvent([this]{ processRespondEvent(); }, name()), 69 deviceSize(p->device_size), 70 deviceBusWidth(p->device_bus_width), burstLength(p->burst_length), 71 deviceRowBufferSize(p->device_rowbuffer_size), 72 devicesPerRank(p->devices_per_rank), 73 burstSize((devicesPerRank * burstLength * deviceBusWidth) / 8), 74 rowBufferSize(devicesPerRank * deviceRowBufferSize), --- 27 unchanged lines hidden (view full) --- 102{ 103 // sanity check the ranks since we rely on bit slicing for the 104 // address decoding 105 fatal_if(!isPowerOf2(ranksPerChannel), "DRAM rank count of %d is not " 106 "allowed, must be a power of two\n", ranksPerChannel); 107 108 fatal_if(!isPowerOf2(burstSize), "DRAM burst size %d is not allowed, " 109 "must be a power of two\n", burstSize); | 66 nextReqEvent([this]{ processNextReqEvent(); }, name()), 67 respondEvent([this]{ processRespondEvent(); }, name()), 68 deviceSize(p->device_size), 69 deviceBusWidth(p->device_bus_width), burstLength(p->burst_length), 70 deviceRowBufferSize(p->device_rowbuffer_size), 71 devicesPerRank(p->devices_per_rank), 72 burstSize((devicesPerRank * burstLength * deviceBusWidth) / 8), 73 rowBufferSize(devicesPerRank * deviceRowBufferSize), --- 27 unchanged lines hidden (view full) --- 101{ 102 // sanity check the ranks since we rely on bit slicing for the 103 // address decoding 104 fatal_if(!isPowerOf2(ranksPerChannel), "DRAM rank count of %d is not " 105 "allowed, must be a power of two\n", ranksPerChannel); 106 107 fatal_if(!isPowerOf2(burstSize), "DRAM burst size %d is not allowed, " 108 "must be a power of two\n", burstSize); |
109 readQueue.resize(p->qos_priorities); 110 writeQueue.resize(p->qos_priorities); |
|
110 | 111 |
112 |
|
111 for (int i = 0; i < ranksPerChannel; i++) { 112 Rank* rank = new Rank(*this, p, i); 113 ranks.push_back(rank); 114 } 115 116 // perform a basic check of the write thresholds 117 if (p->write_low_thresh_perc >= p->write_high_thresh_perc) 118 fatal("Write buffer low threshold %d must be smaller than the " --- 62 unchanged lines hidden (view full) --- 181 } 182 } 183 184} 185 186void 187DRAMCtrl::init() 188{ | 113 for (int i = 0; i < ranksPerChannel; i++) { 114 Rank* rank = new Rank(*this, p, i); 115 ranks.push_back(rank); 116 } 117 118 // perform a basic check of the write thresholds 119 if (p->write_low_thresh_perc >= p->write_high_thresh_perc) 120 fatal("Write buffer low threshold %d must be smaller than the " --- 62 unchanged lines hidden (view full) --- 183 } 184 } 185 186} 187 188void 189DRAMCtrl::init() 190{ |
189 AbstractMemory::init(); | 191 MemCtrl::init(); |
190 191 if (!port.isConnected()) { 192 fatal("DRAMCtrl %s is unconnected!\n", name()); 193 } else { 194 port.sendRangeChange(); 195 } 196 197 // a bit of sanity checks on the interleaving, save it for here to --- 80 unchanged lines hidden (view full) --- 278 } 279 return latency; 280} 281 282bool 283DRAMCtrl::readQueueFull(unsigned int neededEntries) const 284{ 285 DPRINTF(DRAM, "Read queue limit %d, current size %d, entries needed %d\n", | 192 193 if (!port.isConnected()) { 194 fatal("DRAMCtrl %s is unconnected!\n", name()); 195 } else { 196 port.sendRangeChange(); 197 } 198 199 // a bit of sanity checks on the interleaving, save it for here to --- 80 unchanged lines hidden (view full) --- 280 } 281 return latency; 282} 283 284bool 285DRAMCtrl::readQueueFull(unsigned int neededEntries) const 286{ 287 DPRINTF(DRAM, "Read queue limit %d, current size %d, entries needed %d\n", |
286 readBufferSize, readQueue.size() + respQueue.size(), | 288 readBufferSize, totalReadQueueSize + respQueue.size(), |
287 neededEntries); 288 | 289 neededEntries); 290 |
289 return 290 (readQueue.size() + respQueue.size() + neededEntries) > readBufferSize; | 291 auto rdsize_new = totalReadQueueSize + respQueue.size() + neededEntries; 292 return rdsize_new > readBufferSize; |
291} 292 293bool 294DRAMCtrl::writeQueueFull(unsigned int neededEntries) const 295{ 296 DPRINTF(DRAM, "Write queue limit %d, current size %d, entries needed %d\n", | 293} 294 295bool 296DRAMCtrl::writeQueueFull(unsigned int neededEntries) const 297{ 298 DPRINTF(DRAM, "Write queue limit %d, current size %d, entries needed %d\n", |
297 writeBufferSize, writeQueue.size(), neededEntries); 298 return (writeQueue.size() + neededEntries) > writeBufferSize; | 299 writeBufferSize, totalWriteQueueSize, neededEntries); 300 301 auto wrsize_new = (totalWriteQueueSize + neededEntries); 302 return wrsize_new > writeBufferSize; |
299} 300 301DRAMCtrl::DRAMPacket* 302DRAMCtrl::decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned size, 303 bool isRead) 304{ 305 // decode the address based on the address mapping scheme, with 306 // Ro, Ra, Co, Ba and Ch denoting row, rank, column, bank and --- 115 unchanged lines hidden (view full) --- 422 Addr addr = pkt->getAddr(); 423 unsigned pktsServicedByWrQ = 0; 424 BurstHelper* burst_helper = NULL; 425 for (int cnt = 0; cnt < pktCount; ++cnt) { 426 unsigned size = std::min((addr | (burstSize - 1)) + 1, 427 pkt->getAddr() + pkt->getSize()) - addr; 428 readPktSize[ceilLog2(size)]++; 429 readBursts++; | 303} 304 305DRAMCtrl::DRAMPacket* 306DRAMCtrl::decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned size, 307 bool isRead) 308{ 309 // decode the address based on the address mapping scheme, with 310 // Ro, Ra, Co, Ba and Ch denoting row, rank, column, bank and --- 115 unchanged lines hidden (view full) --- 426 Addr addr = pkt->getAddr(); 427 unsigned pktsServicedByWrQ = 0; 428 BurstHelper* burst_helper = NULL; 429 for (int cnt = 0; cnt < pktCount; ++cnt) { 430 unsigned size = std::min((addr | (burstSize - 1)) + 1, 431 pkt->getAddr() + pkt->getSize()) - addr; 432 readPktSize[ceilLog2(size)]++; 433 readBursts++; |
434 masterReadAccesses[pkt->masterId()]++; |
|
430 431 // First check write buffer to see if the data is already at 432 // the controller 433 bool foundInWrQ = false; 434 Addr burst_addr = burstAlign(addr); 435 // if the burst address is not present then there is no need 436 // looking any further 437 if (isInWriteQueue.find(burst_addr) != isInWriteQueue.end()) { | 435 436 // First check write buffer to see if the data is already at 437 // the controller 438 bool foundInWrQ = false; 439 Addr burst_addr = burstAlign(addr); 440 // if the burst address is not present then there is no need 441 // looking any further 442 if (isInWriteQueue.find(burst_addr) != isInWriteQueue.end()) { |
438 for (const auto& p : writeQueue) { 439 // check if the read is subsumed in the write queue 440 // packet we are looking at 441 if (p->addr <= addr && (addr + size) <= (p->addr + p->size)) { 442 foundInWrQ = true; 443 servicedByWrQ++; 444 pktsServicedByWrQ++; 445 DPRINTF(DRAM, "Read to addr %lld with size %d serviced by " 446 "write queue\n", addr, size); 447 bytesReadWrQ += burstSize; 448 break; | 443 for (const auto& vec : writeQueue) { 444 for (const auto& p : vec) { 445 // check if the read is subsumed in the write queue 446 // packet we are looking at 447 if (p->addr <= addr && 448 ((addr + size) <= (p->addr + p->size))) { 449 450 foundInWrQ = true; 451 servicedByWrQ++; 452 pktsServicedByWrQ++; 453 DPRINTF(DRAM, 454 "Read to addr %lld with size %d serviced by " 455 "write queue\n", 456 addr, size); 457 bytesReadWrQ += burstSize; 458 break; 459 } |
449 } 450 } 451 } 452 453 // If not found in the write q, make a DRAM packet and 454 // push it onto the read queue 455 if (!foundInWrQ) { 456 457 // Make the burst helper for split packets 458 if (pktCount > 1 && burst_helper == NULL) { 459 DPRINTF(DRAM, "Read to addr %lld translates to %d " 460 "dram requests\n", pkt->getAddr(), pktCount); 461 burst_helper = new BurstHelper(pktCount); 462 } 463 464 DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, true); 465 dram_pkt->burstHelper = burst_helper; 466 467 assert(!readQueueFull(1)); | 460 } 461 } 462 } 463 464 // If not found in the write q, make a DRAM packet and 465 // push it onto the read queue 466 if (!foundInWrQ) { 467 468 // Make the burst helper for split packets 469 if (pktCount > 1 && burst_helper == NULL) { 470 DPRINTF(DRAM, "Read to addr %lld translates to %d " 471 "dram requests\n", pkt->getAddr(), pktCount); 472 burst_helper = new BurstHelper(pktCount); 473 } 474 475 DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, true); 476 dram_pkt->burstHelper = burst_helper; 477 478 assert(!readQueueFull(1)); |
468 rdQLenPdf[readQueue.size() + respQueue.size()]++; | 479 rdQLenPdf[totalReadQueueSize + respQueue.size()]++; |
469 470 DPRINTF(DRAM, "Adding to read queue\n"); 471 | 480 481 DPRINTF(DRAM, "Adding to read queue\n"); 482 |
472 readQueue.push_back(dram_pkt); | 483 readQueue[dram_pkt->qosValue()].push_back(dram_pkt); |
473 | 484 |
474 // increment read entries of the rank | |
475 ++dram_pkt->rankRef.readEntries; 476 | 485 ++dram_pkt->rankRef.readEntries; 486 |
487 // log packet 488 logRequest(MemCtrl::READ, pkt->masterId(), pkt->qosValue(), 489 dram_pkt->addr, 1); 490 |
|
477 // Update stats | 491 // Update stats |
478 avgRdQLen = readQueue.size() + respQueue.size(); | 492 avgRdQLen = totalReadQueueSize + respQueue.size(); |
479 } 480 481 // Starting address of next dram pkt (aligend to burstSize boundary) 482 addr = (addr | (burstSize - 1)) + 1; 483 } 484 485 // If all packets are serviced by write queue, we send the repsonse back 486 if (pktsServicedByWrQ == pktCount) { --- 23 unchanged lines hidden (view full) --- 510 // if the request size is larger than burst size, the pkt is split into 511 // multiple DRAM packets 512 Addr addr = pkt->getAddr(); 513 for (int cnt = 0; cnt < pktCount; ++cnt) { 514 unsigned size = std::min((addr | (burstSize - 1)) + 1, 515 pkt->getAddr() + pkt->getSize()) - addr; 516 writePktSize[ceilLog2(size)]++; 517 writeBursts++; | 493 } 494 495 // Starting address of next dram pkt (aligend to burstSize boundary) 496 addr = (addr | (burstSize - 1)) + 1; 497 } 498 499 // If all packets are serviced by write queue, we send the repsonse back 500 if (pktsServicedByWrQ == pktCount) { --- 23 unchanged lines hidden (view full) --- 524 // if the request size is larger than burst size, the pkt is split into 525 // multiple DRAM packets 526 Addr addr = pkt->getAddr(); 527 for (int cnt = 0; cnt < pktCount; ++cnt) { 528 unsigned size = std::min((addr | (burstSize - 1)) + 1, 529 pkt->getAddr() + pkt->getSize()) - addr; 530 writePktSize[ceilLog2(size)]++; 531 writeBursts++; |
532 masterWriteAccesses[pkt->masterId()]++; |
|
518 519 // see if we can merge with an existing item in the write 520 // queue and keep track of whether we have merged or not 521 bool merged = isInWriteQueue.find(burstAlign(addr)) != 522 isInWriteQueue.end(); 523 524 // if the item was not merged we need to create a new write 525 // and enqueue it 526 if (!merged) { 527 DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, false); 528 | 533 534 // see if we can merge with an existing item in the write 535 // queue and keep track of whether we have merged or not 536 bool merged = isInWriteQueue.find(burstAlign(addr)) != 537 isInWriteQueue.end(); 538 539 // if the item was not merged we need to create a new write 540 // and enqueue it 541 if (!merged) { 542 DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, false); 543 |
529 assert(writeQueue.size() < writeBufferSize); 530 wrQLenPdf[writeQueue.size()]++; | 544 assert(totalWriteQueueSize < writeBufferSize); 545 wrQLenPdf[totalWriteQueueSize]++; |
531 532 DPRINTF(DRAM, "Adding to write queue\n"); 533 | 546 547 DPRINTF(DRAM, "Adding to write queue\n"); 548 |
534 writeQueue.push_back(dram_pkt); | 549 writeQueue[dram_pkt->qosValue()].push_back(dram_pkt); |
535 isInWriteQueue.insert(burstAlign(addr)); | 550 isInWriteQueue.insert(burstAlign(addr)); |
536 assert(writeQueue.size() == isInWriteQueue.size()); | |
537 | 551 |
552 // log packet 553 logRequest(MemCtrl::WRITE, pkt->masterId(), pkt->qosValue(), 554 dram_pkt->addr, 1); 555 556 assert(totalWriteQueueSize == isInWriteQueue.size()); 557 |
|
538 // Update stats | 558 // Update stats |
539 avgWrQLen = writeQueue.size(); | 559 avgWrQLen = totalWriteQueueSize; |
540 541 // increment write entries of the rank 542 ++dram_pkt->rankRef.writeEntries; 543 } else { 544 DPRINTF(DRAM, "Merging write burst with existing queue entry\n"); 545 546 // keep track of the fact that this burst effectively 547 // disappeared as it was merged with an existing one --- 15 unchanged lines hidden (view full) --- 563 // queue, do so now 564 if (!nextReqEvent.scheduled()) { 565 DPRINTF(DRAM, "Request scheduled immediately\n"); 566 schedule(nextReqEvent, curTick()); 567 } 568} 569 570void | 560 561 // increment write entries of the rank 562 ++dram_pkt->rankRef.writeEntries; 563 } else { 564 DPRINTF(DRAM, "Merging write burst with existing queue entry\n"); 565 566 // keep track of the fact that this burst effectively 567 // disappeared as it was merged with an existing one --- 15 unchanged lines hidden (view full) --- 583 // queue, do so now 584 if (!nextReqEvent.scheduled()) { 585 DPRINTF(DRAM, "Request scheduled immediately\n"); 586 schedule(nextReqEvent, curTick()); 587 } 588} 589 590void |
571DRAMCtrl::printQs() const { | 591DRAMCtrl::printQs() const 592{ 593#if TRACING_ON |
572 DPRINTF(DRAM, "===READ QUEUE===\n\n"); | 594 DPRINTF(DRAM, "===READ QUEUE===\n\n"); |
573 for (auto i = readQueue.begin() ; i != readQueue.end() ; ++i) { 574 DPRINTF(DRAM, "Read %lu\n", (*i)->addr); | 595 for (const auto& queue : readQueue) { 596 for (const auto& packet : queue) { 597 DPRINTF(DRAM, "Read %lu\n", packet->addr); 598 } |
575 } | 599 } |
600 |
|
576 DPRINTF(DRAM, "\n===RESP QUEUE===\n\n"); | 601 DPRINTF(DRAM, "\n===RESP QUEUE===\n\n"); |
577 for (auto i = respQueue.begin() ; i != respQueue.end() ; ++i) { 578 DPRINTF(DRAM, "Response %lu\n", (*i)->addr); | 602 for (const auto& packet : respQueue) { 603 DPRINTF(DRAM, "Response %lu\n", packet->addr); |
579 } | 604 } |
605 |
|
580 DPRINTF(DRAM, "\n===WRITE QUEUE===\n\n"); | 606 DPRINTF(DRAM, "\n===WRITE QUEUE===\n\n"); |
581 for (auto i = writeQueue.begin() ; i != writeQueue.end() ; ++i) { 582 DPRINTF(DRAM, "Write %lu\n", (*i)->addr); | 607 for (const auto& queue : writeQueue) { 608 for (const auto& packet : queue) { 609 DPRINTF(DRAM, "Write %lu\n", packet->addr); 610 } |
583 } | 611 } |
612#endif // TRACING_ON |
|
584} 585 586bool 587DRAMCtrl::recvTimingReq(PacketPtr pkt) 588{ 589 // This is where we enter from the outside world 590 DPRINTF(DRAM, "recvTimingReq: request %s addr %lld size %d\n", 591 pkt->cmdString(), pkt->getAddr(), pkt->getSize()); --- 14 unchanged lines hidden (view full) --- 606 // Find out how many dram packets a pkt translates to 607 // If the burst size is equal or larger than the pkt size, then a pkt 608 // translates to only one dram packet. Otherwise, a pkt translates to 609 // multiple dram packets 610 unsigned size = pkt->getSize(); 611 unsigned offset = pkt->getAddr() & (burstSize - 1); 612 unsigned int dram_pkt_count = divCeil(offset + size, burstSize); 613 | 613} 614 615bool 616DRAMCtrl::recvTimingReq(PacketPtr pkt) 617{ 618 // This is where we enter from the outside world 619 DPRINTF(DRAM, "recvTimingReq: request %s addr %lld size %d\n", 620 pkt->cmdString(), pkt->getAddr(), pkt->getSize()); --- 14 unchanged lines hidden (view full) --- 635 // Find out how many dram packets a pkt translates to 636 // If the burst size is equal or larger than the pkt size, then a pkt 637 // translates to only one dram packet. Otherwise, a pkt translates to 638 // multiple dram packets 639 unsigned size = pkt->getSize(); 640 unsigned offset = pkt->getAddr() & (burstSize - 1); 641 unsigned int dram_pkt_count = divCeil(offset + size, burstSize); 642 |
643 // run the QoS scheduler and assign a QoS priority value to the packet 644 qosSchedule( { &readQueue, &writeQueue }, burstSize, pkt); 645 |
|
614 // check local buffers and do not accept if full 615 if (pkt->isRead()) { 616 assert(size != 0); 617 if (readQueueFull(dram_pkt_count)) { 618 DPRINTF(DRAM, "Read queue full, not accepting\n"); 619 // remember that we have to retry this port 620 retryRdReq = true; 621 numRdRetry++; --- 94 unchanged lines hidden (view full) --- 716 717 if (!respQueue.empty()) { 718 assert(respQueue.front()->readyTime >= curTick()); 719 assert(!respondEvent.scheduled()); 720 schedule(respondEvent, respQueue.front()->readyTime); 721 } else { 722 // if there is nothing left in any queue, signal a drain 723 if (drainState() == DrainState::Draining && | 646 // check local buffers and do not accept if full 647 if (pkt->isRead()) { 648 assert(size != 0); 649 if (readQueueFull(dram_pkt_count)) { 650 DPRINTF(DRAM, "Read queue full, not accepting\n"); 651 // remember that we have to retry this port 652 retryRdReq = true; 653 numRdRetry++; --- 94 unchanged lines hidden (view full) --- 748 749 if (!respQueue.empty()) { 750 assert(respQueue.front()->readyTime >= curTick()); 751 assert(!respondEvent.scheduled()); 752 schedule(respondEvent, respQueue.front()->readyTime); 753 } else { 754 // if there is nothing left in any queue, signal a drain 755 if (drainState() == DrainState::Draining && |
724 writeQueue.empty() && readQueue.empty() && allRanksDrained()) { | 756 !totalWriteQueueSize && !totalReadQueueSize && allRanksDrained()) { |
725 726 DPRINTF(Drain, "DRAM controller done draining\n"); 727 signalDrainDone(); 728 } 729 } 730 731 // We have made a location in the queue available at this point, 732 // so if there is a read that was forced to wait, retry now 733 if (retryRdReq) { 734 retryRdReq = false; 735 port.sendRetryReq(); 736 } 737} 738 | 757 758 DPRINTF(Drain, "DRAM controller done draining\n"); 759 signalDrainDone(); 760 } 761 } 762 763 // We have made a location in the queue available at this point, 764 // so if there is a read that was forced to wait, retry now 765 if (retryRdReq) { 766 retryRdReq = false; 767 port.sendRetryReq(); 768 } 769} 770 |
739bool 740DRAMCtrl::chooseNext(std::deque<DRAMPacket*>& queue, Tick extra_col_delay) | 771DRAMCtrl::DRAMPacketQueue::iterator 772DRAMCtrl::chooseNext(DRAMPacketQueue& queue, Tick extra_col_delay) |
741{ | 773{ |
742 // This method does the arbitration between requests. The chosen 743 // packet is simply moved to the head of the queue. The other 744 // methods know that this is the place to look. For example, with 745 // FCFS, this method does nothing 746 assert(!queue.empty()); | 774 // This method does the arbitration between requests. |
747 | 775 |
748 // bool to indicate if a packet to an available rank is found 749 bool found_packet = false; 750 if (queue.size() == 1) { 751 DRAMPacket* dram_pkt = queue.front(); 752 // available rank corresponds to state refresh idle 753 if (ranks[dram_pkt->rank]->inRefIdleState()) { 754 found_packet = true; 755 DPRINTF(DRAM, "Single request, going to a free rank\n"); 756 } else { 757 DPRINTF(DRAM, "Single request, going to a busy rank\n"); 758 } 759 return found_packet; 760 } | 776 DRAMCtrl::DRAMPacketQueue::iterator ret = queue.end(); |
761 | 777 |
762 if (memSchedPolicy == Enums::fcfs) { 763 // check if there is a packet going to a free rank 764 for (auto i = queue.begin(); i != queue.end() ; ++i) { 765 DRAMPacket* dram_pkt = *i; | 778 if (!queue.empty()) { 779 if (queue.size() == 1) { 780 // available rank corresponds to state refresh idle 781 DRAMPacket* dram_pkt = *(queue.begin()); |
766 if (ranks[dram_pkt->rank]->inRefIdleState()) { | 782 if (ranks[dram_pkt->rank]->inRefIdleState()) { |
767 queue.erase(i); 768 queue.push_front(dram_pkt); 769 found_packet = true; 770 break; | 783 ret = queue.begin(); 784 DPRINTF(DRAM, "Single request, going to a free rank\n"); 785 } else { 786 DPRINTF(DRAM, "Single request, going to a busy rank\n"); |
771 } | 787 } |
788 } else if (memSchedPolicy == Enums::fcfs) { 789 // check if there is a packet going to a free rank 790 for (auto i = queue.begin(); i != queue.end(); ++i) { 791 DRAMPacket* dram_pkt = *i; 792 if (ranks[dram_pkt->rank]->inRefIdleState()) { 793 ret = i; 794 break; 795 } 796 } 797 } else if (memSchedPolicy == Enums::frfcfs) { 798 ret = chooseNextFRFCFS(queue, extra_col_delay); 799 } else { 800 panic("No scheduling policy chosen\n"); |
|
772 } | 801 } |
773 } else if (memSchedPolicy == Enums::frfcfs) { 774 found_packet = reorderQueue(queue, extra_col_delay); 775 } else 776 panic("No scheduling policy chosen\n"); 777 return found_packet; | 802 } 803 return ret; |
778} 779 | 804} 805 |
780bool 781DRAMCtrl::reorderQueue(std::deque<DRAMPacket*>& queue, Tick extra_col_delay) | 806DRAMCtrl::DRAMPacketQueue::iterator 807DRAMCtrl::chooseNextFRFCFS(DRAMPacketQueue& queue, Tick extra_col_delay) |
782{ 783 // Only determine this if needed 784 vector<uint32_t> earliest_banks(ranksPerChannel, 0); 785 786 // Has minBankPrep been called to populate earliest_banks? 787 bool filled_earliest_banks = false; 788 // can the PRE/ACT sequence be done without impacting utlization? 789 bool hidden_bank_prep = false; --- 16 unchanged lines hidden (view full) --- 806 auto selected_pkt_it = queue.end(); 807 808 // time we need to issue a column command to be seamless 809 const Tick min_col_at = std::max(nextBurstAt + extra_col_delay, curTick()); 810 811 for (auto i = queue.begin(); i != queue.end() ; ++i) { 812 DRAMPacket* dram_pkt = *i; 813 const Bank& bank = dram_pkt->bankRef; | 808{ 809 // Only determine this if needed 810 vector<uint32_t> earliest_banks(ranksPerChannel, 0); 811 812 // Has minBankPrep been called to populate earliest_banks? 813 bool filled_earliest_banks = false; 814 // can the PRE/ACT sequence be done without impacting utlization? 815 bool hidden_bank_prep = false; --- 16 unchanged lines hidden (view full) --- 832 auto selected_pkt_it = queue.end(); 833 834 // time we need to issue a column command to be seamless 835 const Tick min_col_at = std::max(nextBurstAt + extra_col_delay, curTick()); 836 837 for (auto i = queue.begin(); i != queue.end() ; ++i) { 838 DRAMPacket* dram_pkt = *i; 839 const Bank& bank = dram_pkt->bankRef; |
814 const Tick col_allowed_at = dram_pkt->isRead ? bank.rdAllowedAt : 815 bank.wrAllowedAt; | 840 const Tick col_allowed_at = dram_pkt->isRead() ? bank.rdAllowedAt : 841 bank.wrAllowedAt; |
816 | 842 |
843 DPRINTF(DRAM, "%s checking packet in bank %d\n", 844 __func__, dram_pkt->bankRef.bank); 845 |
|
817 // check if rank is not doing a refresh and thus is available, if not, 818 // jump to the next packet 819 if (dram_pkt->rankRef.inRefIdleState()) { | 846 // check if rank is not doing a refresh and thus is available, if not, 847 // jump to the next packet 848 if (dram_pkt->rankRef.inRefIdleState()) { |
849 850 DPRINTF(DRAM, 851 "%s bank %d - Rank %d available\n", __func__, 852 dram_pkt->bankRef.bank, dram_pkt->rankRef.rank); 853 |
|
820 // check if it is a row hit 821 if (bank.openRow == dram_pkt->row) { 822 // no additional rank-to-rank or same bank-group 823 // delays, or we switched read/write and might as well 824 // go for the row hit 825 if (col_allowed_at <= min_col_at) { 826 // FCFS within the hits, giving priority to 827 // commands that can issue seamlessly, without 828 // additional delay, such as same rank accesses 829 // and/or different bank-group accesses | 854 // check if it is a row hit 855 if (bank.openRow == dram_pkt->row) { 856 // no additional rank-to-rank or same bank-group 857 // delays, or we switched read/write and might as well 858 // go for the row hit 859 if (col_allowed_at <= min_col_at) { 860 // FCFS within the hits, giving priority to 861 // commands that can issue seamlessly, without 862 // additional delay, such as same rank accesses 863 // and/or different bank-group accesses |
830 DPRINTF(DRAM, "Seamless row buffer hit\n"); | 864 DPRINTF(DRAM, "%s Seamless row buffer hit\n", __func__); |
831 selected_pkt_it = i; 832 // no need to look through the remaining queue entries 833 break; 834 } else if (!found_hidden_bank && !found_prepped_pkt) { 835 // if we did not find a packet to a closed row that can 836 // issue the bank commands without incurring delay, and 837 // did not yet find a packet to a prepped row, remember 838 // the current one 839 selected_pkt_it = i; 840 found_prepped_pkt = true; | 865 selected_pkt_it = i; 866 // no need to look through the remaining queue entries 867 break; 868 } else if (!found_hidden_bank && !found_prepped_pkt) { 869 // if we did not find a packet to a closed row that can 870 // issue the bank commands without incurring delay, and 871 // did not yet find a packet to a prepped row, remember 872 // the current one 873 selected_pkt_it = i; 874 found_prepped_pkt = true; |
841 DPRINTF(DRAM, "Prepped row buffer hit\n"); | 875 DPRINTF(DRAM, "%s Prepped row buffer hit\n", __func__); |
842 } 843 } else if (!found_earliest_pkt) { 844 // if we have not initialised the bank status, do it 845 // now, and only once per scheduling decisions 846 if (!filled_earliest_banks) { 847 // determine entries with earliest bank delay 848 std::tie(earliest_banks, hidden_bank_prep) = 849 minBankPrep(queue, min_col_at); --- 11 unchanged lines hidden (view full) --- 861 // give priority to packets that can issue 862 // bank commands 'behind the scenes' 863 // any additional delay if any will be due to 864 // col-to-col command requirements 865 if (hidden_bank_prep || !found_prepped_pkt) 866 selected_pkt_it = i; 867 } 868 } | 876 } 877 } else if (!found_earliest_pkt) { 878 // if we have not initialised the bank status, do it 879 // now, and only once per scheduling decisions 880 if (!filled_earliest_banks) { 881 // determine entries with earliest bank delay 882 std::tie(earliest_banks, hidden_bank_prep) = 883 minBankPrep(queue, min_col_at); --- 11 unchanged lines hidden (view full) --- 895 // give priority to packets that can issue 896 // bank commands 'behind the scenes' 897 // any additional delay if any will be due to 898 // col-to-col command requirements 899 if (hidden_bank_prep || !found_prepped_pkt) 900 selected_pkt_it = i; 901 } 902 } |
903 } else { 904 DPRINTF(DRAM, "%s bank %d - Rank %d not available\n", __func__, 905 dram_pkt->bankRef.bank, dram_pkt->rankRef.rank); |
|
869 } 870 } 871 | 906 } 907 } 908 |
872 if (selected_pkt_it != queue.end()) { 873 DRAMPacket* selected_pkt = *selected_pkt_it; 874 queue.erase(selected_pkt_it); 875 queue.push_front(selected_pkt); 876 return true; | 909 if (selected_pkt_it == queue.end()) { 910 DPRINTF(DRAM, "%s no available ranks found\n", __func__); |
877 } 878 | 911 } 912 |
879 return false; | 913 return selected_pkt_it; |
880} 881 882void 883DRAMCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency) 884{ 885 DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr()); 886 887 bool needsResponse = pkt->needsResponse(); --- 216 unchanged lines hidden (view full) --- 1104 Tick act_tick = std::max(bank.actAllowedAt, curTick()); 1105 1106 // Record the activation and deal with all the global timing 1107 // constraints caused be a new activation (tRRD and tXAW) 1108 activateBank(rank, bank, act_tick, dram_pkt->row); 1109 } 1110 1111 // respect any constraints on the command (e.g. tRCD or tCCD) | 914} 915 916void 917DRAMCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency) 918{ 919 DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr()); 920 921 bool needsResponse = pkt->needsResponse(); --- 216 unchanged lines hidden (view full) --- 1138 Tick act_tick = std::max(bank.actAllowedAt, curTick()); 1139 1140 // Record the activation and deal with all the global timing 1141 // constraints caused be a new activation (tRRD and tXAW) 1142 activateBank(rank, bank, act_tick, dram_pkt->row); 1143 } 1144 1145 // respect any constraints on the command (e.g. tRCD or tCCD) |
1112 const Tick col_allowed_at = dram_pkt->isRead ? | 1146 const Tick col_allowed_at = dram_pkt->isRead() ? |
1113 bank.rdAllowedAt : bank.wrAllowedAt; 1114 1115 // we need to wait until the bus is available before we can issue 1116 // the command; need minimum of tBURST between commands 1117 Tick cmd_at = std::max({col_allowed_at, nextBurstAt, curTick()}); 1118 1119 // update the packet ready time 1120 dram_pkt->readyTime = cmd_at + tCL + tBURST; --- 10 unchanged lines hidden (view full) --- 1131 if (dram_pkt->rank == j) { 1132 if (bankGroupArch && 1133 (bank.bankgr == ranks[j]->banks[i].bankgr)) { 1134 // bank group architecture requires longer delays between 1135 // RD/WR burst commands to the same bank group. 1136 // tCCD_L is default requirement for same BG timing 1137 // tCCD_L_WR is required for write-to-write 1138 // Need to also take bus turnaround delays into account | 1147 bank.rdAllowedAt : bank.wrAllowedAt; 1148 1149 // we need to wait until the bus is available before we can issue 1150 // the command; need minimum of tBURST between commands 1151 Tick cmd_at = std::max({col_allowed_at, nextBurstAt, curTick()}); 1152 1153 // update the packet ready time 1154 dram_pkt->readyTime = cmd_at + tCL + tBURST; --- 10 unchanged lines hidden (view full) --- 1165 if (dram_pkt->rank == j) { 1166 if (bankGroupArch && 1167 (bank.bankgr == ranks[j]->banks[i].bankgr)) { 1168 // bank group architecture requires longer delays between 1169 // RD/WR burst commands to the same bank group. 1170 // tCCD_L is default requirement for same BG timing 1171 // tCCD_L_WR is required for write-to-write 1172 // Need to also take bus turnaround delays into account |
1139 dly_to_rd_cmd = dram_pkt->isRead ? | 1173 dly_to_rd_cmd = dram_pkt->isRead() ? |
1140 tCCD_L : std::max(tCCD_L, wrToRdDly); | 1174 tCCD_L : std::max(tCCD_L, wrToRdDly); |
1141 dly_to_wr_cmd = dram_pkt->isRead ? | 1175 dly_to_wr_cmd = dram_pkt->isRead() ? |
1142 std::max(tCCD_L, rdToWrDly) : tCCD_L_WR; 1143 } else { 1144 // tBURST is default requirement for diff BG timing 1145 // Need to also take bus turnaround delays into account | 1176 std::max(tCCD_L, rdToWrDly) : tCCD_L_WR; 1177 } else { 1178 // tBURST is default requirement for diff BG timing 1179 // Need to also take bus turnaround delays into account |
1146 dly_to_rd_cmd = dram_pkt->isRead ? tBURST : wrToRdDly; 1147 dly_to_wr_cmd = dram_pkt->isRead ? rdToWrDly : tBURST; | 1180 dly_to_rd_cmd = dram_pkt->isRead() ? tBURST : wrToRdDly; 1181 dly_to_wr_cmd = dram_pkt->isRead() ? rdToWrDly : tBURST; |
1148 } 1149 } else { 1150 // different rank is by default in a different bank group and 1151 // doesn't require longer tCCD or additional RTW, WTR delays 1152 // Need to account for rank-to-rank switching with tCS 1153 dly_to_wr_cmd = rankToRankDly; 1154 dly_to_rd_cmd = rankToRankDly; 1155 } --- 6 unchanged lines hidden (view full) --- 1162 1163 // Save rank of current access 1164 activeRank = dram_pkt->rank; 1165 1166 // If this is a write, we also need to respect the write recovery 1167 // time before a precharge, in the case of a read, respect the 1168 // read to precharge constraint 1169 bank.preAllowedAt = std::max(bank.preAllowedAt, | 1182 } 1183 } else { 1184 // different rank is by default in a different bank group and 1185 // doesn't require longer tCCD or additional RTW, WTR delays 1186 // Need to account for rank-to-rank switching with tCS 1187 dly_to_wr_cmd = rankToRankDly; 1188 dly_to_rd_cmd = rankToRankDly; 1189 } --- 6 unchanged lines hidden (view full) --- 1196 1197 // Save rank of current access 1198 activeRank = dram_pkt->rank; 1199 1200 // If this is a write, we also need to respect the write recovery 1201 // time before a precharge, in the case of a read, respect the 1202 // read to precharge constraint 1203 bank.preAllowedAt = std::max(bank.preAllowedAt, |
1170 dram_pkt->isRead ? cmd_at + tRTP : | 1204 dram_pkt->isRead() ? cmd_at + tRTP : |
1171 dram_pkt->readyTime + tWR); 1172 1173 // increment the bytes accessed and the accesses per row 1174 bank.bytesAccessed += burstSize; 1175 ++bank.rowAccesses; 1176 1177 // if we reached the max, then issue with an auto-precharge 1178 bool auto_precharge = pageMgmt == Enums::close || --- 11 unchanged lines hidden (view full) --- 1190 // 2) close_adaptive page policy does not blindly close the 1191 // page, but closes it only if there are no row hits in the queue. 1192 // In this case, only force an auto precharge when there 1193 // are no same page hits in the queue 1194 bool got_more_hits = false; 1195 bool got_bank_conflict = false; 1196 1197 // either look at the read queue or write queue | 1205 dram_pkt->readyTime + tWR); 1206 1207 // increment the bytes accessed and the accesses per row 1208 bank.bytesAccessed += burstSize; 1209 ++bank.rowAccesses; 1210 1211 // if we reached the max, then issue with an auto-precharge 1212 bool auto_precharge = pageMgmt == Enums::close || --- 11 unchanged lines hidden (view full) --- 1224 // 2) close_adaptive page policy does not blindly close the 1225 // page, but closes it only if there are no row hits in the queue. 1226 // In this case, only force an auto precharge when there 1227 // are no same page hits in the queue 1228 bool got_more_hits = false; 1229 bool got_bank_conflict = false; 1230 1231 // either look at the read queue or write queue |
1198 const deque<DRAMPacket*>& queue = dram_pkt->isRead ? readQueue : 1199 writeQueue; 1200 auto p = queue.begin(); 1201 // make sure we are not considering the packet that we are 1202 // currently dealing with (which is the head of the queue) 1203 ++p; | 1232 const std::vector<DRAMPacketQueue>& queue = 1233 dram_pkt->isRead() ? readQueue : writeQueue; |
1204 | 1234 |
1205 // keep on looking until we find a hit or reach the end of the queue 1206 // 1) if a hit is found, then both open and close adaptive policies keep 1207 // the page open 1208 // 2) if no hit is found, got_bank_conflict is set to true if a bank 1209 // conflict request is waiting in the queue 1210 while (!got_more_hits && p != queue.end()) { 1211 bool same_rank_bank = (dram_pkt->rank == (*p)->rank) && 1212 (dram_pkt->bank == (*p)->bank); 1213 bool same_row = dram_pkt->row == (*p)->row; 1214 got_more_hits |= same_rank_bank && same_row; 1215 got_bank_conflict |= same_rank_bank && !same_row; 1216 ++p; | 1235 for (uint8_t i = 0; i < numPriorities(); ++i) { 1236 auto p = queue[i].begin(); 1237 // keep on looking until we find a hit or reach the end of the queue 1238 // 1) if a hit is found, then both open and close adaptive policies keep 1239 // the page open 1240 // 2) if no hit is found, got_bank_conflict is set to true if a bank 1241 // conflict request is waiting in the queue 1242 // 3) make sure we are not considering the packet that we are 1243 // currently dealing with 1244 while (!got_more_hits && p != queue[i].end()) { 1245 if (dram_pkt != (*p)) { 1246 bool same_rank_bank = (dram_pkt->rank == (*p)->rank) && 1247 (dram_pkt->bank == (*p)->bank); 1248 1249 bool same_row = dram_pkt->row == (*p)->row; 1250 got_more_hits |= same_rank_bank && same_row; 1251 got_bank_conflict |= same_rank_bank && !same_row; 1252 } 1253 ++p; 1254 } 1255 1256 if (got_more_hits) 1257 break; |
1217 } 1218 1219 // auto pre-charge when either 1220 // 1) open_adaptive policy, we have not got any more hits, and 1221 // have a bank conflict 1222 // 2) close_adaptive policy and we have not got any more hits 1223 auto_precharge = !got_more_hits && 1224 (got_bank_conflict || pageMgmt == Enums::close_adaptive); 1225 } 1226 1227 // DRAMPower trace command to be written | 1258 } 1259 1260 // auto pre-charge when either 1261 // 1) open_adaptive policy, we have not got any more hits, and 1262 // have a bank conflict 1263 // 2) close_adaptive policy and we have not got any more hits 1264 auto_precharge = !got_more_hits && 1265 (got_bank_conflict || pageMgmt == Enums::close_adaptive); 1266 } 1267 1268 // DRAMPower trace command to be written |
1228 std::string mem_cmd = dram_pkt->isRead ? "RD" : "WR"; | 1269 std::string mem_cmd = dram_pkt->isRead() ? "RD" : "WR"; |
1229 1230 // MemCommand required for DRAMPower library 1231 MemCommand::cmds command = (mem_cmd == "RD") ? MemCommand::RD : 1232 MemCommand::WR; 1233 1234 // Update bus state to reflect when previous command was issued 1235 nextBurstAt = cmd_at + tBURST; 1236 --- 18 unchanged lines hidden (view full) --- 1255 1256 // Update the minimum timing between the requests, this is a 1257 // conservative estimate of when we have to schedule the next 1258 // request to not introduce any unecessary bubbles. In most cases 1259 // we will wake up sooner than we have to. 1260 nextReqTime = nextBurstAt - (tRP + tRCD); 1261 1262 // Update the stats and schedule the next request | 1270 1271 // MemCommand required for DRAMPower library 1272 MemCommand::cmds command = (mem_cmd == "RD") ? MemCommand::RD : 1273 MemCommand::WR; 1274 1275 // Update bus state to reflect when previous command was issued 1276 nextBurstAt = cmd_at + tBURST; 1277 --- 18 unchanged lines hidden (view full) --- 1296 1297 // Update the minimum timing between the requests, this is a 1298 // conservative estimate of when we have to schedule the next 1299 // request to not introduce any unecessary bubbles. In most cases 1300 // we will wake up sooner than we have to. 1301 nextReqTime = nextBurstAt - (tRP + tRCD); 1302 1303 // Update the stats and schedule the next request |
1263 if (dram_pkt->isRead) { | 1304 if (dram_pkt->isRead()) { |
1264 ++readsThisTime; 1265 if (row_hit) 1266 readRowHits++; 1267 bytesReadDRAM += burstSize; 1268 perBankRdBursts[dram_pkt->bankId]++; 1269 1270 // Update latency stats 1271 totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime; | 1305 ++readsThisTime; 1306 if (row_hit) 1307 readRowHits++; 1308 bytesReadDRAM += burstSize; 1309 perBankRdBursts[dram_pkt->bankId]++; 1310 1311 // Update latency stats 1312 totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime; |
1313 masterReadTotalLat[dram_pkt->masterId()] += 1314 dram_pkt->readyTime - dram_pkt->entryTime; 1315 |
|
1272 totBusLat += tBURST; 1273 totQLat += cmd_at - dram_pkt->entryTime; | 1316 totBusLat += tBURST; 1317 totQLat += cmd_at - dram_pkt->entryTime; |
1318 masterReadBytes[dram_pkt->masterId()] += dram_pkt->size; |
|
1274 } else { 1275 ++writesThisTime; 1276 if (row_hit) 1277 writeRowHits++; 1278 bytesWritten += burstSize; 1279 perBankWrBursts[dram_pkt->bankId]++; | 1319 } else { 1320 ++writesThisTime; 1321 if (row_hit) 1322 writeRowHits++; 1323 bytesWritten += burstSize; 1324 perBankWrBursts[dram_pkt->bankId]++; |
1325 masterWriteBytes[dram_pkt->masterId()] += dram_pkt->size; 1326 masterWriteTotalLat[dram_pkt->masterId()] += 1327 dram_pkt->readyTime - dram_pkt->entryTime; |
|
1280 } 1281} 1282 1283void 1284DRAMCtrl::processNextReqEvent() 1285{ | 1328 } 1329} 1330 1331void 1332DRAMCtrl::processNextReqEvent() 1333{ |
1334 // transition is handled by QoS algorithm if enabled 1335 if (turnPolicy) { 1336 // select bus state - only done if QoS algorithms are in use 1337 busStateNext = selectNextBusState(); 1338 } 1339 1340 // detect bus state change 1341 bool switched_cmd_type = (busState != busStateNext); 1342 // record stats 1343 recordTurnaroundStats(); 1344 1345 DPRINTF(DRAM, "QoS Turnarounds selected state %s %s\n", 1346 (busState==MemCtrl::READ)?"READ":"WRITE", 1347 switched_cmd_type?"[turnaround triggered]":""); 1348 1349 if (switched_cmd_type) { 1350 if (busState == READ) { 1351 DPRINTF(DRAM, 1352 "Switching to writes after %d reads with %d reads " 1353 "waiting\n", readsThisTime, totalReadQueueSize); 1354 rdPerTurnAround.sample(readsThisTime); 1355 readsThisTime = 0; 1356 } else { 1357 DPRINTF(DRAM, 1358 "Switching to reads after %d writes with %d writes " 1359 "waiting\n", writesThisTime, totalWriteQueueSize); 1360 wrPerTurnAround.sample(writesThisTime); 1361 writesThisTime = 0; 1362 } 1363 } 1364 1365 // updates current state 1366 busState = busStateNext; 1367 1368 // check ranks for refresh/wakeup - uses busStateNext, so done after turnaround 1369 // decisions |
|
1286 int busyRanks = 0; 1287 for (auto r : ranks) { 1288 if (!r->inRefIdleState()) { 1289 if (r->pwrState != PWR_SREF) { 1290 // rank is busy refreshing 1291 DPRINTF(DRAMState, "Rank %d is not available\n", r->rank); 1292 busyRanks++; 1293 --- 24 unchanged lines hidden (view full) --- 1318 1319 if (busyRanks == ranksPerChannel) { 1320 // if all ranks are refreshing wait for them to finish 1321 // and stall this state machine without taking any further 1322 // action, and do not schedule a new nextReqEvent 1323 return; 1324 } 1325 | 1370 int busyRanks = 0; 1371 for (auto r : ranks) { 1372 if (!r->inRefIdleState()) { 1373 if (r->pwrState != PWR_SREF) { 1374 // rank is busy refreshing 1375 DPRINTF(DRAMState, "Rank %d is not available\n", r->rank); 1376 busyRanks++; 1377 --- 24 unchanged lines hidden (view full) --- 1402 1403 if (busyRanks == ranksPerChannel) { 1404 // if all ranks are refreshing wait for them to finish 1405 // and stall this state machine without taking any further 1406 // action, and do not schedule a new nextReqEvent 1407 return; 1408 } 1409 |
1326 // pre-emptively set to false. Overwrite if in transitioning to 1327 // a new state 1328 bool switched_cmd_type = false; 1329 if (busState != busStateNext) { 1330 if (busState == READ) { 1331 DPRINTF(DRAM, "Switching to writes after %d reads with %d reads " 1332 "waiting\n", readsThisTime, readQueue.size()); 1333 1334 // sample and reset the read-related stats as we are now 1335 // transitioning to writes, and all reads are done 1336 rdPerTurnAround.sample(readsThisTime); 1337 readsThisTime = 0; 1338 1339 // now proceed to do the actual writes 1340 switched_cmd_type = true; 1341 } else { 1342 DPRINTF(DRAM, "Switching to reads after %d writes with %d writes " 1343 "waiting\n", writesThisTime, writeQueue.size()); 1344 1345 wrPerTurnAround.sample(writesThisTime); 1346 writesThisTime = 0; 1347 1348 switched_cmd_type = true; 1349 } 1350 // update busState to match next state until next transition 1351 busState = busStateNext; 1352 } 1353 | |
1354 // when we get here it is either a read or a write 1355 if (busState == READ) { 1356 1357 // track if we should switch or not 1358 bool switch_to_writes = false; 1359 | 1410 // when we get here it is either a read or a write 1411 if (busState == READ) { 1412 1413 // track if we should switch or not 1414 bool switch_to_writes = false; 1415 |
1360 if (readQueue.empty()) { | 1416 if (totalReadQueueSize == 0) { |
1361 // In the case there is no read request to go next, 1362 // trigger writes if we have passed the low threshold (or 1363 // if we are draining) | 1417 // In the case there is no read request to go next, 1418 // trigger writes if we have passed the low threshold (or 1419 // if we are draining) |
1364 if (!writeQueue.empty() && | 1420 if (!(totalWriteQueueSize == 0) && |
1365 (drainState() == DrainState::Draining || | 1421 (drainState() == DrainState::Draining || |
1366 writeQueue.size() > writeLowThreshold)) { | 1422 totalWriteQueueSize > writeLowThreshold)) { |
1367 | 1423 |
1424 DPRINTF(DRAM, "Switching to writes due to read queue empty\n"); |
|
1368 switch_to_writes = true; 1369 } else { 1370 // check if we are drained 1371 // not done draining until in PWR_IDLE state 1372 // ensuring all banks are closed and 1373 // have exited low power states 1374 if (drainState() == DrainState::Draining && 1375 respQueue.empty() && allRanksDrained()) { 1376 1377 DPRINTF(Drain, "DRAM controller done draining\n"); 1378 signalDrainDone(); 1379 } 1380 1381 // nothing to do, not even any point in scheduling an 1382 // event for the next request 1383 return; 1384 } 1385 } else { | 1425 switch_to_writes = true; 1426 } else { 1427 // check if we are drained 1428 // not done draining until in PWR_IDLE state 1429 // ensuring all banks are closed and 1430 // have exited low power states 1431 if (drainState() == DrainState::Draining && 1432 respQueue.empty() && allRanksDrained()) { 1433 1434 DPRINTF(Drain, "DRAM controller done draining\n"); 1435 signalDrainDone(); 1436 } 1437 1438 // nothing to do, not even any point in scheduling an 1439 // event for the next request 1440 return; 1441 } 1442 } else { |
1386 // bool to check if there is a read to a free rank 1387 bool found_read = false; | |
1388 | 1443 |
1389 // Figure out which read request goes next, and move it to the 1390 // front of the read queue 1391 // If we are changing command type, incorporate the minimum 1392 // bus turnaround delay which will be tCS (different rank) case 1393 found_read = chooseNext(readQueue, switched_cmd_type ? tCS : 0); | 1444 bool read_found = false; 1445 DRAMPacketQueue::iterator to_read; 1446 uint8_t prio = numPriorities(); |
1394 | 1447 |
1448 for (auto queue = readQueue.rbegin(); 1449 queue != readQueue.rend(); ++queue) { 1450 1451 prio--; 1452 1453 DPRINTF(QOS, 1454 "DRAM controller checking READ queue [%d] priority [%d elements]\n", 1455 prio, queue->size()); 1456 1457 // Figure out which read request goes next 1458 // If we are changing command type, incorporate the minimum 1459 // bus turnaround delay which will be tCS (different rank) case 1460 to_read = chooseNext((*queue), switched_cmd_type ? tCS : 0); 1461 1462 if (to_read != queue->end()) { 1463 // candidate read found 1464 read_found = true; 1465 break; 1466 } 1467 } 1468 |
|
1395 // if no read to an available rank is found then return 1396 // at this point. There could be writes to the available ranks 1397 // which are above the required threshold. However, to 1398 // avoid adding more complexity to the code, return and wait 1399 // for a refresh event to kick things into action again. | 1469 // if no read to an available rank is found then return 1470 // at this point. There could be writes to the available ranks 1471 // which are above the required threshold. However, to 1472 // avoid adding more complexity to the code, return and wait 1473 // for a refresh event to kick things into action again. |
1400 if (!found_read) | 1474 if (!read_found) { 1475 DPRINTF(DRAM, "No Reads Found - exiting\n"); |
1401 return; | 1476 return; |
1477 } |
|
1402 | 1478 |
1403 DRAMPacket* dram_pkt = readQueue.front(); | 1479 auto dram_pkt = *to_read; 1480 |
1404 assert(dram_pkt->rankRef.inRefIdleState()); 1405 1406 doDRAMAccess(dram_pkt); 1407 | 1481 assert(dram_pkt->rankRef.inRefIdleState()); 1482 1483 doDRAMAccess(dram_pkt); 1484 |
1408 // At this point we're done dealing with the request 1409 readQueue.pop_front(); 1410 | |
1411 // Every respQueue which will generate an event, increment count 1412 ++dram_pkt->rankRef.outstandingEvents; | 1485 // Every respQueue which will generate an event, increment count 1486 ++dram_pkt->rankRef.outstandingEvents; |
1413 | |
1414 // sanity check 1415 assert(dram_pkt->size <= burstSize); 1416 assert(dram_pkt->readyTime >= curTick()); 1417 | 1487 // sanity check 1488 assert(dram_pkt->size <= burstSize); 1489 assert(dram_pkt->readyTime >= curTick()); 1490 |
1491 // log the response 1492 logResponse(MemCtrl::READ, (*to_read)->masterId(), 1493 dram_pkt->qosValue(), dram_pkt->getAddr(), 1, 1494 dram_pkt->readyTime - dram_pkt->entryTime); 1495 1496 |
|
1418 // Insert into response queue. It will be sent back to the | 1497 // Insert into response queue. It will be sent back to the |
1419 // requestor at its readyTime | 1498 // requester at its readyTime |
1420 if (respQueue.empty()) { 1421 assert(!respondEvent.scheduled()); 1422 schedule(respondEvent, dram_pkt->readyTime); 1423 } else { 1424 assert(respQueue.back()->readyTime <= dram_pkt->readyTime); 1425 assert(respondEvent.scheduled()); 1426 } 1427 1428 respQueue.push_back(dram_pkt); 1429 1430 // we have so many writes that we have to transition | 1499 if (respQueue.empty()) { 1500 assert(!respondEvent.scheduled()); 1501 schedule(respondEvent, dram_pkt->readyTime); 1502 } else { 1503 assert(respQueue.back()->readyTime <= dram_pkt->readyTime); 1504 assert(respondEvent.scheduled()); 1505 } 1506 1507 respQueue.push_back(dram_pkt); 1508 1509 // we have so many writes that we have to transition |
1431 if (writeQueue.size() > writeHighThreshold) { | 1510 if (totalWriteQueueSize > writeHighThreshold) { |
1432 switch_to_writes = true; 1433 } | 1511 switch_to_writes = true; 1512 } |
1513 1514 // remove the request from the queue - the iterator is no longer valid . 1515 readQueue[dram_pkt->qosValue()].erase(to_read); |
|
1434 } 1435 1436 // switching to writes, either because the read queue is empty 1437 // and the writes have passed the low threshold (or we are 1438 // draining), or because the writes hit the hight threshold 1439 if (switch_to_writes) { 1440 // transition to writing 1441 busStateNext = WRITE; 1442 } 1443 } else { | 1516 } 1517 1518 // switching to writes, either because the read queue is empty 1519 // and the writes have passed the low threshold (or we are 1520 // draining), or because the writes hit the hight threshold 1521 if (switch_to_writes) { 1522 // transition to writing 1523 busStateNext = WRITE; 1524 } 1525 } else { |
1444 // bool to check if write to free rank is found 1445 bool found_write = false; | |
1446 | 1526 |
1447 // If we are changing command type, incorporate the minimum 1448 // bus turnaround delay 1449 found_write = chooseNext(writeQueue, 1450 switched_cmd_type ? std::min(tRTW, tCS) : 0); | 1527 bool write_found = false; 1528 DRAMPacketQueue::iterator to_write; 1529 uint8_t prio = numPriorities(); |
1451 | 1530 |
1531 for (auto queue = writeQueue.rbegin(); 1532 queue != writeQueue.rend(); ++queue) { 1533 1534 prio--; 1535 1536 DPRINTF(QOS, 1537 "DRAM controller checking WRITE queue [%d] priority [%d elements]\n", 1538 prio, queue->size()); 1539 1540 // If we are changing command type, incorporate the minimum 1541 // bus turnaround delay 1542 to_write = chooseNext((*queue), 1543 switched_cmd_type ? std::min(tRTW, tCS) : 0); 1544 1545 if (to_write != queue->end()) { 1546 write_found = true; 1547 break; 1548 } 1549 } 1550 |
|
1452 // if there are no writes to a rank that is available to service 1453 // requests (i.e. rank is in refresh idle state) are found then 1454 // return. There could be reads to the available ranks. However, to 1455 // avoid adding more complexity to the code, return at this point and 1456 // wait for a refresh event to kick things into action again. | 1551 // if there are no writes to a rank that is available to service 1552 // requests (i.e. rank is in refresh idle state) are found then 1553 // return. There could be reads to the available ranks. However, to 1554 // avoid adding more complexity to the code, return at this point and 1555 // wait for a refresh event to kick things into action again. |
1457 if (!found_write) | 1556 if (!write_found) { 1557 DPRINTF(DRAM, "No Writes Found - exiting\n"); |
1458 return; | 1558 return; |
1559 } |
|
1459 | 1560 |
1460 DRAMPacket* dram_pkt = writeQueue.front(); | 1561 auto dram_pkt = *to_write; 1562 |
1461 assert(dram_pkt->rankRef.inRefIdleState()); 1462 // sanity check 1463 assert(dram_pkt->size <= burstSize); 1464 1465 doDRAMAccess(dram_pkt); 1466 | 1563 assert(dram_pkt->rankRef.inRefIdleState()); 1564 // sanity check 1565 assert(dram_pkt->size <= burstSize); 1566 1567 doDRAMAccess(dram_pkt); 1568 |
1467 writeQueue.pop_front(); 1468 | |
1469 // removed write from queue, decrement count 1470 --dram_pkt->rankRef.writeEntries; 1471 1472 // Schedule write done event to decrement event count 1473 // after the readyTime has been reached 1474 // Only schedule latest write event to minimize events 1475 // required; only need to ensure that final event scheduled covers 1476 // the time that writes are outstanding and bus is active 1477 // to holdoff power-down entry events 1478 if (!dram_pkt->rankRef.writeDoneEvent.scheduled()) { 1479 schedule(dram_pkt->rankRef.writeDoneEvent, dram_pkt->readyTime); 1480 // New event, increment count 1481 ++dram_pkt->rankRef.outstandingEvents; 1482 1483 } else if (dram_pkt->rankRef.writeDoneEvent.when() < | 1569 // removed write from queue, decrement count 1570 --dram_pkt->rankRef.writeEntries; 1571 1572 // Schedule write done event to decrement event count 1573 // after the readyTime has been reached 1574 // Only schedule latest write event to minimize events 1575 // required; only need to ensure that final event scheduled covers 1576 // the time that writes are outstanding and bus is active 1577 // to holdoff power-down entry events 1578 if (!dram_pkt->rankRef.writeDoneEvent.scheduled()) { 1579 schedule(dram_pkt->rankRef.writeDoneEvent, dram_pkt->readyTime); 1580 // New event, increment count 1581 ++dram_pkt->rankRef.outstandingEvents; 1582 1583 } else if (dram_pkt->rankRef.writeDoneEvent.when() < |
1484 dram_pkt-> readyTime) { | 1584 dram_pkt->readyTime) { 1585 |
1485 reschedule(dram_pkt->rankRef.writeDoneEvent, dram_pkt->readyTime); 1486 } 1487 1488 isInWriteQueue.erase(burstAlign(dram_pkt->addr)); | 1586 reschedule(dram_pkt->rankRef.writeDoneEvent, dram_pkt->readyTime); 1587 } 1588 1589 isInWriteQueue.erase(burstAlign(dram_pkt->addr)); |
1590 1591 // log the response 1592 logResponse(MemCtrl::WRITE, dram_pkt->masterId(), 1593 dram_pkt->qosValue(), dram_pkt->getAddr(), 1, 1594 dram_pkt->readyTime - dram_pkt->entryTime); 1595 1596 1597 // remove the request from the queue - the iterator is no longer valid 1598 writeQueue[dram_pkt->qosValue()].erase(to_write); 1599 |
|
1489 delete dram_pkt; 1490 1491 // If we emptied the write queue, or got sufficiently below the 1492 // threshold (using the minWritesPerSwitch as the hysteresis) and 1493 // are not draining, or we have reads waiting and have done enough 1494 // writes, then switch to reads. | 1600 delete dram_pkt; 1601 1602 // If we emptied the write queue, or got sufficiently below the 1603 // threshold (using the minWritesPerSwitch as the hysteresis) and 1604 // are not draining, or we have reads waiting and have done enough 1605 // writes, then switch to reads. |
1495 if (writeQueue.empty() || 1496 (writeQueue.size() + minWritesPerSwitch < writeLowThreshold && 1497 drainState() != DrainState::Draining) || 1498 (!readQueue.empty() && writesThisTime >= minWritesPerSwitch)) { | 1606 bool below_threshold = 1607 totalWriteQueueSize + minWritesPerSwitch < writeLowThreshold; 1608 1609 if (totalWriteQueueSize == 0 || 1610 (below_threshold && drainState() != DrainState::Draining) || 1611 (totalReadQueueSize && writesThisTime >= minWritesPerSwitch)) { 1612 |
1499 // turn the bus back around for reads again 1500 busStateNext = READ; 1501 1502 // note that the we switch back to reads also in the idle 1503 // case, which eventually will check for any draining and 1504 // also pause any further scheduling if there is really 1505 // nothing to do 1506 } 1507 } 1508 // It is possible that a refresh to another rank kicks things back into 1509 // action before reaching this point. 1510 if (!nextReqEvent.scheduled()) 1511 schedule(nextReqEvent, std::max(nextReqTime, curTick())); 1512 1513 // If there is space available and we have writes waiting then let 1514 // them retry. This is done here to ensure that the retry does not 1515 // cause a nextReqEvent to be scheduled before we do so as part of 1516 // the next request processing | 1613 // turn the bus back around for reads again 1614 busStateNext = READ; 1615 1616 // note that the we switch back to reads also in the idle 1617 // case, which eventually will check for any draining and 1618 // also pause any further scheduling if there is really 1619 // nothing to do 1620 } 1621 } 1622 // It is possible that a refresh to another rank kicks things back into 1623 // action before reaching this point. 1624 if (!nextReqEvent.scheduled()) 1625 schedule(nextReqEvent, std::max(nextReqTime, curTick())); 1626 1627 // If there is space available and we have writes waiting then let 1628 // them retry. This is done here to ensure that the retry does not 1629 // cause a nextReqEvent to be scheduled before we do so as part of 1630 // the next request processing |
1517 if (retryWrReq && writeQueue.size() < writeBufferSize) { | 1631 if (retryWrReq && totalWriteQueueSize < writeBufferSize) { |
1518 retryWrReq = false; 1519 port.sendRetryReq(); 1520 } 1521} 1522 1523pair<vector<uint32_t>, bool> | 1632 retryWrReq = false; 1633 port.sendRetryReq(); 1634 } 1635} 1636 1637pair<vector<uint32_t>, bool> |
1524DRAMCtrl::minBankPrep(const deque<DRAMPacket*>& queue, | 1638DRAMCtrl::minBankPrep(const DRAMPacketQueue& queue, |
1525 Tick min_col_at) const 1526{ 1527 Tick min_act_at = MaxTick; 1528 vector<uint32_t> bank_mask(ranksPerChannel, 0); 1529 1530 // latest Tick for which ACT can occur without incurring additoinal 1531 // delay on the data bus 1532 const Tick hidden_act_max = std::max(min_col_at - tRCD, curTick()); --- 848 unchanged lines hidden (view full) --- 2381 Stats::registerDumpCallback(new RankDumpCallback(this)); 2382 Stats::registerResetCallback(new RankResetCallback(this)); 2383} 2384void 2385DRAMCtrl::regStats() 2386{ 2387 using namespace Stats; 2388 | 1639 Tick min_col_at) const 1640{ 1641 Tick min_act_at = MaxTick; 1642 vector<uint32_t> bank_mask(ranksPerChannel, 0); 1643 1644 // latest Tick for which ACT can occur without incurring additoinal 1645 // delay on the data bus 1646 const Tick hidden_act_max = std::max(min_col_at - tRCD, curTick()); --- 848 unchanged lines hidden (view full) --- 2495 Stats::registerDumpCallback(new RankDumpCallback(this)); 2496 Stats::registerResetCallback(new RankResetCallback(this)); 2497} 2498void 2499DRAMCtrl::regStats() 2500{ 2501 using namespace Stats; 2502 |
2389 AbstractMemory::regStats(); | 2503 MemCtrl::regStats(); |
2390 2391 for (auto r : ranks) { 2392 r->regStats(); 2393 } 2394 2395 registerResetCallback(new MemResetCallback(this)); 2396 2397 readReqs --- 126 unchanged lines hidden (view full) --- 2524 .desc("What read queue length does an incoming req see"); 2525 2526 wrQLenPdf 2527 .init(writeBufferSize) 2528 .name(name() + ".wrQLenPdf") 2529 .desc("What write queue length does an incoming req see"); 2530 2531 bytesPerActivate | 2504 2505 for (auto r : ranks) { 2506 r->regStats(); 2507 } 2508 2509 registerResetCallback(new MemResetCallback(this)); 2510 2511 readReqs --- 126 unchanged lines hidden (view full) --- 2638 .desc("What read queue length does an incoming req see"); 2639 2640 wrQLenPdf 2641 .init(writeBufferSize) 2642 .name(name() + ".wrQLenPdf") 2643 .desc("What write queue length does an incoming req see"); 2644 2645 bytesPerActivate |
2532 .init(maxAccessesPerRow) | 2646 .init(maxAccessesPerRow ? maxAccessesPerRow : rowBufferSize) |
2533 .name(name() + ".bytesPerActivate") 2534 .desc("Bytes accessed per row activation") 2535 .flags(nozero); 2536 2537 rdPerTurnAround 2538 .init(readBufferSize) 2539 .name(name() + ".rdPerTurnAround") 2540 .desc("Reads before turning the bus around for writes") --- 94 unchanged lines hidden (view full) --- 2635 2636 pageHitRate 2637 .name(name() + ".pageHitRate") 2638 .desc("Row buffer hit rate, read and write combined") 2639 .precision(2); 2640 2641 pageHitRate = (writeRowHits + readRowHits) / 2642 (writeBursts - mergedWrBursts + readBursts - servicedByWrQ) * 100; | 2647 .name(name() + ".bytesPerActivate") 2648 .desc("Bytes accessed per row activation") 2649 .flags(nozero); 2650 2651 rdPerTurnAround 2652 .init(readBufferSize) 2653 .name(name() + ".rdPerTurnAround") 2654 .desc("Reads before turning the bus around for writes") --- 94 unchanged lines hidden (view full) --- 2749 2750 pageHitRate 2751 .name(name() + ".pageHitRate") 2752 .desc("Row buffer hit rate, read and write combined") 2753 .precision(2); 2754 2755 pageHitRate = (writeRowHits + readRowHits) / 2756 (writeBursts - mergedWrBursts + readBursts - servicedByWrQ) * 100; |
2757 2758 // per-master bytes read and written to memory 2759 masterReadBytes 2760 .init(_system->maxMasters()) 2761 .name(name() + ".masterReadBytes") 2762 .desc("Per-master bytes read from memory") 2763 .flags(nozero | nonan); 2764 2765 masterWriteBytes 2766 .init(_system->maxMasters()) 2767 .name(name() + ".masterWriteBytes") 2768 .desc("Per-master bytes write to memory") 2769 .flags(nozero | nonan); 2770 2771 // per-master bytes read and written to memory rate 2772 masterReadRate.name(name() + ".masterReadRate") 2773 .desc("Per-master bytes read from memory rate (Bytes/sec)") 2774 .flags(nozero | nonan) 2775 .precision(12); 2776 2777 masterReadRate = masterReadBytes/simSeconds; 2778 2779 masterWriteRate 2780 .name(name() + ".masterWriteRate") 2781 .desc("Per-master bytes write to memory rate (Bytes/sec)") 2782 .flags(nozero | nonan) 2783 .precision(12); 2784 2785 masterWriteRate = masterWriteBytes/simSeconds; 2786 2787 masterReadAccesses 2788 .init(_system->maxMasters()) 2789 .name(name() + ".masterReadAccesses") 2790 .desc("Per-master read serviced memory accesses") 2791 .flags(nozero); 2792 2793 masterWriteAccesses 2794 .init(_system->maxMasters()) 2795 .name(name() + ".masterWriteAccesses") 2796 .desc("Per-master write serviced memory accesses") 2797 .flags(nozero); 2798 2799 2800 masterReadTotalLat 2801 .init(_system->maxMasters()) 2802 .name(name() + ".masterReadTotalLat") 2803 .desc("Per-master read total memory access latency") 2804 .flags(nozero | nonan); 2805 2806 masterReadAvgLat.name(name() + ".masterReadAvgLat") 2807 .desc("Per-master read average memory access latency") 2808 .flags(nonan) 2809 .precision(2); 2810 2811 masterReadAvgLat = masterReadTotalLat/masterReadAccesses; 2812 2813 masterWriteTotalLat 2814 .init(_system->maxMasters()) 2815 .name(name() + ".masterWriteTotalLat") 2816 .desc("Per-master write total memory access latency") 2817 .flags(nozero | nonan); 2818 2819 masterWriteAvgLat.name(name() + ".masterWriteAvgLat") 2820 .desc("Per-master write average memory access latency") 2821 .flags(nonan) 2822 .precision(2); 2823 2824 masterWriteAvgLat = masterWriteTotalLat/masterWriteAccesses; 2825 2826 for (int i = 0; i < _system->maxMasters(); i++) { 2827 const std::string master = _system->getMasterName(i); 2828 masterReadBytes.subname(i, master); 2829 masterReadRate.subname(i, master); 2830 masterWriteBytes.subname(i, master); 2831 masterWriteRate.subname(i, master); 2832 masterReadAccesses.subname(i, master); 2833 masterWriteAccesses.subname(i, master); 2834 masterReadTotalLat.subname(i, master); 2835 masterReadAvgLat.subname(i, master); 2836 masterWriteTotalLat.subname(i, master); 2837 masterWriteAvgLat.subname(i, master); 2838 } |
|
2643} 2644 2645void 2646DRAMCtrl::recvFunctional(PacketPtr pkt) 2647{ 2648 // rely on the abstract memory 2649 functionalAccess(pkt); 2650} --- 8 unchanged lines hidden (view full) --- 2659 } 2660} 2661 2662DrainState 2663DRAMCtrl::drain() 2664{ 2665 // if there is anything in any of our internal queues, keep track 2666 // of that as well | 2839} 2840 2841void 2842DRAMCtrl::recvFunctional(PacketPtr pkt) 2843{ 2844 // rely on the abstract memory 2845 functionalAccess(pkt); 2846} --- 8 unchanged lines hidden (view full) --- 2855 } 2856} 2857 2858DrainState 2859DRAMCtrl::drain() 2860{ 2861 // if there is anything in any of our internal queues, keep track 2862 // of that as well |
2667 if (!(writeQueue.empty() && readQueue.empty() && respQueue.empty() && | 2863 if (!(!totalWriteQueueSize && !totalReadQueueSize && respQueue.empty() && |
2668 allRanksDrained())) { 2669 2670 DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d," | 2864 allRanksDrained())) { 2865 2866 DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d," |
2671 " resp: %d\n", writeQueue.size(), readQueue.size(), | 2867 " resp: %d\n", totalWriteQueueSize, totalReadQueueSize, |
2672 respQueue.size()); 2673 2674 // the only queue that is not drained automatically over time 2675 // is the write queue, thus kick things into action if needed | 2868 respQueue.size()); 2869 2870 // the only queue that is not drained automatically over time 2871 // is the write queue, thus kick things into action if needed |
2676 if (!writeQueue.empty() && !nextReqEvent.scheduled()) { | 2872 if (!totalWriteQueueSize && !nextReqEvent.scheduled()) { |
2677 schedule(nextReqEvent, curTick()); 2678 } 2679 2680 // also need to kick off events to exit self-refresh 2681 for (auto r : ranks) { 2682 // force self-refresh exit, which in turn will issue auto-refresh 2683 if (r->pwrState == PWR_SREF) { 2684 DPRINTF(DRAM,"Rank%d: Forcing self-refresh wakeup in drain\n", --- 91 unchanged lines hidden --- | 2873 schedule(nextReqEvent, curTick()); 2874 } 2875 2876 // also need to kick off events to exit self-refresh 2877 for (auto r : ranks) { 2878 // force self-refresh exit, which in turn will issue auto-refresh 2879 if (r->pwrState == PWR_SREF) { 2880 DPRINTF(DRAM,"Rank%d: Forcing self-refresh wakeup in drain\n", --- 91 unchanged lines hidden --- |