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