dram_ctrl.hh revision 9488
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 */ 269 void accessAndRespond(PacketPtr pkt); 270 271 /** 272 * Address decoder to figure out physical mapping onto ranks, 273 * banks, and rows. 274 * 275 * @param pkt The packet from the outside world 276 * @return A DRAMPacket pointer with the decoded information 277 */ 278 DRAMPacket* decodeAddr(PacketPtr pkt); 279 280 /** 281 * The memory schduler/arbiter - picks which request needs to 282 * go next, based on the specified policy such as fcfs or frfcfs 283 * and moves it to the head of the read queue 284 * 285 * @return True if a request was chosen, False if Q is empty 286 */ 287 bool chooseNextReq(); 288 289 /** 290 * Calls chooseNextReq() to pick the right request, then calls 291 * doDRAMAccess on that request in order to actually service 292 * that request 293 */ 294 void scheduleNextReq(); 295 296 /** 297 *Looks at the state of the banks, channels, row buffer hits etc 298 * to estimate how long a request will take to complete. 299 * 300 * @param dram_pkt The request for which we want to estimate latency 301 * @param inTime The tick at which you want to probe the memory 302 * 303 * @return A pair of ticks, one indicating how many ticks *after* 304 * inTime the request require, and the other indicating how 305 * much of that was just the bank access time, ignoring the 306 * ticks spent simply waiting for resources to become free 307 */ 308 std::pair<Tick, Tick> estimateLatency(DRAMPacket* dram_pkt, Tick inTime); 309 310 /** 311 * Move the request at the head of the read queue to the response 312 * queue, sorting by readyTime.\ If it is the only packet in the 313 * response queue, schedule a respond event to send it back to the 314 * outside world 315 */ 316 void moveToRespQ(); 317 318 /** 319 * Scheduling policy within the write Q 320 */ 321 void chooseNextWrite(); 322 323 /** 324 * Looking at all banks, determine the moment in time when they 325 * are all free. 326 * 327 * @return The tick when all banks are free 328 */ 329 Tick maxBankFreeAt() const; 330 331 332 /** 333 * Keep track of when row activations happen, in order to enforce 334 * the maximum number of activations in the activation window. The 335 * method updates the time that the banks become available based 336 * on the current limits. 337 */ 338 void recordActivate(Tick act_tick); 339 340 void printParams() const; 341 void printQs() const; 342 343 /** 344 * The controller's main read and write queues 345 */ 346 std::list<DRAMPacket*> dramReadQueue; 347 std::list<DRAMPacket*> dramWriteQueue; 348 349 /** 350 * Response queue where read packets wait after we're done working 351 * with them, but it's not time to send the response yet.\ It is 352 * seperate mostly to keep the code clean and help with gem5 events, 353 * but for all logical purposes such as sizing the read queue, this 354 * and the main read queue need to be added together. 355 */ 356 std::list<DRAMPacket*> dramRespQueue; 357 358 /** If we need to drain, keep the drain manager around until we're done 359 * here. 360 */ 361 DrainManager *drainManager; 362 363 /** 364 * Multi-dimensional vector of banks, first dimension is ranks, 365 * second is bank 366 */ 367 std::vector<std::vector<Bank> > banks; 368 369 /** 370 * The following are basic design parameters of the memory 371 * controller, and are initialized based on parameter values. The 372 * bytesPerCacheLine is based on the neighbouring port and thus 373 * determined outside the constructor. Similarly, the rowsPerBank 374 * is determined based on the capacity, number of ranks and banks, 375 * the cache line size, and the row buffer size. 376 */ 377 uint32_t bytesPerCacheLine; 378 const uint32_t linesPerRowBuffer; 379 const uint32_t ranksPerChannel; 380 const uint32_t banksPerRank; 381 uint32_t rowsPerBank; 382 const uint32_t readBufferSize; 383 const uint32_t writeBufferSize; 384 const double writeThresholdPerc; 385 uint32_t writeThreshold; 386 387 /** 388 * Basic memory timing parameters initialized based on parameter 389 * values. 390 */ 391 const Tick tWTR; 392 const Tick tBURST; 393 const Tick tRCD; 394 const Tick tCL; 395 const Tick tRP; 396 const Tick tRFC; 397 const Tick tREFI; 398 const Tick tXAW; 399 const uint32_t activationLimit; 400 401 /** 402 * Memory controller configuration initialized based on parameter 403 * values. 404 */ 405 Enums::MemSched memSchedPolicy; 406 Enums::AddrMap addrMapping; 407 Enums::PageManage pageMgmt; 408 409 /** 410 * Till when has the main data bus been spoken for already? 411 */ 412 Tick busBusyUntil; 413 414 Tick prevdramaccess; 415 Tick writeStartTime; 416 Tick prevArrival; 417 int numReqs; 418 419 // All statistics that the model needs to capture 420 Stats::Scalar readReqs; 421 Stats::Scalar writeReqs; 422 Stats::Scalar cpuReqs; 423 Stats::Scalar bytesRead; 424 Stats::Scalar bytesWritten; 425 Stats::Scalar bytesConsumedRd; 426 Stats::Scalar bytesConsumedWr; 427 Stats::Scalar servicedByWrQ; 428 Stats::Scalar neitherReadNorWrite; 429 Stats::Vector perBankRdReqs; 430 Stats::Vector perBankWrReqs; 431 Stats::Scalar numRdRetry; 432 Stats::Scalar numWrRetry; 433 Stats::Scalar totGap; 434 Stats::Vector readPktSize; 435 Stats::Vector writePktSize; 436 Stats::Vector neitherPktSize; 437 Stats::Vector rdQLenPdf; 438 Stats::Vector wrQLenPdf; 439 440 441 // Latencies summed over all requests 442 Stats::Scalar totQLat; 443 Stats::Scalar totMemAccLat; 444 Stats::Scalar totBusLat; 445 Stats::Scalar totBankLat; 446 447 // Average latencies per request 448 Stats::Formula avgQLat; 449 Stats::Formula avgBankLat; 450 Stats::Formula avgBusLat; 451 Stats::Formula avgMemAccLat; 452 453 // Average bandwidth 454 Stats::Formula avgRdBW; 455 Stats::Formula avgWrBW; 456 Stats::Formula avgConsumedRdBW; 457 Stats::Formula avgConsumedWrBW; 458 Stats::Formula peakBW; 459 Stats::Formula busUtil; 460 461 // Average queue lengths 462 Stats::Average avgRdQLen; 463 Stats::Average avgWrQLen; 464 465 // Row hit count and rate 466 Stats::Scalar readRowHits; 467 Stats::Scalar writeRowHits; 468 Stats::Formula readRowHitRate; 469 Stats::Formula writeRowHitRate; 470 Stats::Formula avgGap; 471 472 /** @todo this is a temporary workaround until the 4-phase code is 473 * committed. upstream caches needs this packet until true is returned, so 474 * hold onto it for deletion until a subsequent call 475 */ 476 std::vector<PacketPtr> pendingDelete; 477 478 public: 479 480 void regStats(); 481 482 SimpleDRAM(const SimpleDRAMParams* p); 483 484 unsigned int drain(DrainManager* dm); 485 486 virtual BaseSlavePort& getSlavePort(const std::string& if_name, 487 PortID idx = InvalidPortID); 488 489 virtual void init(); 490 virtual void startup(); 491 492 protected: 493 494 Tick recvAtomic(PacketPtr pkt); 495 void recvFunctional(PacketPtr pkt); 496 bool recvTimingReq(PacketPtr pkt); 497 498}; 499 500#endif //__MEM_SIMPLE_DRAM_HH__ 501