dram_ctrl.hh revision 9349
16892SBrad.Beckmann@amd.com/* 26892SBrad.Beckmann@amd.com * Copyright (c) 2012 ARM Limited 36892SBrad.Beckmann@amd.com * All rights reserved 46892SBrad.Beckmann@amd.com * 56892SBrad.Beckmann@amd.com * The license below extends only to copyright in the software and shall 66892SBrad.Beckmann@amd.com * not be construed as granting a license to any other intellectual 76892SBrad.Beckmann@amd.com * property including but not limited to intellectual property relating 86892SBrad.Beckmann@amd.com * to a hardware implementation of the functionality of the software 96892SBrad.Beckmann@amd.com * licensed hereunder. You may use the software subject to the license 106892SBrad.Beckmann@amd.com * terms below provided that you ensure that this notice is replicated 116892SBrad.Beckmann@amd.com * unmodified and in its entirety in all distributions of the software, 126892SBrad.Beckmann@amd.com * modified or unmodified, in source code or in binary form. 136892SBrad.Beckmann@amd.com * 146892SBrad.Beckmann@amd.com * Redistribution and use in source and binary forms, with or without 156892SBrad.Beckmann@amd.com * modification, are permitted provided that the following conditions are 166892SBrad.Beckmann@amd.com * met: redistributions of source code must retain the above copyright 176892SBrad.Beckmann@amd.com * notice, this list of conditions and the following disclaimer; 186892SBrad.Beckmann@amd.com * redistributions in binary form must reproduce the above copyright 196892SBrad.Beckmann@amd.com * notice, this list of conditions and the following disclaimer in the 206892SBrad.Beckmann@amd.com * documentation and/or other materials provided with the distribution; 216892SBrad.Beckmann@amd.com * neither the name of the copyright holders nor the names of its 226892SBrad.Beckmann@amd.com * contributors may be used to endorse or promote products derived from 236892SBrad.Beckmann@amd.com * this software without specific prior written permission. 246892SBrad.Beckmann@amd.com * 256892SBrad.Beckmann@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 266892SBrad.Beckmann@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 276892SBrad.Beckmann@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 286892SBrad.Beckmann@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 296892SBrad.Beckmann@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 306892SBrad.Beckmann@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 316892SBrad.Beckmann@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 326892SBrad.Beckmann@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 336892SBrad.Beckmann@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 346892SBrad.Beckmann@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 356892SBrad.Beckmann@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 366892SBrad.Beckmann@amd.com * 376892SBrad.Beckmann@amd.com * Authors: Andreas Hansson 386892SBrad.Beckmann@amd.com * Ani Udipi 396892SBrad.Beckmann@amd.com */ 406892SBrad.Beckmann@amd.com 416892SBrad.Beckmann@amd.com/** 426892SBrad.Beckmann@amd.com * @file 436892SBrad.Beckmann@amd.com * SimpleDRAM declaration 446892SBrad.Beckmann@amd.com */ 456892SBrad.Beckmann@amd.com 467538SBrad.Beckmann@amd.com#ifndef __MEM_SIMPLE_DRAM_HH__ 477538SBrad.Beckmann@amd.com#define __MEM_SIMPLE_DRAM_HH__ 487538SBrad.Beckmann@amd.com 496893SBrad.Beckmann@amd.com#include "base/statistics.hh" 506892SBrad.Beckmann@amd.com#include "enums/AddrMap.hh" 516892SBrad.Beckmann@amd.com#include "enums/MemSched.hh" 526892SBrad.Beckmann@amd.com#include "enums/PageManage.hh" 536892SBrad.Beckmann@amd.com#include "mem/abstract_mem.hh" 546893SBrad.Beckmann@amd.com#include "mem/qport.hh" 556893SBrad.Beckmann@amd.com#include "params/SimpleDRAM.hh" 566892SBrad.Beckmann@amd.com#include "sim/eventq.hh" 576892SBrad.Beckmann@amd.com 586892SBrad.Beckmann@amd.com/** 596892SBrad.Beckmann@amd.com * The simple DRAM is a basic single-channel memory controller aiming 606892SBrad.Beckmann@amd.com * to mimic a high-level DRAM controller and the most important timing 616892SBrad.Beckmann@amd.com * constraints associated with the DRAM. The focus is really on 626892SBrad.Beckmann@amd.com * modelling the impact on the system rather than the DRAM itself, 636892SBrad.Beckmann@amd.com * hence the focus is on the controller model and not on the 646892SBrad.Beckmann@amd.com * memory. By adhering to the correct timing constraints, ultimately 656892SBrad.Beckmann@amd.com * there is no need for a memory model in addition to the controller 666892SBrad.Beckmann@amd.com * model. 676892SBrad.Beckmann@amd.com * 686892SBrad.Beckmann@amd.com * As a basic design principle, this controller is not cycle callable, 696893SBrad.Beckmann@amd.com * but instead uses events to decide when new decisions can be made, 706893SBrad.Beckmann@amd.com * when resources become available, when things are to be considered 716892SBrad.Beckmann@amd.com * done, and when to send things back. Through these simple 726892SBrad.Beckmann@amd.com * principles, we achieve a performant model that is not 736892SBrad.Beckmann@amd.com * cycle-accurate, but enables us to evaluate the system impact of a 746903SBrad.Beckmann@amd.com * wide range of memory technologies, and also collect statistics 756903SBrad.Beckmann@amd.com * about the use of the memory. 766903SBrad.Beckmann@amd.com */ 776903SBrad.Beckmann@amd.comclass SimpleDRAM : public AbstractMemory 786903SBrad.Beckmann@amd.com{ 796903SBrad.Beckmann@amd.com 806892SBrad.Beckmann@amd.com private: 817015SBrad.Beckmann@amd.com 827015SBrad.Beckmann@amd.com // For now, make use of a queued slave port to avoid dealing with 836892SBrad.Beckmann@amd.com // flow control for the responses being sent back 846893SBrad.Beckmann@amd.com class MemoryPort : public QueuedSlavePort 856893SBrad.Beckmann@amd.com { 866893SBrad.Beckmann@amd.com 876893SBrad.Beckmann@amd.com SlavePacketQueue queue; 886893SBrad.Beckmann@amd.com SimpleDRAM& memory; 896892SBrad.Beckmann@amd.com 906892SBrad.Beckmann@amd.com public: 916892SBrad.Beckmann@amd.com 926892SBrad.Beckmann@amd.com MemoryPort(const std::string& name, SimpleDRAM& _memory); 936892SBrad.Beckmann@amd.com 946892SBrad.Beckmann@amd.com protected: 956893SBrad.Beckmann@amd.com 966893SBrad.Beckmann@amd.com Tick recvAtomic(PacketPtr pkt); 976893SBrad.Beckmann@amd.com 986893SBrad.Beckmann@amd.com void recvFunctional(PacketPtr pkt); 996893SBrad.Beckmann@amd.com 1006893SBrad.Beckmann@amd.com bool recvTimingReq(PacketPtr); 1016905SBrad.Beckmann@amd.com 1026905SBrad.Beckmann@amd.com virtual AddrRangeList getAddrRanges() const; 1036905SBrad.Beckmann@amd.com 1046893SBrad.Beckmann@amd.com }; 1056893SBrad.Beckmann@amd.com 1066893SBrad.Beckmann@amd.com /** 1076893SBrad.Beckmann@amd.com * Our incoming port, for a multi-ported controller add a crossbar 1086892SBrad.Beckmann@amd.com * in front of it 1096892SBrad.Beckmann@amd.com */ 1106892SBrad.Beckmann@amd.com MemoryPort port; 1116905SBrad.Beckmann@amd.com 1126905SBrad.Beckmann@amd.com /** 1136905SBrad.Beckmann@amd.com * Remember if we have to retry a request when available. 1146892SBrad.Beckmann@amd.com */ 1156893SBrad.Beckmann@amd.com bool retryRdReq; 1166905SBrad.Beckmann@amd.com bool retryWrReq; 1177031SBrad.Beckmann@amd.com 1187031SBrad.Beckmann@amd.com /** 1197031SBrad.Beckmann@amd.com * Remember that a row buffer hit occured 1206892SBrad.Beckmann@amd.com */ 1216892SBrad.Beckmann@amd.com bool rowHitFlag; 1226893SBrad.Beckmann@amd.com 1236893SBrad.Beckmann@amd.com /** 1246893SBrad.Beckmann@amd.com * Use this flag to shutoff reads, i.e. do not schedule any reads 1256893SBrad.Beckmann@amd.com * beyond those already done so that we can turn the bus around 1266893SBrad.Beckmann@amd.com * and do a few writes, or refresh, or whatever 1276893SBrad.Beckmann@amd.com */ 1286893SBrad.Beckmann@amd.com bool stopReads; 1296893SBrad.Beckmann@amd.com 1306893SBrad.Beckmann@amd.com /** 1316893SBrad.Beckmann@amd.com * A basic class to track the bank state indirectly via 1326892SBrad.Beckmann@amd.com * times "freeAt" and "tRASDoneAt" and what page is currently open 1336893SBrad.Beckmann@amd.com */ 1346892SBrad.Beckmann@amd.com class Bank 1356893SBrad.Beckmann@amd.com { 1366892SBrad.Beckmann@amd.com 1376892SBrad.Beckmann@amd.com public: 1386892SBrad.Beckmann@amd.com 1396892SBrad.Beckmann@amd.com static const uint32_t INVALID_ROW = -1; 1406893SBrad.Beckmann@amd.com 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 manager around until we're done 345 * here. 346 */ 347 DrainManager *drainManager; 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 /** @todo this is a temporary workaround until the 4-phase code is 457 * committed. upstream caches needs this packet until true is returned, so 458 * hold onto it for deletion until a subsequent call 459 */ 460 std::vector<PacketPtr> pendingDelete; 461 462 public: 463 464 void regStats(); 465 466 SimpleDRAM(const SimpleDRAMParams* p); 467 468 unsigned int drain(DrainManager* dm); 469 470 virtual BaseSlavePort& getSlavePort(const std::string& if_name, 471 PortID idx = InvalidPortID); 472 473 virtual void init(); 474 virtual void startup(); 475 476 protected: 477 478 Tick recvAtomic(PacketPtr pkt); 479 void recvFunctional(PacketPtr pkt); 480 bool recvTimingReq(PacketPtr pkt); 481 482}; 483 484#endif //__MEM_SIMPLE_DRAM_HH__ 485