dram_ctrl.hh revision 9243
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 "base/statistics.hh" 50#include "enums/AddrMap.hh" 51#include "enums/MemSched.hh" 52#include "enums/PageManage.hh" 53#include "mem/abstract_mem.hh" 54#include "mem/qport.hh" 55#include "params/SimpleDRAM.hh" 56#include "sim/eventq.hh" 57 58/** 59 * The simple DRAM is a basic single-channel memory controller aiming 60 * to mimic a high-level DRAM controller and the most important timing 61 * constraints associated with the DRAM. The focus is really on 62 * modelling the impact on the system rather than the DRAM itself, 63 * hence the focus is on the controller model and not on the 64 * memory. By adhering to the correct timing constraints, ultimately 65 * there is no need for a memory model in addition to the controller 66 * model. 67 * 68 * As a basic design principle, this controller is not cycle callable, 69 * but instead uses events to decide when new decisions can be made, 70 * when resources become available, when things are to be considered 71 * done, and when to send things back. Through these simple 72 * principles, we achieve a performant model that is not 73 * cycle-accurate, but enables us to evaluate the system impact of a 74 * wide range of memory technologies, and also collect statistics 75 * about the use of the memory. 76 */ 77class SimpleDRAM : public AbstractMemory 78{ 79 80 private: 81 82 // For now, make use of a queued slave port to avoid dealing with 83 // flow control for the responses being sent back 84 class MemoryPort : public QueuedSlavePort 85 { 86 87 SlavePacketQueue queue; 88 SimpleDRAM& memory; 89 90 public: 91 92 MemoryPort(const std::string& name, SimpleDRAM& _memory); 93 94 protected: 95 96 Tick recvAtomic(PacketPtr pkt); 97 98 void recvFunctional(PacketPtr pkt); 99 100 bool recvTimingReq(PacketPtr); 101 102 virtual AddrRangeList getAddrRanges() const; 103 104 }; 105 106 /** 107 * Our incoming port, for a multi-ported controller add a crossbar 108 * in front of it 109 */ 110 MemoryPort port; 111 112 /** 113 * Remember if we have to retry a request when available. 114 */ 115 bool retryRdReq; 116 bool retryWrReq; 117 118 /** 119 * Remember that a row buffer hit occured 120 */ 121 bool rowHitFlag; 122 123 /** 124 * Use this flag to shutoff reads, i.e. do not schedule any reads 125 * beyond those already done so that we can turn the bus around 126 * and do a few writes, or refresh, or whatever 127 */ 128 bool stopReads; 129 130 /** 131 * A basic class to track the bank state indirectly via 132 * times "freeAt" and "tRASDoneAt" and what page is currently open 133 */ 134 class Bank 135 { 136 137 public: 138 139 static const uint32_t INVALID_ROW = -1; 140 141 uint32_t openRow; 142 143 Tick freeAt; 144 Tick tRASDoneAt; 145 146 Bank() : openRow(INVALID_ROW), freeAt(0), tRASDoneAt(0) 147 { } 148 }; 149 150 /** 151 * A DRAM packet stores packets along with the timestamp of when 152 * the packet entered the queue, and also the decoded address. 153 */ 154 class DRAMPacket { 155 156 public: 157 158 /** When did request enter the controller */ 159 const Tick entryTime; 160 161 /** When will request leave the controller */ 162 Tick readyTime; 163 164 /** This comes from the outside world */ 165 const PacketPtr pkt; 166 167 /** Will be populated by address decoder */ 168 const uint8_t rank; 169 const uint16_t bank; 170 const uint16_t row; 171 const Addr addr; 172 Bank& bank_ref; 173 174 DRAMPacket(PacketPtr _pkt, uint8_t _rank, 175 uint16_t _bank, uint16_t _row, Addr _addr, Bank& _bank_ref) 176 : entryTime(curTick()), readyTime(curTick()), 177 pkt(_pkt), rank(_rank), bank(_bank), row(_row), addr(_addr), 178 bank_ref(_bank_ref) 179 { } 180 181 }; 182 183 /** 184 * Bunch of things requires to setup "events" in gem5 185 * When event "writeEvent" occurs for example, the method 186 * processWriteEvent is called; no parameters are allowed 187 * in these methods 188 */ 189 void processWriteEvent(); 190 EventWrapper<SimpleDRAM, &SimpleDRAM::processWriteEvent> writeEvent; 191 192 void processRespondEvent(); 193 EventWrapper<SimpleDRAM, &SimpleDRAM::processRespondEvent> respondEvent; 194 195 void processRefreshEvent(); 196 EventWrapper<SimpleDRAM, &SimpleDRAM::processRefreshEvent> refreshEvent; 197 198 void processNextReqEvent(); 199 EventWrapper<SimpleDRAM,&SimpleDRAM::processNextReqEvent> nextReqEvent; 200 201 202 /** 203 * Check if the read queue has room for more entries 204 * 205 * @return true if read queue is full, false otherwise 206 */ 207 bool readQueueFull() const; 208 209 /** 210 * Check if the write queue has room for more entries 211 * 212 * @return true if write queue is full, false otherwise 213 */ 214 bool writeQueueFull() const; 215 216 /** 217 * When a new read comes in, first check if the write q has a 218 * pending request to the same address.\ If not, decode the 219 * address to populate rank/bank/row, create a "dram_pkt", and 220 * push it to the back of the read queue.\ If this is the only 221 * read request in the system, schedule an event to start 222 * servicing it. 223 * 224 * @param pkt The request packet from the outside world 225 */ 226 void addToReadQueue(PacketPtr pkt); 227 228 /** 229 * Decode the incoming pkt, create a dram_pkt and push to the 230 * back of the write queue. \If the write q length is more than 231 * the threshold specified by the user, ie the queue is beginning 232 * to get full, stop reads, and start draining writes. 233 * 234 * @param pkt The request packet from the outside world 235 */ 236 void addToWriteQueue(PacketPtr pkt); 237 238 /** 239 * Actually do the DRAM access - figure out the latency it 240 * will take to service the req based on bank state, channel state etc 241 * and then update those states to account for this request.\ Based 242 * on this, update the packet's "readyTime" and move it to the 243 * response q from where it will eventually go back to the outside 244 * world. 245 * 246 * @param pkt The DRAM packet created from the outside world pkt 247 */ 248 void doDRAMAccess(DRAMPacket* dram_pkt); 249 250 /** 251 * Check when the channel is free to turnaround, add turnaround 252 * delay and schedule a whole bunch of writes. 253 */ 254 void triggerWrites(); 255 256 /** 257 * When a packet reaches its "readyTime" in the response Q, 258 * use the "access()" method in AbstractMemory to actually 259 * create the response packet, and send it back to the outside 260 * world requestor. 261 * 262 * @param pkt The packet from the outside world 263 */ 264 void accessAndRespond(PacketPtr pkt); 265 266 /** 267 * Address decoder to figure out physical mapping onto ranks, 268 * banks, and rows. 269 * 270 * @param pkt The packet from the outside world 271 * @return A DRAMPacket pointer with the decoded information 272 */ 273 DRAMPacket* decodeAddr(PacketPtr pkt); 274 275 /** 276 * The memory schduler/arbiter - picks which request needs to 277 * go next, based on the specified policy such as fcfs or frfcfs 278 * and moves it to the head of the read queue 279 * 280 * @return True if a request was chosen, False if Q is empty 281 */ 282 bool chooseNextReq(); 283 284 /** 285 * Calls chooseNextReq() to pick the right request, then calls 286 * doDRAMAccess on that request in order to actually service 287 * that request 288 */ 289 void scheduleNextReq(); 290 291 /** 292 *Looks at the state of the banks, channels, row buffer hits etc 293 * to estimate how long a request will take to complete. 294 * 295 * @param dram_pkt The request for which we want to estimate latency 296 * @param inTime The tick at which you want to probe the memory 297 * 298 * @return A pair of ticks, one indicating how many ticks *after* 299 * inTime the request require, and the other indicating how 300 * much of that was just the bank access time, ignoring the 301 * ticks spent simply waiting for resources to become free 302 */ 303 std::pair<Tick, Tick> estimateLatency(DRAMPacket* dram_pkt, Tick inTime); 304 305 /** 306 * Move the request at the head of the read queue to the response 307 * queue, sorting by readyTime.\ If it is the only packet in the 308 * response queue, schedule a respond event to send it back to the 309 * outside world 310 */ 311 void moveToRespQ(); 312 313 /** 314 * Scheduling policy within the write Q 315 */ 316 void chooseNextWrite(); 317 318 /** 319 * Looking at all banks, determine the moment in time when they 320 * are all free. 321 * 322 * @return The tick when all banks are free 323 */ 324 Tick maxBankFreeAt() const; 325 326 void printParams() const; 327 void printQs() const; 328 329 /** 330 * The controller's main read and write queues 331 */ 332 std::list<DRAMPacket*> dramReadQueue; 333 std::list<DRAMPacket*> dramWriteQueue; 334 335 /** 336 * Response queue where read packets wait after we're done working 337 * with them, but it's not time to send the response yet.\ It is 338 * seperate mostly to keep the code clean and help with gem5 events, 339 * but for all logical purposes such as sizing the read queue, this 340 * and the main read queue need to be added together. 341 */ 342 std::list<DRAMPacket*> dramRespQueue; 343 344 /** If we need to drain, keep the drain event around until we're done 345 * here. 346 */ 347 Event *drainEvent; 348 349 /** 350 * Multi-dimensional vector of banks, first dimension is ranks, 351 * second is bank 352 */ 353 std::vector<std::vector<Bank> > banks; 354 355 /** 356 * The following are basic design parameters of the memory 357 * controller, and are initialized based on parameter values. The 358 * bytesPerCacheLine is based on the neighbouring port and thus 359 * determined outside the constructor. Similarly, the rowsPerBank 360 * is determined based on the capacity, number of ranks and banks, 361 * the cache line size, and the row buffer size. 362 */ 363 uint32_t bytesPerCacheLine; 364 const uint32_t linesPerRowBuffer; 365 const uint32_t ranksPerChannel; 366 const uint32_t banksPerRank; 367 uint32_t rowsPerBank; 368 const uint32_t readBufferSize; 369 const uint32_t writeBufferSize; 370 const double writeThresholdPerc; 371 uint32_t writeThreshold; 372 373 /** 374 * Basic memory timing parameters initialized based on parameter 375 * values. 376 */ 377 const Tick tWTR; 378 const Tick tBURST; 379 const Tick tRCD; 380 const Tick tCL; 381 const Tick tRP; 382 const Tick tRFC; 383 const Tick tREFI; 384 385 /** 386 * Memory controller configuration initialized based on parameter 387 * values. 388 */ 389 Enums::MemSched memSchedPolicy; 390 Enums::AddrMap addrMapping; 391 Enums::PageManage pageMgmt; 392 393 /** 394 * Till when has the main data bus been spoken for already? 395 */ 396 Tick busBusyUntil; 397 398 Tick prevdramaccess; 399 Tick writeStartTime; 400 Tick prevArrival; 401 int numReqs; 402 403 // All statistics that the model needs to capture 404 Stats::Scalar readReqs; 405 Stats::Scalar writeReqs; 406 Stats::Scalar cpuReqs; 407 Stats::Scalar bytesRead; 408 Stats::Scalar bytesWritten; 409 Stats::Scalar bytesConsumedRd; 410 Stats::Scalar bytesConsumedWr; 411 Stats::Scalar servicedByWrQ; 412 Stats::Scalar neitherReadNorWrite; 413 Stats::Vector perBankRdReqs; 414 Stats::Vector perBankWrReqs; 415 Stats::Scalar numRdRetry; 416 Stats::Scalar numWrRetry; 417 Stats::Scalar totGap; 418 Stats::Vector readPktSize; 419 Stats::Vector writePktSize; 420 Stats::Vector neitherPktSize; 421 Stats::Vector rdQLenPdf; 422 Stats::Vector wrQLenPdf; 423 424 425 // Latencies summed over all requests 426 Stats::Scalar totQLat; 427 Stats::Scalar totMemAccLat; 428 Stats::Scalar totBusLat; 429 Stats::Scalar totBankLat; 430 431 // Average latencies per request 432 Stats::Formula avgQLat; 433 Stats::Formula avgBankLat; 434 Stats::Formula avgBusLat; 435 Stats::Formula avgMemAccLat; 436 437 // Average bandwidth 438 Stats::Formula avgRdBW; 439 Stats::Formula avgWrBW; 440 Stats::Formula avgConsumedRdBW; 441 Stats::Formula avgConsumedWrBW; 442 Stats::Formula peakBW; 443 Stats::Formula busUtil; 444 445 // Average queue lengths 446 Stats::Average avgRdQLen; 447 Stats::Average avgWrQLen; 448 449 // Row hit count and rate 450 Stats::Scalar readRowHits; 451 Stats::Scalar writeRowHits; 452 Stats::Formula readRowHitRate; 453 Stats::Formula writeRowHitRate; 454 Stats::Formula avgGap; 455 456 public: 457 458 void regStats(); 459 460 SimpleDRAM(const SimpleDRAMParams* p); 461 462 unsigned int drain(Event* de); 463 464 virtual SlavePort& getSlavePort(const std::string& if_name, 465 int idx = InvalidPortID); 466 467 virtual void init(); 468 virtual void startup(); 469 470 protected: 471 472 Tick recvAtomic(PacketPtr pkt); 473 void recvFunctional(PacketPtr pkt); 474 bool recvTimingReq(PacketPtr pkt); 475 476}; 477 478#endif //__MEM_SIMPLE_DRAM_HH__ 479