dram_ctrl.hh revision 9831
1/* 2 * Copyright (c) 2012 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 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2013 Amin Farmahini-Farahani 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Andreas Hansson 41 * Ani Udipi 42 */ 43 44/** 45 * @file 46 * SimpleDRAM declaration 47 */ 48 49#ifndef __MEM_SIMPLE_DRAM_HH__ 50#define __MEM_SIMPLE_DRAM_HH__ 51 52#include <deque> 53 54#include "base/statistics.hh" 55#include "enums/AddrMap.hh" 56#include "enums/MemSched.hh" 57#include "enums/PageManage.hh" 58#include "mem/abstract_mem.hh" 59#include "mem/qport.hh" 60#include "params/SimpleDRAM.hh" 61#include "sim/eventq.hh" 62 63/** 64 * The simple DRAM is a basic single-channel memory controller aiming 65 * to mimic a high-level DRAM controller and the most important timing 66 * constraints associated with the DRAM. The focus is really on 67 * modelling the impact on the system rather than the DRAM itself, 68 * hence the focus is on the controller model and not on the 69 * memory. By adhering to the correct timing constraints, ultimately 70 * there is no need for a memory model in addition to the controller 71 * model. 72 * 73 * As a basic design principle, this controller is not cycle callable, 74 * but instead uses events to decide when new decisions can be made, 75 * when resources become available, when things are to be considered 76 * done, and when to send things back. Through these simple 77 * principles, we achieve a performant model that is not 78 * cycle-accurate, but enables us to evaluate the system impact of a 79 * wide range of memory technologies, and also collect statistics 80 * about the use of the memory. 81 */ 82class SimpleDRAM : public AbstractMemory 83{ 84 85 private: 86 87 // For now, make use of a queued slave port to avoid dealing with 88 // flow control for the responses being sent back 89 class MemoryPort : public QueuedSlavePort 90 { 91 92 SlavePacketQueue queue; 93 SimpleDRAM& memory; 94 95 public: 96 97 MemoryPort(const std::string& name, SimpleDRAM& _memory); 98 99 protected: 100 101 Tick recvAtomic(PacketPtr pkt); 102 103 void recvFunctional(PacketPtr pkt); 104 105 bool recvTimingReq(PacketPtr); 106 107 virtual AddrRangeList getAddrRanges() const; 108 109 }; 110 111 /** 112 * Our incoming port, for a multi-ported controller add a crossbar 113 * in front of it 114 */ 115 MemoryPort port; 116 117 /** 118 * Remember if we have to retry a request when available. 119 */ 120 bool retryRdReq; 121 bool retryWrReq; 122 123 /** 124 * Remember that a row buffer hit occured 125 */ 126 bool rowHitFlag; 127 128 /** 129 * Use this flag to shutoff reads, i.e. do not schedule any reads 130 * beyond those already done so that we can turn the bus around 131 * and do a few writes, or refresh, or whatever 132 */ 133 bool stopReads; 134 135 /** List to keep track of activate ticks */ 136 std::deque<Tick> actTicks; 137 138 /** 139 * A basic class to track the bank state indirectly via times 140 * "freeAt" and "tRASDoneAt" and what page is currently open. The 141 * bank also keeps track of how many bytes have been accessed in 142 * the open row since it was opened. 143 */ 144 class Bank 145 { 146 147 public: 148 149 static const uint32_t INVALID_ROW = -1; 150 151 uint32_t openRow; 152 153 Tick freeAt; 154 Tick tRASDoneAt; 155 156 uint32_t bytesAccessed; 157 158 Bank() : 159 openRow(INVALID_ROW), freeAt(0), tRASDoneAt(0), bytesAccessed(0) 160 { } 161 }; 162 163 /** 164 * A burst helper helps organize and manage a packet that is larger than 165 * the DRAM burst size. A system packet that is larger than the burst size 166 * is split into multiple DRAM packets and all those DRAM packets point to 167 * a single burst helper such that we know when the whole packet is served. 168 */ 169 class BurstHelper { 170 171 public: 172 173 /** Number of DRAM bursts requred for a system packet **/ 174 const unsigned int burstCount; 175 176 /** Number of DRAM bursts serviced so far for a system packet **/ 177 unsigned int burstsServiced; 178 179 BurstHelper(unsigned int _burstCount) 180 : burstCount(_burstCount), burstsServiced(0) 181 { } 182 }; 183 184 /** 185 * A DRAM packet stores packets along with the timestamp of when 186 * the packet entered the queue, and also the decoded address. 187 */ 188 class DRAMPacket { 189 190 public: 191 192 /** When did request enter the controller */ 193 const Tick entryTime; 194 195 /** When will request leave the controller */ 196 Tick readyTime; 197 198 /** This comes from the outside world */ 199 const PacketPtr pkt; 200 201 /** Will be populated by address decoder */ 202 const uint8_t rank; 203 const uint16_t bank; 204 const uint16_t row; 205 206 /** 207 * The starting address of the DRAM packet. 208 * This address could be unaligned to burst size boundaries. The 209 * reason is to keep the address offset so we can accurately check 210 * incoming read packets with packets in the write queue. 211 */ 212 const Addr addr; 213 214 /** 215 * The size of this dram packet in bytes 216 * It is always equal or smaller than DRAM burst size 217 */ 218 const unsigned int size; 219 220 /** 221 * A pointer to the BurstHelper if this DRAMPacket is a split packet 222 * If not a split packet (common case), this is set to NULL 223 */ 224 BurstHelper* burstHelper; 225 Bank& bank_ref; 226 227 DRAMPacket(PacketPtr _pkt, uint8_t _rank, uint16_t _bank, 228 uint16_t _row, Addr _addr, unsigned int _size, 229 Bank& _bank_ref) 230 : entryTime(curTick()), readyTime(curTick()), 231 pkt(_pkt), rank(_rank), bank(_bank), row(_row), addr(_addr), 232 size(_size), burstHelper(NULL), bank_ref(_bank_ref) 233 { } 234 235 }; 236 237 /** 238 * Bunch of things requires to setup "events" in gem5 239 * When event "writeEvent" occurs for example, the method 240 * processWriteEvent is called; no parameters are allowed 241 * in these methods 242 */ 243 void processWriteEvent(); 244 EventWrapper<SimpleDRAM, &SimpleDRAM::processWriteEvent> writeEvent; 245 246 void processRespondEvent(); 247 EventWrapper<SimpleDRAM, &SimpleDRAM::processRespondEvent> respondEvent; 248 249 void processRefreshEvent(); 250 EventWrapper<SimpleDRAM, &SimpleDRAM::processRefreshEvent> refreshEvent; 251 252 void processNextReqEvent(); 253 EventWrapper<SimpleDRAM,&SimpleDRAM::processNextReqEvent> nextReqEvent; 254 255 256 /** 257 * Check if the read queue has room for more entries 258 * 259 * @param pktCount The number of entries needed in the read queue 260 * @return true if read queue is full, false otherwise 261 */ 262 bool readQueueFull(unsigned int pktCount) const; 263 264 /** 265 * Check if the write queue has room for more entries 266 * 267 * @param pktCount The number of entries needed in the write queue 268 * @return true if write queue is full, false otherwise 269 */ 270 bool writeQueueFull(unsigned int pktCount) const; 271 272 /** 273 * When a new read comes in, first check if the write q has a 274 * pending request to the same address.\ If not, decode the 275 * address to populate rank/bank/row, create one or mutliple 276 * "dram_pkt", and push them to the back of the read queue.\ 277 * If this is the only 278 * read request in the system, schedule an event to start 279 * servicing it. 280 * 281 * @param pkt The request packet from the outside world 282 * @param pktCount The number of DRAM bursts the pkt 283 * translate to. If pkt size is larger then one full burst, 284 * then pktCount is greater than one. 285 */ 286 void addToReadQueue(PacketPtr pkt, unsigned int pktCount); 287 288 /** 289 * Decode the incoming pkt, create a dram_pkt and push to the 290 * back of the write queue. \If the write q length is more than 291 * the threshold specified by the user, ie the queue is beginning 292 * to get full, stop reads, and start draining writes. 293 * 294 * @param pkt The request packet from the outside world 295 * @param pktCount The number of DRAM bursts the pkt 296 * translate to. If pkt size is larger then one full burst, 297 * then pktCount is greater than one. 298 */ 299 void addToWriteQueue(PacketPtr pkt, unsigned int pktCount); 300 301 /** 302 * Actually do the DRAM access - figure out the latency it 303 * will take to service the req based on bank state, channel state etc 304 * and then update those states to account for this request.\ Based 305 * on this, update the packet's "readyTime" and move it to the 306 * response q from where it will eventually go back to the outside 307 * world. 308 * 309 * @param pkt The DRAM packet created from the outside world pkt 310 */ 311 void doDRAMAccess(DRAMPacket* dram_pkt); 312 313 /** 314 * Check when the channel is free to turnaround, add turnaround 315 * delay and schedule a whole bunch of writes. 316 */ 317 void triggerWrites(); 318 319 /** 320 * When a packet reaches its "readyTime" in the response Q, 321 * use the "access()" method in AbstractMemory to actually 322 * create the response packet, and send it back to the outside 323 * world requestor. 324 * 325 * @param pkt The packet from the outside world 326 * @param static_latency Static latency to add before sending the packet 327 */ 328 void accessAndRespond(PacketPtr pkt, Tick static_latency); 329 330 /** 331 * Address decoder to figure out physical mapping onto ranks, 332 * banks, and rows. This function is called multiple times on the same 333 * system packet if the pakcet is larger than burst of the memory. The 334 * dramPktAddr is used for the offset within the packet. 335 * 336 * @param pkt The packet from the outside world 337 * @param dramPktAddr The starting address of the DRAM packet 338 * @param size The size of the DRAM packet in bytes 339 * @return A DRAMPacket pointer with the decoded information 340 */ 341 DRAMPacket* decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned int size); 342 343 /** 344 * The memory schduler/arbiter - picks which read request needs to 345 * go next, based on the specified policy such as FCFS or FR-FCFS 346 * and moves it to the head of the read queue. 347 * 348 * @return True if a request was chosen and false if queue is empty 349 */ 350 bool chooseNextRead(); 351 352 /** 353 * Calls chooseNextReq() to pick the right request, then calls 354 * doDRAMAccess on that request in order to actually service 355 * that request 356 */ 357 void scheduleNextReq(); 358 359 /** 360 *Looks at the state of the banks, channels, row buffer hits etc 361 * to estimate how long a request will take to complete. 362 * 363 * @param dram_pkt The request for which we want to estimate latency 364 * @param inTime The tick at which you want to probe the memory 365 * 366 * @return A pair of ticks, one indicating how many ticks *after* 367 * inTime the request require, and the other indicating how 368 * much of that was just the bank access time, ignoring the 369 * ticks spent simply waiting for resources to become free 370 */ 371 std::pair<Tick, Tick> estimateLatency(DRAMPacket* dram_pkt, Tick inTime); 372 373 /** 374 * Move the request at the head of the read queue to the response 375 * queue, sorting by readyTime.\ If it is the only packet in the 376 * response queue, schedule a respond event to send it back to the 377 * outside world 378 */ 379 void moveToRespQ(); 380 381 /** 382 * Scheduling policy within the write queue 383 */ 384 void chooseNextWrite(); 385 386 /** 387 * Looking at all banks, determine the moment in time when they 388 * are all free. 389 * 390 * @return The tick when all banks are free 391 */ 392 Tick maxBankFreeAt() const; 393 394 395 /** 396 * Keep track of when row activations happen, in order to enforce 397 * the maximum number of activations in the activation window. The 398 * method updates the time that the banks become available based 399 * on the current limits. 400 */ 401 void recordActivate(Tick act_tick); 402 403 void printParams() const; 404 void printQs() const; 405 406 /** 407 * The controller's main read and write queues 408 */ 409 std::list<DRAMPacket*> readQueue; 410 std::list<DRAMPacket*> writeQueue; 411 412 /** 413 * Response queue where read packets wait after we're done working 414 * with them, but it's not time to send the response yet. The 415 * responses are stored seperately mostly to keep the code clean 416 * and help with events scheduling. For all logical purposes such 417 * as sizing the read queue, this and the main read queue need to 418 * be added together. 419 */ 420 std::list<DRAMPacket*> respQueue; 421 422 /** 423 * If we need to drain, keep the drain manager around until we're 424 * done here. 425 */ 426 DrainManager *drainManager; 427 428 /** 429 * Multi-dimensional vector of banks, first dimension is ranks, 430 * second is bank 431 */ 432 std::vector<std::vector<Bank> > banks; 433 434 /** 435 * The following are basic design parameters of the memory 436 * controller, and are initialized based on parameter values. 437 * The rowsPerBank is determined based on the capacity, number of 438 * ranks and banks, the burst size, and the row buffer size. 439 */ 440 const uint32_t deviceBusWidth; 441 const uint32_t burstLength; 442 const uint32_t deviceRowBufferSize; 443 const uint32_t devicesPerRank; 444 const uint32_t burstSize; 445 const uint32_t rowBufferSize; 446 const uint32_t ranksPerChannel; 447 const uint32_t banksPerRank; 448 const uint32_t channels; 449 uint32_t rowsPerBank; 450 uint32_t columnsPerRowBuffer; 451 const uint32_t readBufferSize; 452 const uint32_t writeBufferSize; 453 const double writeThresholdPerc; 454 uint32_t writeThreshold; 455 456 /** 457 * Basic memory timing parameters initialized based on parameter 458 * values. 459 */ 460 const Tick tWTR; 461 const Tick tBURST; 462 const Tick tRCD; 463 const Tick tCL; 464 const Tick tRP; 465 const Tick tRFC; 466 const Tick tREFI; 467 const Tick tXAW; 468 const uint32_t activationLimit; 469 470 /** 471 * Memory controller configuration initialized based on parameter 472 * values. 473 */ 474 Enums::MemSched memSchedPolicy; 475 Enums::AddrMap addrMapping; 476 Enums::PageManage pageMgmt; 477 478 /** 479 * Pipeline latency of the controller frontend. The frontend 480 * contribution is added to writes (that complete when they are in 481 * the write buffer) and reads that are serviced the write buffer. 482 */ 483 const Tick frontendLatency; 484 485 /** 486 * Pipeline latency of the backend and PHY. Along with the 487 * frontend contribution, this latency is added to reads serviced 488 * by the DRAM. 489 */ 490 const Tick backendLatency; 491 492 /** 493 * Till when has the main data bus been spoken for already? 494 */ 495 Tick busBusyUntil; 496 497 Tick writeStartTime; 498 Tick prevArrival; 499 int numReqs; 500 501 // All statistics that the model needs to capture 502 Stats::Scalar readReqs; 503 Stats::Scalar writeReqs; 504 Stats::Scalar readBursts; 505 Stats::Scalar writeBursts; 506 Stats::Scalar bytesRead; 507 Stats::Scalar bytesWritten; 508 Stats::Scalar bytesConsumedRd; 509 Stats::Scalar bytesConsumedWr; 510 Stats::Scalar servicedByWrQ; 511 Stats::Scalar neitherReadNorWrite; 512 Stats::Vector perBankRdReqs; 513 Stats::Vector perBankWrReqs; 514 Stats::Scalar numRdRetry; 515 Stats::Scalar numWrRetry; 516 Stats::Scalar totGap; 517 Stats::Vector readPktSize; 518 Stats::Vector writePktSize; 519 Stats::Vector rdQLenPdf; 520 Stats::Vector wrQLenPdf; 521 Stats::Histogram bytesPerActivate; 522 523 // Latencies summed over all requests 524 Stats::Scalar totQLat; 525 Stats::Scalar totMemAccLat; 526 Stats::Scalar totBusLat; 527 Stats::Scalar totBankLat; 528 529 // Average latencies per request 530 Stats::Formula avgQLat; 531 Stats::Formula avgBankLat; 532 Stats::Formula avgBusLat; 533 Stats::Formula avgMemAccLat; 534 535 // Average bandwidth 536 Stats::Formula avgRdBW; 537 Stats::Formula avgWrBW; 538 Stats::Formula avgConsumedRdBW; 539 Stats::Formula avgConsumedWrBW; 540 Stats::Formula peakBW; 541 Stats::Formula busUtil; 542 543 // Average queue lengths 544 Stats::Average avgRdQLen; 545 Stats::Average avgWrQLen; 546 547 // Row hit count and rate 548 Stats::Scalar readRowHits; 549 Stats::Scalar writeRowHits; 550 Stats::Formula readRowHitRate; 551 Stats::Formula writeRowHitRate; 552 Stats::Formula avgGap; 553 554 /** @todo this is a temporary workaround until the 4-phase code is 555 * committed. upstream caches needs this packet until true is returned, so 556 * hold onto it for deletion until a subsequent call 557 */ 558 std::vector<PacketPtr> pendingDelete; 559 560 public: 561 562 void regStats(); 563 564 SimpleDRAM(const SimpleDRAMParams* p); 565 566 unsigned int drain(DrainManager* dm); 567 568 virtual BaseSlavePort& getSlavePort(const std::string& if_name, 569 PortID idx = InvalidPortID); 570 571 virtual void init(); 572 virtual void startup(); 573 574 protected: 575 576 Tick recvAtomic(PacketPtr pkt); 577 void recvFunctional(PacketPtr pkt); 578 bool recvTimingReq(PacketPtr pkt); 579 580}; 581 582#endif //__MEM_SIMPLE_DRAM_HH__ 583