dram_ctrl.hh revision 10146:27dfed4c8403
15081Sgblack@eecs.umich.edu/* 25081Sgblack@eecs.umich.edu * Copyright (c) 2012 ARM Limited 35081Sgblack@eecs.umich.edu * All rights reserved 47087Snate@binkert.org * 57087Snate@binkert.org * The license below extends only to copyright in the software and shall 67087Snate@binkert.org * not be construed as granting a license to any other intellectual 77087Snate@binkert.org * property including but not limited to intellectual property relating 87087Snate@binkert.org * to a hardware implementation of the functionality of the software 97087Snate@binkert.org * licensed hereunder. You may use the software subject to the license 107087Snate@binkert.org * terms below provided that you ensure that this notice is replicated 117087Snate@binkert.org * unmodified and in its entirety in all distributions of the software, 125081Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 137087Snate@binkert.org * 147087Snate@binkert.org * Copyright (c) 2013 Amin Farmahini-Farahani 157087Snate@binkert.org * All rights reserved. 167087Snate@binkert.org * 177087Snate@binkert.org * Redistribution and use in source and binary forms, with or without 187087Snate@binkert.org * modification, are permitted provided that the following conditions are 197087Snate@binkert.org * met: redistributions of source code must retain the above copyright 207087Snate@binkert.org * notice, this list of conditions and the following disclaimer; 215081Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 227087Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 235081Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 245081Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 255081Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 265081Sgblack@eecs.umich.edu * this software without specific prior written permission. 275081Sgblack@eecs.umich.edu * 285081Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 295081Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 305081Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 315081Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 325081Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 335081Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 345081Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 355081Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 365081Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 375081Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 385081Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 395081Sgblack@eecs.umich.edu * 405081Sgblack@eecs.umich.edu * Authors: Andreas Hansson 415081Sgblack@eecs.umich.edu * Ani Udipi 425081Sgblack@eecs.umich.edu * Neha Agarwal 435081Sgblack@eecs.umich.edu */ 445081Sgblack@eecs.umich.edu 455081Sgblack@eecs.umich.edu/** 465119Sgblack@eecs.umich.edu * @file 475176Sgblack@eecs.umich.edu * DRAMCtrl declaration 485081Sgblack@eecs.umich.edu */ 495081Sgblack@eecs.umich.edu 505081Sgblack@eecs.umich.edu#ifndef __MEM_DRAM_CTRL_HH__ 515081Sgblack@eecs.umich.edu#define __MEM_DRAM_CTRL_HH__ 525081Sgblack@eecs.umich.edu 535081Sgblack@eecs.umich.edu#include <deque> 545081Sgblack@eecs.umich.edu 555081Sgblack@eecs.umich.edu#include "base/statistics.hh" 565081Sgblack@eecs.umich.edu#include "enums/AddrMap.hh" 575119Sgblack@eecs.umich.edu#include "enums/MemSched.hh" 585176Sgblack@eecs.umich.edu#include "enums/PageManage.hh" 595081Sgblack@eecs.umich.edu#include "mem/abstract_mem.hh" 605081Sgblack@eecs.umich.edu#include "mem/qport.hh" 615081Sgblack@eecs.umich.edu#include "params/DRAMCtrl.hh" 625081Sgblack@eecs.umich.edu#include "sim/eventq.hh" 635081Sgblack@eecs.umich.edu 645081Sgblack@eecs.umich.edu/** 655081Sgblack@eecs.umich.edu * The DRAM controller is a basic single-channel memory controller 665081Sgblack@eecs.umich.edu * aiming to mimic a high-level DRAM controller and the most important 675081Sgblack@eecs.umich.edu * timing constraints associated with the DRAM. The focus is really on 685081Sgblack@eecs.umich.edu * modelling the impact on the system rather than the DRAM itself, 695119Sgblack@eecs.umich.edu * hence the focus is on the controller model and not on the 705176Sgblack@eecs.umich.edu * memory. By adhering to the correct timing constraints, ultimately 715081Sgblack@eecs.umich.edu * there is no need for a memory model in addition to the controller 725081Sgblack@eecs.umich.edu * model. 735081Sgblack@eecs.umich.edu * 745081Sgblack@eecs.umich.edu * As a basic design principle, this controller is not cycle callable, 755081Sgblack@eecs.umich.edu * but instead uses events to decide when new decisions can be made, 765081Sgblack@eecs.umich.edu * when resources become available, when things are to be considered 775081Sgblack@eecs.umich.edu * done, and when to send things back. Through these simple 785081Sgblack@eecs.umich.edu * principles, we achieve a performant model that is not 795081Sgblack@eecs.umich.edu * cycle-accurate, but enables us to evaluate the system impact of a 805081Sgblack@eecs.umich.edu * wide range of memory technologies, and also collect statistics 815119Sgblack@eecs.umich.edu * about the use of the memory. 825176Sgblack@eecs.umich.edu */ 835081Sgblack@eecs.umich.educlass DRAMCtrl : public AbstractMemory 845081Sgblack@eecs.umich.edu{ 855081Sgblack@eecs.umich.edu 865081Sgblack@eecs.umich.edu private: 875081Sgblack@eecs.umich.edu 885543Ssaidi@eecs.umich.edu // For now, make use of a queued slave port to avoid dealing with 895081Sgblack@eecs.umich.edu // flow control for the responses being sent back 90 class MemoryPort : public QueuedSlavePort 91 { 92 93 SlavePacketQueue queue; 94 DRAMCtrl& memory; 95 96 public: 97 98 MemoryPort(const std::string& name, DRAMCtrl& _memory); 99 100 protected: 101 102 Tick recvAtomic(PacketPtr pkt); 103 104 void recvFunctional(PacketPtr pkt); 105 106 bool recvTimingReq(PacketPtr); 107 108 virtual AddrRangeList getAddrRanges() const; 109 110 }; 111 112 /** 113 * Our incoming port, for a multi-ported controller add a crossbar 114 * in front of it 115 */ 116 MemoryPort port; 117 118 /** 119 * Remember if we have to retry a request when available. 120 */ 121 bool retryRdReq; 122 bool retryWrReq; 123 124 /** 125 * Remember that a row buffer hit occured 126 */ 127 bool rowHitFlag; 128 129 /** 130 * Use this flag to shutoff reads, i.e. do not schedule any reads 131 * beyond those already done so that we can turn the bus around 132 * and do a few writes, or refresh, or whatever 133 */ 134 bool stopReads; 135 136 /** List to keep track of activate ticks */ 137 std::vector<std::deque<Tick>> actTicks; 138 139 /** 140 * A basic class to track the bank state indirectly via times 141 * "freeAt" and "tRASDoneAt" and what page is currently open. The 142 * bank also keeps track of how many bytes have been accessed in 143 * the open row since it was opened. 144 */ 145 class Bank 146 { 147 148 public: 149 150 static const uint32_t INVALID_ROW = -1; 151 152 uint32_t openRow; 153 154 Tick freeAt; 155 Tick tRASDoneAt; 156 Tick actAllowedAt; 157 158 uint32_t rowAccesses; 159 uint32_t bytesAccessed; 160 161 Bank() : 162 openRow(INVALID_ROW), freeAt(0), tRASDoneAt(0), actAllowedAt(0), 163 rowAccesses(0), bytesAccessed(0) 164 { } 165 }; 166 167 /** 168 * A burst helper helps organize and manage a packet that is larger than 169 * the DRAM burst size. A system packet that is larger than the burst size 170 * is split into multiple DRAM packets and all those DRAM packets point to 171 * a single burst helper such that we know when the whole packet is served. 172 */ 173 class BurstHelper { 174 175 public: 176 177 /** Number of DRAM bursts requred for a system packet **/ 178 const unsigned int burstCount; 179 180 /** Number of DRAM bursts serviced so far for a system packet **/ 181 unsigned int burstsServiced; 182 183 BurstHelper(unsigned int _burstCount) 184 : burstCount(_burstCount), burstsServiced(0) 185 { } 186 }; 187 188 /** 189 * A DRAM packet stores packets along with the timestamp of when 190 * the packet entered the queue, and also the decoded address. 191 */ 192 class DRAMPacket { 193 194 public: 195 196 /** When did request enter the controller */ 197 const Tick entryTime; 198 199 /** When will request leave the controller */ 200 Tick readyTime; 201 202 /** This comes from the outside world */ 203 const PacketPtr pkt; 204 205 const bool isRead; 206 207 /** Will be populated by address decoder */ 208 const uint8_t rank; 209 const uint8_t bank; 210 const uint16_t row; 211 212 /** 213 * Bank id is calculated considering banks in all the ranks 214 * eg: 2 ranks each with 8 banks, then bankId = 0 --> rank0, bank0 and 215 * bankId = 8 --> rank1, bank0 216 */ 217 const uint16_t bankId; 218 219 /** 220 * The starting address of the DRAM packet. 221 * This address could be unaligned to burst size boundaries. The 222 * reason is to keep the address offset so we can accurately check 223 * incoming read packets with packets in the write queue. 224 */ 225 Addr addr; 226 227 /** 228 * The size of this dram packet in bytes 229 * It is always equal or smaller than DRAM burst size 230 */ 231 unsigned int size; 232 233 /** 234 * A pointer to the BurstHelper if this DRAMPacket is a split packet 235 * If not a split packet (common case), this is set to NULL 236 */ 237 BurstHelper* burstHelper; 238 Bank& bankRef; 239 240 DRAMPacket(PacketPtr _pkt, bool is_read, uint8_t _rank, uint8_t _bank, 241 uint16_t _row, uint16_t bank_id, Addr _addr, 242 unsigned int _size, Bank& bank_ref) 243 : entryTime(curTick()), readyTime(curTick()), 244 pkt(_pkt), isRead(is_read), rank(_rank), bank(_bank), row(_row), 245 bankId(bank_id), addr(_addr), size(_size), burstHelper(NULL), 246 bankRef(bank_ref) 247 { } 248 249 }; 250 251 /** 252 * Bunch of things requires to setup "events" in gem5 253 * When event "writeEvent" occurs for example, the method 254 * processWriteEvent is called; no parameters are allowed 255 * in these methods 256 */ 257 void processWriteEvent(); 258 EventWrapper<DRAMCtrl, &DRAMCtrl::processWriteEvent> writeEvent; 259 260 void processRespondEvent(); 261 EventWrapper<DRAMCtrl, &DRAMCtrl::processRespondEvent> respondEvent; 262 263 void processRefreshEvent(); 264 EventWrapper<DRAMCtrl, &DRAMCtrl::processRefreshEvent> refreshEvent; 265 266 void processNextReqEvent(); 267 EventWrapper<DRAMCtrl,&DRAMCtrl::processNextReqEvent> nextReqEvent; 268 269 270 /** 271 * Check if the read queue has room for more entries 272 * 273 * @param pktCount The number of entries needed in the read queue 274 * @return true if read queue is full, false otherwise 275 */ 276 bool readQueueFull(unsigned int pktCount) const; 277 278 /** 279 * Check if the write queue has room for more entries 280 * 281 * @param pktCount The number of entries needed in the write queue 282 * @return true if write queue is full, false otherwise 283 */ 284 bool writeQueueFull(unsigned int pktCount) const; 285 286 /** 287 * When a new read comes in, first check if the write q has a 288 * pending request to the same address.\ If not, decode the 289 * address to populate rank/bank/row, create one or mutliple 290 * "dram_pkt", and push them to the back of the read queue.\ 291 * If this is the only 292 * read request in the system, schedule an event to start 293 * servicing it. 294 * 295 * @param pkt The request packet from the outside world 296 * @param pktCount The number of DRAM bursts the pkt 297 * translate to. If pkt size is larger then one full burst, 298 * then pktCount is greater than one. 299 */ 300 void addToReadQueue(PacketPtr pkt, unsigned int pktCount); 301 302 /** 303 * Decode the incoming pkt, create a dram_pkt and push to the 304 * back of the write queue. \If the write q length is more than 305 * the threshold specified by the user, ie the queue is beginning 306 * to get full, stop reads, and start draining writes. 307 * 308 * @param pkt The request packet from the outside world 309 * @param pktCount The number of DRAM bursts the pkt 310 * translate to. If pkt size is larger then one full burst, 311 * then pktCount is greater than one. 312 */ 313 void addToWriteQueue(PacketPtr pkt, unsigned int pktCount); 314 315 /** 316 * Actually do the DRAM access - figure out the latency it 317 * will take to service the req based on bank state, channel state etc 318 * and then update those states to account for this request.\ Based 319 * on this, update the packet's "readyTime" and move it to the 320 * response q from where it will eventually go back to the outside 321 * world. 322 * 323 * @param pkt The DRAM packet created from the outside world pkt 324 */ 325 void doDRAMAccess(DRAMPacket* dram_pkt); 326 327 /** 328 * Check when the channel is free to turnaround, add turnaround 329 * delay and schedule a whole bunch of writes. 330 */ 331 void triggerWrites(); 332 333 /** 334 * When a packet reaches its "readyTime" in the response Q, 335 * use the "access()" method in AbstractMemory to actually 336 * create the response packet, and send it back to the outside 337 * world requestor. 338 * 339 * @param pkt The packet from the outside world 340 * @param static_latency Static latency to add before sending the packet 341 */ 342 void accessAndRespond(PacketPtr pkt, Tick static_latency); 343 344 /** 345 * Address decoder to figure out physical mapping onto ranks, 346 * banks, and rows. This function is called multiple times on the same 347 * system packet if the pakcet is larger than burst of the memory. The 348 * dramPktAddr is used for the offset within the packet. 349 * 350 * @param pkt The packet from the outside world 351 * @param dramPktAddr The starting address of the DRAM packet 352 * @param size The size of the DRAM packet in bytes 353 * @param isRead Is the request for a read or a write to DRAM 354 * @return A DRAMPacket pointer with the decoded information 355 */ 356 DRAMPacket* decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned int size, 357 bool isRead); 358 359 /** 360 * The memory schduler/arbiter - picks which read request needs to 361 * go next, based on the specified policy such as FCFS or FR-FCFS 362 * and moves it to the head of the read queue. 363 * 364 * @return True if a request was chosen and false if queue is empty 365 */ 366 bool chooseNextRead(); 367 368 /** 369 * Calls chooseNextReq() to pick the right request, then calls 370 * doDRAMAccess on that request in order to actually service 371 * that request 372 */ 373 void scheduleNextReq(); 374 375 /** 376 *Looks at the state of the banks, channels, row buffer hits etc 377 * to estimate how long a request will take to complete. 378 * 379 * @param dram_pkt The request for which we want to estimate latency 380 * @param inTime The tick at which you want to probe the memory 381 * 382 * @return A pair of ticks, one indicating how many ticks *after* 383 * inTime the request require, and the other indicating how 384 * much of that was just the bank access time, ignoring the 385 * ticks spent simply waiting for resources to become free 386 */ 387 std::pair<Tick, Tick> estimateLatency(DRAMPacket* dram_pkt, Tick inTime); 388 389 /** 390 * Move the request at the head of the read queue to the response 391 * queue, sorting by readyTime.\ If it is the only packet in the 392 * response queue, schedule a respond event to send it back to the 393 * outside world 394 */ 395 void moveToRespQ(); 396 397 /** 398 * Scheduling policy within the write queue 399 */ 400 void chooseNextWrite(); 401 402 /** 403 * For FR-FCFS policy reorder the read/write queue depending on row buffer 404 * hits and earliest banks available in DRAM 405 */ 406 void reorderQueue(std::deque<DRAMPacket*>& queue); 407 408 /** 409 * Looking at all banks, determine the moment in time when they 410 * are all free. 411 * 412 * @return The tick when all banks are free 413 */ 414 Tick maxBankFreeAt() const; 415 416 /** 417 * Find which are the earliest available banks for the enqueued 418 * requests. Assumes maximum of 64 banks per DIMM 419 * 420 * @param Queued requests to consider 421 * @return One-hot encoded mask of bank indices 422 */ 423 uint64_t minBankFreeAt(const std::deque<DRAMPacket*>& queue) const; 424 425 /** 426 * Keep track of when row activations happen, in order to enforce 427 * the maximum number of activations in the activation window. The 428 * method updates the time that the banks become available based 429 * on the current limits. 430 */ 431 void recordActivate(Tick act_tick, uint8_t rank, uint8_t bank); 432 433 void printParams() const; 434 435 /** 436 * Used for debugging to observe the contents of the queues. 437 */ 438 void printQs() const; 439 440 /** 441 * The controller's main read and write queues 442 */ 443 std::deque<DRAMPacket*> readQueue; 444 std::deque<DRAMPacket*> writeQueue; 445 446 /** 447 * Response queue where read packets wait after we're done working 448 * with them, but it's not time to send the response yet. The 449 * responses are stored seperately mostly to keep the code clean 450 * and help with events scheduling. For all logical purposes such 451 * as sizing the read queue, this and the main read queue need to 452 * be added together. 453 */ 454 std::deque<DRAMPacket*> respQueue; 455 456 /** 457 * If we need to drain, keep the drain manager around until we're 458 * done here. 459 */ 460 DrainManager *drainManager; 461 462 /** 463 * Multi-dimensional vector of banks, first dimension is ranks, 464 * second is bank 465 */ 466 std::vector<std::vector<Bank> > banks; 467 468 /** 469 * The following are basic design parameters of the memory 470 * controller, and are initialized based on parameter values. 471 * The rowsPerBank is determined based on the capacity, number of 472 * ranks and banks, the burst size, and the row buffer size. 473 */ 474 const uint32_t deviceBusWidth; 475 const uint32_t burstLength; 476 const uint32_t deviceRowBufferSize; 477 const uint32_t devicesPerRank; 478 const uint32_t burstSize; 479 const uint32_t rowBufferSize; 480 const uint32_t columnsPerRowBuffer; 481 const uint32_t ranksPerChannel; 482 const uint32_t banksPerRank; 483 const uint32_t channels; 484 uint32_t rowsPerBank; 485 const uint32_t readBufferSize; 486 const uint32_t writeBufferSize; 487 const uint32_t writeHighThreshold; 488 const uint32_t writeLowThreshold; 489 const uint32_t minWritesPerSwitch; 490 uint32_t writesThisTime; 491 492 /** 493 * Basic memory timing parameters initialized based on parameter 494 * values. 495 */ 496 const Tick tWTR; 497 const Tick tBURST; 498 const Tick tRCD; 499 const Tick tCL; 500 const Tick tRP; 501 const Tick tRAS; 502 const Tick tRFC; 503 const Tick tREFI; 504 const Tick tRRD; 505 const Tick tXAW; 506 const uint32_t activationLimit; 507 508 /** 509 * Memory controller configuration initialized based on parameter 510 * values. 511 */ 512 Enums::MemSched memSchedPolicy; 513 Enums::AddrMap addrMapping; 514 Enums::PageManage pageMgmt; 515 516 /** 517 * Max column accesses (read and write) per row, before forefully 518 * closing it. 519 */ 520 const uint32_t maxAccessesPerRow; 521 522 /** 523 * Pipeline latency of the controller frontend. The frontend 524 * contribution is added to writes (that complete when they are in 525 * the write buffer) and reads that are serviced the write buffer. 526 */ 527 const Tick frontendLatency; 528 529 /** 530 * Pipeline latency of the backend and PHY. Along with the 531 * frontend contribution, this latency is added to reads serviced 532 * by the DRAM. 533 */ 534 const Tick backendLatency; 535 536 /** 537 * Till when has the main data bus been spoken for already? 538 */ 539 Tick busBusyUntil; 540 541 Tick prevArrival; 542 543 // The absolute soonest you have to start thinking about the 544 // next request is the longest access time that can occur before 545 // busBusyUntil. Assuming you need to precharge, 546 // open a new row, and access, it is tRP + tRCD + tCL 547 Tick newTime; 548 549 // All statistics that the model needs to capture 550 Stats::Scalar readReqs; 551 Stats::Scalar writeReqs; 552 Stats::Scalar readBursts; 553 Stats::Scalar writeBursts; 554 Stats::Scalar bytesReadDRAM; 555 Stats::Scalar bytesReadWrQ; 556 Stats::Scalar bytesWritten; 557 Stats::Scalar bytesReadSys; 558 Stats::Scalar bytesWrittenSys; 559 Stats::Scalar servicedByWrQ; 560 Stats::Scalar mergedWrBursts; 561 Stats::Scalar neitherReadNorWrite; 562 Stats::Vector perBankRdBursts; 563 Stats::Vector perBankWrBursts; 564 Stats::Scalar numRdRetry; 565 Stats::Scalar numWrRetry; 566 Stats::Scalar totGap; 567 Stats::Vector readPktSize; 568 Stats::Vector writePktSize; 569 Stats::Vector rdQLenPdf; 570 Stats::Vector wrQLenPdf; 571 Stats::Histogram bytesPerActivate; 572 573 // Latencies summed over all requests 574 Stats::Scalar totQLat; 575 Stats::Scalar totMemAccLat; 576 Stats::Scalar totBusLat; 577 Stats::Scalar totBankLat; 578 579 // Average latencies per request 580 Stats::Formula avgQLat; 581 Stats::Formula avgBankLat; 582 Stats::Formula avgBusLat; 583 Stats::Formula avgMemAccLat; 584 585 // Average bandwidth 586 Stats::Formula avgRdBW; 587 Stats::Formula avgWrBW; 588 Stats::Formula avgRdBWSys; 589 Stats::Formula avgWrBWSys; 590 Stats::Formula peakBW; 591 Stats::Formula busUtil; 592 Stats::Formula busUtilRead; 593 Stats::Formula busUtilWrite; 594 595 // Average queue lengths 596 Stats::Average avgRdQLen; 597 Stats::Average avgWrQLen; 598 599 // Row hit count and rate 600 Stats::Scalar readRowHits; 601 Stats::Scalar writeRowHits; 602 Stats::Formula readRowHitRate; 603 Stats::Formula writeRowHitRate; 604 Stats::Formula avgGap; 605 606 // DRAM Power Calculation 607 Stats::Formula pageHitRate; 608 Stats::Formula prechargeAllPercent; 609 Stats::Scalar prechargeAllTime; 610 611 // To track number of cycles all the banks are precharged 612 Tick startTickPrechargeAll; 613 // To track number of banks which are currently active 614 unsigned int numBanksActive; 615 616 /** @todo this is a temporary workaround until the 4-phase code is 617 * committed. upstream caches needs this packet until true is returned, so 618 * hold onto it for deletion until a subsequent call 619 */ 620 std::vector<PacketPtr> pendingDelete; 621 622 public: 623 624 void regStats(); 625 626 DRAMCtrl(const DRAMCtrlParams* p); 627 628 unsigned int drain(DrainManager* dm); 629 630 virtual BaseSlavePort& getSlavePort(const std::string& if_name, 631 PortID idx = InvalidPortID); 632 633 virtual void init(); 634 virtual void startup(); 635 636 protected: 637 638 Tick recvAtomic(PacketPtr pkt); 639 void recvFunctional(PacketPtr pkt); 640 bool recvTimingReq(PacketPtr pkt); 641 642}; 643 644#endif //__MEM_DRAM_CTRL_HH__ 645