dram_ctrl.hh revision 9726
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 137 * times "freeAt" and "tRASDoneAt" and what page is currently open 138 */ 139 class Bank 140 { 141 142 public: 143 144 static const uint32_t INVALID_ROW = -1; 145 146 uint32_t openRow; 147 148 Tick freeAt; 149 Tick tRASDoneAt; 150 151 Bank() : openRow(INVALID_ROW), freeAt(0), tRASDoneAt(0) 152 { } 153 }; 154 155 /** 156 * A DRAM packet stores packets along with the timestamp of when 157 * the packet entered the queue, and also the decoded address. 158 */ 159 class DRAMPacket { 160 161 public: 162 163 /** When did request enter the controller */ 164 const Tick entryTime; 165 166 /** When will request leave the controller */ 167 Tick readyTime; 168 169 /** This comes from the outside world */ 170 const PacketPtr pkt; 171 172 /** Will be populated by address decoder */ 173 const uint8_t rank; 174 const uint16_t bank; 175 const uint16_t row; 176 const Addr addr; 177 Bank& bank_ref; 178 179 DRAMPacket(PacketPtr _pkt, uint8_t _rank, 180 uint16_t _bank, uint16_t _row, Addr _addr, Bank& _bank_ref) 181 : entryTime(curTick()), readyTime(curTick()), 182 pkt(_pkt), rank(_rank), bank(_bank), row(_row), addr(_addr), 183 bank_ref(_bank_ref) 184 { } 185 186 }; 187 188 /** 189 * Bunch of things requires to setup "events" in gem5 190 * When event "writeEvent" occurs for example, the method 191 * processWriteEvent is called; no parameters are allowed 192 * in these methods 193 */ 194 void processWriteEvent(); 195 EventWrapper<SimpleDRAM, &SimpleDRAM::processWriteEvent> writeEvent; 196 197 void processRespondEvent(); 198 EventWrapper<SimpleDRAM, &SimpleDRAM::processRespondEvent> respondEvent; 199 200 void processRefreshEvent(); 201 EventWrapper<SimpleDRAM, &SimpleDRAM::processRefreshEvent> refreshEvent; 202 203 void processNextReqEvent(); 204 EventWrapper<SimpleDRAM,&SimpleDRAM::processNextReqEvent> nextReqEvent; 205 206 207 /** 208 * Check if the read queue has room for more entries 209 * 210 * @return true if read queue is full, false otherwise 211 */ 212 bool readQueueFull() const; 213 214 /** 215 * Check if the write queue has room for more entries 216 * 217 * @return true if write queue is full, false otherwise 218 */ 219 bool writeQueueFull() const; 220 221 /** 222 * When a new read comes in, first check if the write q has a 223 * pending request to the same address.\ If not, decode the 224 * address to populate rank/bank/row, create a "dram_pkt", and 225 * push it to the back of the read queue.\ If this is the only 226 * read request in the system, schedule an event to start 227 * servicing it. 228 * 229 * @param pkt The request packet from the outside world 230 */ 231 void addToReadQueue(PacketPtr pkt); 232 233 /** 234 * Decode the incoming pkt, create a dram_pkt and push to the 235 * back of the write queue. \If the write q length is more than 236 * the threshold specified by the user, ie the queue is beginning 237 * to get full, stop reads, and start draining writes. 238 * 239 * @param pkt The request packet from the outside world 240 */ 241 void addToWriteQueue(PacketPtr pkt); 242 243 /** 244 * Actually do the DRAM access - figure out the latency it 245 * will take to service the req based on bank state, channel state etc 246 * and then update those states to account for this request.\ Based 247 * on this, update the packet's "readyTime" and move it to the 248 * response q from where it will eventually go back to the outside 249 * world. 250 * 251 * @param pkt The DRAM packet created from the outside world pkt 252 */ 253 void doDRAMAccess(DRAMPacket* dram_pkt); 254 255 /** 256 * Check when the channel is free to turnaround, add turnaround 257 * delay and schedule a whole bunch of writes. 258 */ 259 void triggerWrites(); 260 261 /** 262 * When a packet reaches its "readyTime" in the response Q, 263 * use the "access()" method in AbstractMemory to actually 264 * create the response packet, and send it back to the outside 265 * world requestor. 266 * 267 * @param pkt The packet from the outside world 268 * @param static_latency Static latency to add before sending the packet 269 */ 270 void accessAndRespond(PacketPtr pkt, Tick static_latency); 271 272 /** 273 * Address decoder to figure out physical mapping onto ranks, 274 * banks, and rows. 275 * 276 * @param pkt The packet from the outside world 277 * @return A DRAMPacket pointer with the decoded information 278 */ 279 DRAMPacket* decodeAddr(PacketPtr pkt); 280 281 /** 282 * The memory schduler/arbiter - picks which read request needs to 283 * go next, based on the specified policy such as FCFS or FR-FCFS 284 * and moves it to the head of the read queue. 285 * 286 * @return True if a request was chosen and false if queue is empty 287 */ 288 bool chooseNextRead(); 289 290 /** 291 * Calls chooseNextReq() to pick the right request, then calls 292 * doDRAMAccess on that request in order to actually service 293 * that request 294 */ 295 void scheduleNextReq(); 296 297 /** 298 *Looks at the state of the banks, channels, row buffer hits etc 299 * to estimate how long a request will take to complete. 300 * 301 * @param dram_pkt The request for which we want to estimate latency 302 * @param inTime The tick at which you want to probe the memory 303 * 304 * @return A pair of ticks, one indicating how many ticks *after* 305 * inTime the request require, and the other indicating how 306 * much of that was just the bank access time, ignoring the 307 * ticks spent simply waiting for resources to become free 308 */ 309 std::pair<Tick, Tick> estimateLatency(DRAMPacket* dram_pkt, Tick inTime); 310 311 /** 312 * Move the request at the head of the read queue to the response 313 * queue, sorting by readyTime.\ If it is the only packet in the 314 * response queue, schedule a respond event to send it back to the 315 * outside world 316 */ 317 void moveToRespQ(); 318 319 /** 320 * Scheduling policy within the write queue 321 */ 322 void chooseNextWrite(); 323 324 /** 325 * Looking at all banks, determine the moment in time when they 326 * are all free. 327 * 328 * @return The tick when all banks are free 329 */ 330 Tick maxBankFreeAt() const; 331 332 333 /** 334 * Keep track of when row activations happen, in order to enforce 335 * the maximum number of activations in the activation window. The 336 * method updates the time that the banks become available based 337 * on the current limits. 338 */ 339 void recordActivate(Tick act_tick); 340 341 void printParams() const; 342 void printQs() const; 343 344 /** 345 * The controller's main read and write queues 346 */ 347 std::list<DRAMPacket*> readQueue; 348 std::list<DRAMPacket*> writeQueue; 349 350 /** 351 * Response queue where read packets wait after we're done working 352 * with them, but it's not time to send the response yet. The 353 * responses are stored seperately mostly to keep the code clean 354 * and help with events scheduling. For all logical purposes such 355 * as sizing the read queue, this and the main read queue need to 356 * be added together. 357 */ 358 std::list<DRAMPacket*> respQueue; 359 360 /** 361 * If we need to drain, keep the drain manager around until we're 362 * done here. 363 */ 364 DrainManager *drainManager; 365 366 /** 367 * Multi-dimensional vector of banks, first dimension is ranks, 368 * second is bank 369 */ 370 std::vector<std::vector<Bank> > banks; 371 372 /** 373 * The following are basic design parameters of the memory 374 * controller, and are initialized based on parameter values. The 375 * bytesPerCacheLine is based on the neighbouring ports cache line 376 * size and thus determined outside the constructor. Similarly, 377 * the rowsPerBank is determined based on the capacity, number of 378 * ranks and banks, the cache line size, and the row buffer size. 379 */ 380 uint32_t bytesPerCacheLine; 381 const uint32_t linesPerRowBuffer; 382 const uint32_t ranksPerChannel; 383 const uint32_t banksPerRank; 384 const uint32_t channels; 385 uint32_t rowsPerBank; 386 const uint32_t readBufferSize; 387 const uint32_t writeBufferSize; 388 const double writeThresholdPerc; 389 uint32_t writeThreshold; 390 391 /** 392 * Basic memory timing parameters initialized based on parameter 393 * values. 394 */ 395 const Tick tWTR; 396 const Tick tBURST; 397 const Tick tRCD; 398 const Tick tCL; 399 const Tick tRP; 400 const Tick tRFC; 401 const Tick tREFI; 402 const Tick tXAW; 403 const uint32_t activationLimit; 404 405 /** 406 * Memory controller configuration initialized based on parameter 407 * values. 408 */ 409 Enums::MemSched memSchedPolicy; 410 Enums::AddrMap addrMapping; 411 Enums::PageManage pageMgmt; 412 413 /** 414 * Pipeline latency of the controller frontend. The frontend 415 * contribution is added to writes (that complete when they are in 416 * the write buffer) and reads that are serviced the write buffer. 417 */ 418 const Tick frontendLatency; 419 420 /** 421 * Pipeline latency of the backend and PHY. Along with the 422 * frontend contribution, this latency is added to reads serviced 423 * by the DRAM. 424 */ 425 const Tick backendLatency; 426 427 /** 428 * Till when has the main data bus been spoken for already? 429 */ 430 Tick busBusyUntil; 431 432 Tick writeStartTime; 433 Tick prevArrival; 434 int numReqs; 435 436 // All statistics that the model needs to capture 437 Stats::Scalar readReqs; 438 Stats::Scalar writeReqs; 439 Stats::Scalar cpuReqs; 440 Stats::Scalar bytesRead; 441 Stats::Scalar bytesWritten; 442 Stats::Scalar bytesConsumedRd; 443 Stats::Scalar bytesConsumedWr; 444 Stats::Scalar servicedByWrQ; 445 Stats::Scalar neitherReadNorWrite; 446 Stats::Vector perBankRdReqs; 447 Stats::Vector perBankWrReqs; 448 Stats::Scalar numRdRetry; 449 Stats::Scalar numWrRetry; 450 Stats::Scalar totGap; 451 Stats::Vector readPktSize; 452 Stats::Vector writePktSize; 453 Stats::Vector rdQLenPdf; 454 Stats::Vector wrQLenPdf; 455 456 457 // Latencies summed over all requests 458 Stats::Scalar totQLat; 459 Stats::Scalar totMemAccLat; 460 Stats::Scalar totBusLat; 461 Stats::Scalar totBankLat; 462 463 // Average latencies per request 464 Stats::Formula avgQLat; 465 Stats::Formula avgBankLat; 466 Stats::Formula avgBusLat; 467 Stats::Formula avgMemAccLat; 468 469 // Average bandwidth 470 Stats::Formula avgRdBW; 471 Stats::Formula avgWrBW; 472 Stats::Formula avgConsumedRdBW; 473 Stats::Formula avgConsumedWrBW; 474 Stats::Formula peakBW; 475 Stats::Formula busUtil; 476 477 // Average queue lengths 478 Stats::Average avgRdQLen; 479 Stats::Average avgWrQLen; 480 481 // Row hit count and rate 482 Stats::Scalar readRowHits; 483 Stats::Scalar writeRowHits; 484 Stats::Formula readRowHitRate; 485 Stats::Formula writeRowHitRate; 486 Stats::Formula avgGap; 487 488 /** @todo this is a temporary workaround until the 4-phase code is 489 * committed. upstream caches needs this packet until true is returned, so 490 * hold onto it for deletion until a subsequent call 491 */ 492 std::vector<PacketPtr> pendingDelete; 493 494 public: 495 496 void regStats(); 497 498 SimpleDRAM(const SimpleDRAMParams* p); 499 500 unsigned int drain(DrainManager* dm); 501 502 virtual BaseSlavePort& getSlavePort(const std::string& if_name, 503 PortID idx = InvalidPortID); 504 505 virtual void init(); 506 virtual void startup(); 507 508 protected: 509 510 Tick recvAtomic(PacketPtr pkt); 511 void recvFunctional(PacketPtr pkt); 512 bool recvTimingReq(PacketPtr pkt); 513 514}; 515 516#endif //__MEM_SIMPLE_DRAM_HH__ 517