dram_ctrl.cc revision 9963
16145Snate@binkert.org/* 26145Snate@binkert.org * Copyright (c) 2010-2013 ARM Limited 36145Snate@binkert.org * All rights reserved 46145Snate@binkert.org * 56145Snate@binkert.org * The license below extends only to copyright in the software and shall 66145Snate@binkert.org * not be construed as granting a license to any other intellectual 76145Snate@binkert.org * property including but not limited to intellectual property relating 86145Snate@binkert.org * to a hardware implementation of the functionality of the software 96145Snate@binkert.org * licensed hereunder. You may use the software subject to the license 106145Snate@binkert.org * terms below provided that you ensure that this notice is replicated 116145Snate@binkert.org * unmodified and in its entirety in all distributions of the software, 126145Snate@binkert.org * modified or unmodified, in source code or in binary form. 136145Snate@binkert.org * 146145Snate@binkert.org * Copyright (c) 2013 Amin Farmahini-Farahani 156145Snate@binkert.org * All rights reserved. 166145Snate@binkert.org * 176145Snate@binkert.org * Redistribution and use in source and binary forms, with or without 186145Snate@binkert.org * modification, are permitted provided that the following conditions are 196145Snate@binkert.org * met: redistributions of source code must retain the above copyright 206145Snate@binkert.org * notice, this list of conditions and the following disclaimer; 216145Snate@binkert.org * redistributions in binary form must reproduce the above copyright 226145Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 236145Snate@binkert.org * documentation and/or other materials provided with the distribution; 246145Snate@binkert.org * neither the name of the copyright holders nor the names of its 256145Snate@binkert.org * contributors may be used to endorse or promote products derived from 266145Snate@binkert.org * this software without specific prior written permission. 276145Snate@binkert.org * 286145Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 297832Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 307832Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 317054Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 328232Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 337054Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 346154Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 358229Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 366154Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 377054Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 386154Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 396145Snate@binkert.org * 407055Snate@binkert.org * Authors: Andreas Hansson 417055Snate@binkert.org * Ani Udipi 426145Snate@binkert.org */ 436145Snate@binkert.org 446145Snate@binkert.org#include "base/trace.hh" 456145Snate@binkert.org#include "debug/Drain.hh" 466145Snate@binkert.org#include "debug/DRAM.hh" 476145Snate@binkert.org#include "debug/DRAMWR.hh" 486145Snate@binkert.org#include "mem/simple_dram.hh" 496145Snate@binkert.org#include "sim/system.hh" 506145Snate@binkert.org 517054Snate@binkert.orgusing namespace std; 527054Snate@binkert.org 536145Snate@binkert.orgSimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) : 547054Snate@binkert.org AbstractMemory(p), 557054Snate@binkert.org port(name() + ".port", *this), 566145Snate@binkert.org retryRdReq(false), retryWrReq(false), 576145Snate@binkert.org rowHitFlag(false), stopReads(false), actTicks(p->activation_limit, 0), 587054Snate@binkert.org writeEvent(this), respondEvent(this), 597054Snate@binkert.org refreshEvent(this), nextReqEvent(this), drainManager(NULL), 606145Snate@binkert.org deviceBusWidth(p->device_bus_width), burstLength(p->burst_length), 617054Snate@binkert.org deviceRowBufferSize(p->device_rowbuffer_size), 627054Snate@binkert.org devicesPerRank(p->devices_per_rank), 636145Snate@binkert.org burstSize((devicesPerRank * burstLength * deviceBusWidth) / 8), 646145Snate@binkert.org rowBufferSize(devicesPerRank * deviceRowBufferSize), 657054Snate@binkert.org ranksPerChannel(p->ranks_per_channel), 667054Snate@binkert.org banksPerRank(p->banks_per_rank), channels(p->channels), rowsPerBank(0), 676145Snate@binkert.org readBufferSize(p->read_buffer_size), 687054Snate@binkert.org writeBufferSize(p->write_buffer_size), 697054Snate@binkert.org writeThresholdPerc(p->write_thresh_perc), 706145Snate@binkert.org tWTR(p->tWTR), tBURST(p->tBURST), 717832Snate@binkert.org tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP), tRAS(p->tRAS), 727054Snate@binkert.org tRFC(p->tRFC), tREFI(p->tREFI), 737054Snate@binkert.org tXAW(p->tXAW), activationLimit(p->activation_limit), 746145Snate@binkert.org memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping), 757054Snate@binkert.org pageMgmt(p->page_policy), 767054Snate@binkert.org frontendLatency(p->static_frontend_latency), 776145Snate@binkert.org backendLatency(p->static_backend_latency), 786145Snate@binkert.org busBusyUntil(0), writeStartTime(0), 797054Snate@binkert.org prevArrival(0), numReqs(0) 807054Snate@binkert.org{ 816145Snate@binkert.org // create the bank states based on the dimensions of the ranks and 827054Snate@binkert.org // banks 837054Snate@binkert.org banks.resize(ranksPerChannel); 847054Snate@binkert.org for (size_t c = 0; c < ranksPerChannel; ++c) { 857054Snate@binkert.org banks[c].resize(banksPerRank); 866145Snate@binkert.org } 876145Snate@binkert.org 887054Snate@binkert.org // round the write threshold percent to a whole number of entries 897454Snate@binkert.org // in the buffer 907454Snate@binkert.org writeThreshold = writeBufferSize * writeThresholdPerc / 100.0; 916145Snate@binkert.org} 927054Snate@binkert.org 937054Snate@binkert.orgvoid 947054Snate@binkert.orgSimpleDRAM::init() 957054Snate@binkert.org{ 966145Snate@binkert.org if (!port.isConnected()) { 977454Snate@binkert.org fatal("SimpleDRAM %s is unconnected!\n", name()); 987054Snate@binkert.org } else { 997454Snate@binkert.org port.sendRangeChange(); 1007054Snate@binkert.org } 1017054Snate@binkert.org 1027054Snate@binkert.org // we could deal with plenty options here, but for now do a quick 1036145Snate@binkert.org // sanity check 1046145Snate@binkert.org DPRINTF(DRAM, "Burst size %d bytes\n", burstSize); 1056145Snate@binkert.org 1067054Snate@binkert.org // determine the rows per bank by looking at the total capacity 1077054Snate@binkert.org uint64_t capacity = ULL(1) << ceilLog2(AbstractMemory::size()); 1086145Snate@binkert.org 1097454Snate@binkert.org DPRINTF(DRAM, "Memory capacity %lld (%lld) bytes\n", capacity, 1107454Snate@binkert.org AbstractMemory::size()); 1117454Snate@binkert.org 1126145Snate@binkert.org columnsPerRowBuffer = rowBufferSize / burstSize; 1137054Snate@binkert.org 1147054Snate@binkert.org DPRINTF(DRAM, "Row buffer size %d bytes with %d columns per row buffer\n", 1157054Snate@binkert.org rowBufferSize, columnsPerRowBuffer); 1167054Snate@binkert.org 1177054Snate@binkert.org rowsPerBank = capacity / (rowBufferSize * banksPerRank * ranksPerChannel); 1187054Snate@binkert.org 1196145Snate@binkert.org if (range.interleaved()) { 1206145Snate@binkert.org if (channels != range.stripes()) 1217054Snate@binkert.org panic("%s has %d interleaved address stripes but %d channel(s)\n", 1227054Snate@binkert.org name(), range.stripes(), channels); 1236145Snate@binkert.org 1247054Snate@binkert.org if (addrMapping == Enums::RaBaChCo) { 1257054Snate@binkert.org if (rowBufferSize != range.granularity()) { 1267054Snate@binkert.org panic("Interleaving of %s doesn't match RaBaChCo address map\n", 1276145Snate@binkert.org name()); 1287054Snate@binkert.org } 1297054Snate@binkert.org } else if (addrMapping == Enums::RaBaCoCh) { 1307054Snate@binkert.org if (burstSize != range.granularity()) { 1317054Snate@binkert.org panic("Interleaving of %s doesn't match RaBaCoCh address map\n", 1327054Snate@binkert.org name()); 1337054Snate@binkert.org } 1346145Snate@binkert.org } else if (addrMapping == Enums::CoRaBaCh) { 1357054Snate@binkert.org if (burstSize != range.granularity()) 1367054Snate@binkert.org panic("Interleaving of %s doesn't match CoRaBaCh address map\n", 1377054Snate@binkert.org name()); 1387054Snate@binkert.org } 1397054Snate@binkert.org } 1407054Snate@binkert.org} 1416145Snate@binkert.org 1426145Snate@binkert.orgvoid 1437054Snate@binkert.orgSimpleDRAM::startup() 1447054Snate@binkert.org{ 1457054Snate@binkert.org // print the configuration of the controller 1467054Snate@binkert.org printParams(); 1477054Snate@binkert.org 1487054Snate@binkert.org // kick off the refresh 1497054Snate@binkert.org schedule(refreshEvent, curTick() + tREFI); 1507054Snate@binkert.org} 1517054Snate@binkert.org 1527054Snate@binkert.orgTick 1537054Snate@binkert.orgSimpleDRAM::recvAtomic(PacketPtr pkt) 1547054Snate@binkert.org{ 1557054Snate@binkert.org DPRINTF(DRAM, "recvAtomic: %s 0x%x\n", pkt->cmdString(), pkt->getAddr()); 1567054Snate@binkert.org 1577054Snate@binkert.org // do the actual memory access and turn the packet into a response 1587054Snate@binkert.org access(pkt); 1597054Snate@binkert.org 1607054Snate@binkert.org Tick latency = 0; 1617453Snate@binkert.org if (!pkt->memInhibitAsserted() && pkt->hasData()) { 1627054Snate@binkert.org // this value is not supposed to be accurate, just enough to 1637054Snate@binkert.org // keep things going, mimic a closed page 1647054Snate@binkert.org latency = tRP + tRCD + tCL; 1657780Snilay@cs.wisc.edu } 1667780Snilay@cs.wisc.edu return latency; 1677054Snate@binkert.org} 1687780Snilay@cs.wisc.edu 1697054Snate@binkert.orgbool 1707054Snate@binkert.orgSimpleDRAM::readQueueFull(unsigned int neededEntries) const 1717054Snate@binkert.org{ 1727054Snate@binkert.org DPRINTF(DRAM, "Read queue limit %d, current size %d, entries needed %d\n", 1737054Snate@binkert.org readBufferSize, readQueue.size() + respQueue.size(), 1747054Snate@binkert.org neededEntries); 1757054Snate@binkert.org 1767054Snate@binkert.org return 1777780Snilay@cs.wisc.edu (readQueue.size() + respQueue.size() + neededEntries) > readBufferSize; 1787054Snate@binkert.org} 1797054Snate@binkert.org 1807054Snate@binkert.orgbool 1817054Snate@binkert.orgSimpleDRAM::writeQueueFull(unsigned int neededEntries) const 1827054Snate@binkert.org{ 1837054Snate@binkert.org DPRINTF(DRAM, "Write queue limit %d, current size %d, entries needed %d\n", 1847054Snate@binkert.org writeBufferSize, writeQueue.size(), neededEntries); 1857054Snate@binkert.org return (writeQueue.size() + neededEntries) > writeBufferSize; 1867054Snate@binkert.org} 1877054Snate@binkert.org 1887054Snate@binkert.orgSimpleDRAM::DRAMPacket* 1897780Snilay@cs.wisc.eduSimpleDRAM::decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned size) 1907054Snate@binkert.org{ 1917054Snate@binkert.org // decode the address based on the address mapping scheme, with 1927054Snate@binkert.org // Ra, Co, Ba and Ch denoting rank, column, bank and channel, 1937054Snate@binkert.org // respectively 1946145Snate@binkert.org uint8_t rank; 1956145Snate@binkert.org uint16_t bank; 1967054Snate@binkert.org uint16_t row; 1977054Snate@binkert.org 1987054Snate@binkert.org // truncate the address to the access granularity 1996145Snate@binkert.org Addr addr = dramPktAddr / burstSize; 2007054Snate@binkert.org 2017054Snate@binkert.org // we have removed the lowest order address bits that denote the 2026145Snate@binkert.org // position within the column 2037054Snate@binkert.org if (addrMapping == Enums::RaBaChCo) { 2047054Snate@binkert.org // the lowest order bits denote the column to ensure that 2057054Snate@binkert.org // sequential cache lines occupy the same row 2067054Snate@binkert.org addr = addr / columnsPerRowBuffer; 2077054Snate@binkert.org 2087054Snate@binkert.org // take out the channel part of the address 2097054Snate@binkert.org addr = addr / channels; 2107780Snilay@cs.wisc.edu 2117054Snate@binkert.org // after the channel bits, get the bank bits to interleave 2127780Snilay@cs.wisc.edu // over the banks 2137054Snate@binkert.org bank = addr % banksPerRank; 2147054Snate@binkert.org addr = addr / banksPerRank; 2157054Snate@binkert.org 2167054Snate@binkert.org // after the bank, we get the rank bits which thus interleaves 2177054Snate@binkert.org // over the ranks 2186145Snate@binkert.org rank = addr % ranksPerChannel; 2196145Snate@binkert.org addr = addr / ranksPerChannel; 2207054Snate@binkert.org 2217054Snate@binkert.org // lastly, get the row bits 2226145Snate@binkert.org row = addr % rowsPerBank; 2237054Snate@binkert.org addr = addr / rowsPerBank; 2246145Snate@binkert.org } else if (addrMapping == Enums::RaBaCoCh) { 2256145Snate@binkert.org // take out the channel part of the address 2267054Snate@binkert.org addr = addr / channels; 2277054Snate@binkert.org 2286145Snate@binkert.org // next, the column 2297054Snate@binkert.org addr = addr / columnsPerRowBuffer; 2307054Snate@binkert.org 2316145Snate@binkert.org // after the column bits, we get the bank bits to interleave 2327054Snate@binkert.org // over the banks 2337054Snate@binkert.org bank = addr % banksPerRank; 2347054Snate@binkert.org addr = addr / banksPerRank; 2357054Snate@binkert.org 2366145Snate@binkert.org // after the bank, we get the rank bits which thus interleaves 2376145Snate@binkert.org // over the ranks 2386145Snate@binkert.org rank = addr % ranksPerChannel; 2397054Snate@binkert.org addr = addr / ranksPerChannel; 2407054Snate@binkert.org 2416145Snate@binkert.org // lastly, get the row bits 2426145Snate@binkert.org row = addr % rowsPerBank; 2436145Snate@binkert.org addr = addr / rowsPerBank; 2447054Snate@binkert.org } else if (addrMapping == Enums::CoRaBaCh) { 2457054Snate@binkert.org // optimise for closed page mode and utilise maximum 2466145Snate@binkert.org // parallelism of the DRAM (at the cost of power) 2477054Snate@binkert.org 2487054Snate@binkert.org // take out the channel part of the address, not that this has 2496145Snate@binkert.org // to match with how accesses are interleaved between the 2506145Snate@binkert.org // controllers in the address mapping 2517054Snate@binkert.org addr = addr / channels; 2527054Snate@binkert.org 2536145Snate@binkert.org // start with the bank bits, as this provides the maximum 2548054Sksewell@umich.edu // opportunity for parallelism between requests 2556145Snate@binkert.org bank = addr % banksPerRank; 2566145Snate@binkert.org addr = addr / banksPerRank; 2577054Snate@binkert.org 2587054Snate@binkert.org // next get the rank bits 2597054Snate@binkert.org rank = addr % ranksPerChannel; 2607054Snate@binkert.org addr = addr / ranksPerChannel; 2616145Snate@binkert.org 2627054Snate@binkert.org // next the column bits which we do not need to keep track of 2637054Snate@binkert.org // and simply skip past 2647054Snate@binkert.org addr = addr / columnsPerRowBuffer; 2656145Snate@binkert.org 2667054Snate@binkert.org // lastly, get the row bits 2677054Snate@binkert.org row = addr % rowsPerBank; 2687054Snate@binkert.org addr = addr / rowsPerBank; 2697054Snate@binkert.org } else 2707054Snate@binkert.org panic("Unknown address mapping policy chosen!"); 2716145Snate@binkert.org 272 assert(rank < ranksPerChannel); 273 assert(bank < banksPerRank); 274 assert(row < rowsPerBank); 275 276 DPRINTF(DRAM, "Address: %lld Rank %d Bank %d Row %d\n", 277 dramPktAddr, rank, bank, row); 278 279 // create the corresponding DRAM packet with the entry time and 280 // ready time set to the current tick, the latter will be updated 281 // later 282 return new DRAMPacket(pkt, rank, bank, row, dramPktAddr, size, 283 banks[rank][bank]); 284} 285 286void 287SimpleDRAM::addToReadQueue(PacketPtr pkt, unsigned int pktCount) 288{ 289 // only add to the read queue here. whenever the request is 290 // eventually done, set the readyTime, and call schedule() 291 assert(!pkt->isWrite()); 292 293 assert(pktCount != 0); 294 295 // if the request size is larger than burst size, the pkt is split into 296 // multiple DRAM packets 297 // Note if the pkt starting address is not aligened to burst size, the 298 // address of first DRAM packet is kept unaliged. Subsequent DRAM packets 299 // are aligned to burst size boundaries. This is to ensure we accurately 300 // check read packets against packets in write queue. 301 Addr addr = pkt->getAddr(); 302 unsigned pktsServicedByWrQ = 0; 303 BurstHelper* burst_helper = NULL; 304 for (int cnt = 0; cnt < pktCount; ++cnt) { 305 unsigned size = std::min((addr | (burstSize - 1)) + 1, 306 pkt->getAddr() + pkt->getSize()) - addr; 307 readPktSize[ceilLog2(size)]++; 308 readBursts++; 309 310 // First check write buffer to see if the data is already at 311 // the controller 312 bool foundInWrQ = false; 313 for (auto i = writeQueue.begin(); i != writeQueue.end(); ++i) { 314 // check if the read is subsumed in the write entry we are 315 // looking at 316 if ((*i)->addr <= addr && 317 (addr + size) <= ((*i)->addr + (*i)->size)) { 318 foundInWrQ = true; 319 servicedByWrQ++; 320 pktsServicedByWrQ++; 321 DPRINTF(DRAM, "Read to addr %lld with size %d serviced by " 322 "write queue\n", addr, size); 323 bytesRead += burstSize; 324 bytesConsumedRd += size; 325 break; 326 } 327 } 328 329 // If not found in the write q, make a DRAM packet and 330 // push it onto the read queue 331 if (!foundInWrQ) { 332 333 // Make the burst helper for split packets 334 if (pktCount > 1 && burst_helper == NULL) { 335 DPRINTF(DRAM, "Read to addr %lld translates to %d " 336 "dram requests\n", pkt->getAddr(), pktCount); 337 burst_helper = new BurstHelper(pktCount); 338 } 339 340 DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size); 341 dram_pkt->burstHelper = burst_helper; 342 343 assert(!readQueueFull(1)); 344 rdQLenPdf[readQueue.size() + respQueue.size()]++; 345 346 DPRINTF(DRAM, "Adding to read queue\n"); 347 348 readQueue.push_back(dram_pkt); 349 350 // Update stats 351 uint32_t bank_id = banksPerRank * dram_pkt->rank + dram_pkt->bank; 352 assert(bank_id < ranksPerChannel * banksPerRank); 353 perBankRdReqs[bank_id]++; 354 355 avgRdQLen = readQueue.size() + respQueue.size(); 356 } 357 358 // Starting address of next dram pkt (aligend to burstSize boundary) 359 addr = (addr | (burstSize - 1)) + 1; 360 } 361 362 // If all packets are serviced by write queue, we send the repsonse back 363 if (pktsServicedByWrQ == pktCount) { 364 accessAndRespond(pkt, frontendLatency); 365 return; 366 } 367 368 // Update how many split packets are serviced by write queue 369 if (burst_helper != NULL) 370 burst_helper->burstsServiced = pktsServicedByWrQ; 371 372 // If we are not already scheduled to get the read request out of 373 // the queue, do so now 374 if (!nextReqEvent.scheduled() && !stopReads) { 375 DPRINTF(DRAM, "Request scheduled immediately\n"); 376 schedule(nextReqEvent, curTick()); 377 } 378} 379 380void 381SimpleDRAM::processWriteEvent() 382{ 383 assert(!writeQueue.empty()); 384 uint32_t numWritesThisTime = 0; 385 Tick actTick; 386 387 DPRINTF(DRAMWR, "Beginning DRAM Writes\n"); 388 Tick temp1 M5_VAR_USED = std::max(curTick(), busBusyUntil); 389 Tick temp2 M5_VAR_USED = std::max(curTick(), maxBankFreeAt()); 390 391 // @todo: are there any dangers with the untimed while loop? 392 while (!writeQueue.empty()) { 393 if (numWritesThisTime > writeThreshold) { 394 DPRINTF(DRAMWR, "Hit write threshold %d\n", writeThreshold); 395 break; 396 } 397 398 chooseNextWrite(); 399 DRAMPacket* dram_pkt = writeQueue.front(); 400 401 // sanity check 402 assert(dram_pkt->size <= burstSize); 403 404 // What's the earliest the request can be put on the bus 405 Tick schedTime = std::max(curTick(), busBusyUntil); 406 407 DPRINTF(DRAMWR, "Asking for latency estimate at %lld\n", 408 schedTime + tBURST); 409 410 pair<Tick, Tick> lat = estimateLatency(dram_pkt, schedTime + tBURST); 411 Tick accessLat = lat.second; 412 413 // look at the rowHitFlag set by estimateLatency 414 if (rowHitFlag) 415 writeRowHits++; 416 417 Bank& bank = dram_pkt->bank_ref; 418 419 if (pageMgmt == Enums::open) { 420 bank.openRow = dram_pkt->row; 421 bank.freeAt = schedTime + tBURST + std::max(accessLat, tCL); 422 busBusyUntil = bank.freeAt - tCL; 423 bank.bytesAccessed += burstSize; 424 425 if (!rowHitFlag) { 426 actTick = bank.freeAt - tCL - tRCD;//new row opened 427 bank.tRASDoneAt = actTick + tRAS; 428 recordActivate(actTick); 429 busBusyUntil = actTick; 430 431 // sample the number of bytes accessed and reset it as 432 // we are now closing this row 433 bytesPerActivate.sample(bank.bytesAccessed); 434 bank.bytesAccessed = 0; 435 } 436 } else if (pageMgmt == Enums::close) { 437 // All ticks waiting for a bank (if required) are included 438 // in accessLat 439 actTick = schedTime + tBURST + accessLat - tCL - tRCD; 440 recordActivate(actTick); 441 442 // If the DRAM has a very quick tRAS, bank can be made free 443 // after consecutive tCL,tRCD,tRP times. In general, however, 444 // an additional wait is required to respect tRAS. 445 bank.freeAt = std::max(actTick + tRAS + tRP, 446 actTick + tCL + tRCD + tRP); 447 448 //assuming that DRAM first gets write data, then activates 449 busBusyUntil = actTick; 450 DPRINTF(DRAMWR, "processWriteEvent::bank.freeAt for " 451 "banks_id %d is %lld\n", 452 dram_pkt->rank * banksPerRank + dram_pkt->bank, 453 bank.freeAt); 454 bytesPerActivate.sample(burstSize); 455 } else 456 panic("Unknown page management policy chosen\n"); 457 458 DPRINTF(DRAMWR, "Done writing to address %lld\n", dram_pkt->addr); 459 460 DPRINTF(DRAMWR, "schedtime is %lld, tBURST is %lld, " 461 "busbusyuntil is %lld\n", 462 schedTime, tBURST, busBusyUntil); 463 464 writeQueue.pop_front(); 465 delete dram_pkt; 466 467 numWritesThisTime++; 468 } 469 470 DPRINTF(DRAMWR, "Completed %d writes, bus busy for %lld ticks,"\ 471 "banks busy for %lld ticks\n", numWritesThisTime, 472 busBusyUntil - temp1, maxBankFreeAt() - temp2); 473 474 // Update stats 475 avgWrQLen = writeQueue.size(); 476 477 // turn the bus back around for reads again 478 busBusyUntil += tWTR; 479 stopReads = false; 480 481 if (retryWrReq) { 482 retryWrReq = false; 483 port.sendRetry(); 484 } 485 486 // if there is nothing left in any queue, signal a drain 487 if (writeQueue.empty() && readQueue.empty() && 488 respQueue.empty () && drainManager) { 489 drainManager->signalDrainDone(); 490 drainManager = NULL; 491 } 492 493 // Once you're done emptying the write queue, check if there's 494 // anything in the read queue, and call schedule if required. The 495 // retry above could already have caused it to be scheduled, so 496 // first check 497 if (!nextReqEvent.scheduled()) 498 schedule(nextReqEvent, busBusyUntil); 499} 500 501void 502SimpleDRAM::triggerWrites() 503{ 504 DPRINTF(DRAM, "Writes triggered at %lld\n", curTick()); 505 // Flag variable to stop any more read scheduling 506 stopReads = true; 507 508 writeStartTime = std::max(busBusyUntil, curTick()) + tWTR; 509 510 DPRINTF(DRAM, "Writes scheduled at %lld\n", writeStartTime); 511 512 assert(writeStartTime >= curTick()); 513 assert(!writeEvent.scheduled()); 514 schedule(writeEvent, writeStartTime); 515} 516 517void 518SimpleDRAM::addToWriteQueue(PacketPtr pkt, unsigned int pktCount) 519{ 520 // only add to the write queue here. whenever the request is 521 // eventually done, set the readyTime, and call schedule() 522 assert(pkt->isWrite()); 523 524 // if the request size is larger than burst size, the pkt is split into 525 // multiple DRAM packets 526 Addr addr = pkt->getAddr(); 527 for (int cnt = 0; cnt < pktCount; ++cnt) { 528 unsigned size = std::min((addr | (burstSize - 1)) + 1, 529 pkt->getAddr() + pkt->getSize()) - addr; 530 writePktSize[ceilLog2(size)]++; 531 writeBursts++; 532 533 // see if we can merge with an existing item in the write 534 // queue and keep track of whether we have merged or not so we 535 // can stop at that point and also avoid enqueueing a new 536 // request 537 bool merged = false; 538 auto w = writeQueue.begin(); 539 540 while(!merged && w != writeQueue.end()) { 541 // either of the two could be first, if they are the same 542 // it does not matter which way we go 543 if ((*w)->addr >= addr) { 544 // the existing one starts after the new one, figure 545 // out where the new one ends with respect to the 546 // existing one 547 if ((addr + size) >= ((*w)->addr + (*w)->size)) { 548 // check if the existing one is completely 549 // subsumed in the new one 550 DPRINTF(DRAM, "Merging write covering existing burst\n"); 551 merged = true; 552 // update both the address and the size 553 (*w)->addr = addr; 554 (*w)->size = size; 555 } else if ((addr + size) >= (*w)->addr && 556 ((*w)->addr + (*w)->size - addr) <= burstSize) { 557 // the new one is just before or partially 558 // overlapping with the existing one, and together 559 // they fit within a burst 560 DPRINTF(DRAM, "Merging write before existing burst\n"); 561 merged = true; 562 // the existing queue item needs to be adjusted with 563 // respect to both address and size 564 (*w)->addr = addr; 565 (*w)->size = (*w)->addr + (*w)->size - addr; 566 } 567 } else { 568 // the new one starts after the current one, figure 569 // out where the existing one ends with respect to the 570 // new one 571 if (((*w)->addr + (*w)->size) >= (addr + size)) { 572 // check if the new one is completely subsumed in the 573 // existing one 574 DPRINTF(DRAM, "Merging write into existing burst\n"); 575 merged = true; 576 // no adjustments necessary 577 } else if (((*w)->addr + (*w)->size) >= addr && 578 (addr + size - (*w)->addr) <= burstSize) { 579 // the existing one is just before or partially 580 // overlapping with the new one, and together 581 // they fit within a burst 582 DPRINTF(DRAM, "Merging write after existing burst\n"); 583 merged = true; 584 // the address is right, and only the size has 585 // to be adjusted 586 (*w)->size = addr + size - (*w)->addr; 587 } 588 } 589 ++w; 590 } 591 592 // if the item was not merged we need to create a new write 593 // and enqueue it 594 if (!merged) { 595 DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size); 596 597 assert(writeQueue.size() < writeBufferSize); 598 wrQLenPdf[writeQueue.size()]++; 599 600 DPRINTF(DRAM, "Adding to write queue\n"); 601 602 writeQueue.push_back(dram_pkt); 603 604 // Update stats 605 uint32_t bank_id = banksPerRank * dram_pkt->rank + dram_pkt->bank; 606 assert(bank_id < ranksPerChannel * banksPerRank); 607 perBankWrReqs[bank_id]++; 608 609 avgWrQLen = writeQueue.size(); 610 } 611 612 bytesConsumedWr += size; 613 bytesWritten += burstSize; 614 615 // Starting address of next dram pkt (aligend to burstSize boundary) 616 addr = (addr | (burstSize - 1)) + 1; 617 } 618 619 // we do not wait for the writes to be send to the actual memory, 620 // but instead take responsibility for the consistency here and 621 // snoop the write queue for any upcoming reads 622 // @todo, if a pkt size is larger than burst size, we might need a 623 // different front end latency 624 accessAndRespond(pkt, frontendLatency); 625 626 // If your write buffer is starting to fill up, drain it! 627 if (writeQueue.size() > writeThreshold && !stopReads){ 628 triggerWrites(); 629 } 630} 631 632void 633SimpleDRAM::printParams() const 634{ 635 // Sanity check print of important parameters 636 DPRINTF(DRAM, 637 "Memory controller %s physical organization\n" \ 638 "Number of devices per rank %d\n" \ 639 "Device bus width (in bits) %d\n" \ 640 "DRAM data bus burst %d\n" \ 641 "Row buffer size %d\n" \ 642 "Columns per row buffer %d\n" \ 643 "Rows per bank %d\n" \ 644 "Banks per rank %d\n" \ 645 "Ranks per channel %d\n" \ 646 "Total mem capacity %u\n", 647 name(), devicesPerRank, deviceBusWidth, burstSize, rowBufferSize, 648 columnsPerRowBuffer, rowsPerBank, banksPerRank, ranksPerChannel, 649 rowBufferSize * rowsPerBank * banksPerRank * ranksPerChannel); 650 651 string scheduler = memSchedPolicy == Enums::fcfs ? "FCFS" : "FR-FCFS"; 652 string address_mapping = addrMapping == Enums::RaBaChCo ? "RaBaChCo" : 653 (addrMapping == Enums::RaBaCoCh ? "RaBaCoCh" : "CoRaBaCh"); 654 string page_policy = pageMgmt == Enums::open ? "OPEN" : "CLOSE"; 655 656 DPRINTF(DRAM, 657 "Memory controller %s characteristics\n" \ 658 "Read buffer size %d\n" \ 659 "Write buffer size %d\n" \ 660 "Write buffer thresh %d\n" \ 661 "Scheduler %s\n" \ 662 "Address mapping %s\n" \ 663 "Page policy %s\n", 664 name(), readBufferSize, writeBufferSize, writeThreshold, 665 scheduler, address_mapping, page_policy); 666 667 DPRINTF(DRAM, "Memory controller %s timing specs\n" \ 668 "tRCD %d ticks\n" \ 669 "tCL %d ticks\n" \ 670 "tRP %d ticks\n" \ 671 "tBURST %d ticks\n" \ 672 "tRFC %d ticks\n" \ 673 "tREFI %d ticks\n" \ 674 "tWTR %d ticks\n" \ 675 "tXAW (%d) %d ticks\n", 676 name(), tRCD, tCL, tRP, tBURST, tRFC, tREFI, tWTR, 677 activationLimit, tXAW); 678} 679 680void 681SimpleDRAM::printQs() const { 682 DPRINTF(DRAM, "===READ QUEUE===\n\n"); 683 for (auto i = readQueue.begin() ; i != readQueue.end() ; ++i) { 684 DPRINTF(DRAM, "Read %lu\n", (*i)->addr); 685 } 686 DPRINTF(DRAM, "\n===RESP QUEUE===\n\n"); 687 for (auto i = respQueue.begin() ; i != respQueue.end() ; ++i) { 688 DPRINTF(DRAM, "Response %lu\n", (*i)->addr); 689 } 690 DPRINTF(DRAM, "\n===WRITE QUEUE===\n\n"); 691 for (auto i = writeQueue.begin() ; i != writeQueue.end() ; ++i) { 692 DPRINTF(DRAM, "Write %lu\n", (*i)->addr); 693 } 694} 695 696bool 697SimpleDRAM::recvTimingReq(PacketPtr pkt) 698{ 699 /// @todo temporary hack to deal with memory corruption issues until 700 /// 4-phase transactions are complete 701 for (int x = 0; x < pendingDelete.size(); x++) 702 delete pendingDelete[x]; 703 pendingDelete.clear(); 704 705 // This is where we enter from the outside world 706 DPRINTF(DRAM, "recvTimingReq: request %s addr %lld size %d\n", 707 pkt->cmdString(), pkt->getAddr(), pkt->getSize()); 708 709 // simply drop inhibited packets for now 710 if (pkt->memInhibitAsserted()) { 711 DPRINTF(DRAM,"Inhibited packet -- Dropping it now\n"); 712 pendingDelete.push_back(pkt); 713 return true; 714 } 715 716 // Every million accesses, print the state of the queues 717 if (numReqs % 1000000 == 0) 718 printQs(); 719 720 // Calc avg gap between requests 721 if (prevArrival != 0) { 722 totGap += curTick() - prevArrival; 723 } 724 prevArrival = curTick(); 725 726 727 // Find out how many dram packets a pkt translates to 728 // If the burst size is equal or larger than the pkt size, then a pkt 729 // translates to only one dram packet. Otherwise, a pkt translates to 730 // multiple dram packets 731 unsigned size = pkt->getSize(); 732 unsigned offset = pkt->getAddr() & (burstSize - 1); 733 unsigned int dram_pkt_count = divCeil(offset + size, burstSize); 734 735 // check local buffers and do not accept if full 736 if (pkt->isRead()) { 737 assert(size != 0); 738 if (readQueueFull(dram_pkt_count)) { 739 DPRINTF(DRAM, "Read queue full, not accepting\n"); 740 // remember that we have to retry this port 741 retryRdReq = true; 742 numRdRetry++; 743 return false; 744 } else { 745 addToReadQueue(pkt, dram_pkt_count); 746 readReqs++; 747 numReqs++; 748 } 749 } else if (pkt->isWrite()) { 750 assert(size != 0); 751 if (writeQueueFull(dram_pkt_count)) { 752 DPRINTF(DRAM, "Write queue full, not accepting\n"); 753 // remember that we have to retry this port 754 retryWrReq = true; 755 numWrRetry++; 756 return false; 757 } else { 758 addToWriteQueue(pkt, dram_pkt_count); 759 writeReqs++; 760 numReqs++; 761 } 762 } else { 763 DPRINTF(DRAM,"Neither read nor write, ignore timing\n"); 764 neitherReadNorWrite++; 765 accessAndRespond(pkt, 1); 766 } 767 768 retryRdReq = false; 769 retryWrReq = false; 770 return true; 771} 772 773void 774SimpleDRAM::processRespondEvent() 775{ 776 DPRINTF(DRAM, 777 "processRespondEvent(): Some req has reached its readyTime\n"); 778 779 DRAMPacket* dram_pkt = respQueue.front(); 780 781 // Actually responds to the requestor 782 bytesConsumedRd += dram_pkt->size; 783 bytesRead += burstSize; 784 if (dram_pkt->burstHelper) { 785 // it is a split packet 786 dram_pkt->burstHelper->burstsServiced++; 787 if (dram_pkt->burstHelper->burstsServiced == 788 dram_pkt->burstHelper->burstCount) { 789 // we have now serviced all children packets of a system packet 790 // so we can now respond to the requester 791 // @todo we probably want to have a different front end and back 792 // end latency for split packets 793 accessAndRespond(dram_pkt->pkt, frontendLatency + backendLatency); 794 delete dram_pkt->burstHelper; 795 dram_pkt->burstHelper = NULL; 796 } 797 } else { 798 // it is not a split packet 799 accessAndRespond(dram_pkt->pkt, frontendLatency + backendLatency); 800 } 801 802 delete respQueue.front(); 803 respQueue.pop_front(); 804 805 // Update stats 806 avgRdQLen = readQueue.size() + respQueue.size(); 807 808 if (!respQueue.empty()) { 809 assert(respQueue.front()->readyTime >= curTick()); 810 assert(!respondEvent.scheduled()); 811 schedule(respondEvent, respQueue.front()->readyTime); 812 } else { 813 // if there is nothing left in any queue, signal a drain 814 if (writeQueue.empty() && readQueue.empty() && 815 drainManager) { 816 drainManager->signalDrainDone(); 817 drainManager = NULL; 818 } 819 } 820 821 // We have made a location in the queue available at this point, 822 // so if there is a read that was forced to wait, retry now 823 if (retryRdReq) { 824 retryRdReq = false; 825 port.sendRetry(); 826 } 827} 828 829void 830SimpleDRAM::chooseNextWrite() 831{ 832 // This method does the arbitration between write requests. The 833 // chosen packet is simply moved to the head of the write 834 // queue. The other methods know that this is the place to 835 // look. For example, with FCFS, this method does nothing 836 assert(!writeQueue.empty()); 837 838 if (writeQueue.size() == 1) { 839 DPRINTF(DRAMWR, "Single write request, nothing to do\n"); 840 return; 841 } 842 843 if (memSchedPolicy == Enums::fcfs) { 844 // Do nothing, since the correct request is already head 845 } else if (memSchedPolicy == Enums::frfcfs) { 846 auto i = writeQueue.begin(); 847 bool foundRowHit = false; 848 while (!foundRowHit && i != writeQueue.end()) { 849 DRAMPacket* dram_pkt = *i; 850 const Bank& bank = dram_pkt->bank_ref; 851 if (bank.openRow == dram_pkt->row) { //FR part 852 DPRINTF(DRAMWR, "Write row buffer hit\n"); 853 writeQueue.erase(i); 854 writeQueue.push_front(dram_pkt); 855 foundRowHit = true; 856 } else { //FCFS part 857 ; 858 } 859 ++i; 860 } 861 } else 862 panic("No scheduling policy chosen\n"); 863 864 DPRINTF(DRAMWR, "Selected next write request\n"); 865} 866 867bool 868SimpleDRAM::chooseNextRead() 869{ 870 // This method does the arbitration between read requests. The 871 // chosen packet is simply moved to the head of the queue. The 872 // other methods know that this is the place to look. For example, 873 // with FCFS, this method does nothing 874 if (readQueue.empty()) { 875 DPRINTF(DRAM, "No read request to select\n"); 876 return false; 877 } 878 879 // If there is only one request then there is nothing left to do 880 if (readQueue.size() == 1) 881 return true; 882 883 if (memSchedPolicy == Enums::fcfs) { 884 // Do nothing, since the request to serve is already the first 885 // one in the read queue 886 } else if (memSchedPolicy == Enums::frfcfs) { 887 for (auto i = readQueue.begin(); i != readQueue.end() ; ++i) { 888 DRAMPacket* dram_pkt = *i; 889 const Bank& bank = dram_pkt->bank_ref; 890 // Check if it is a row hit 891 if (bank.openRow == dram_pkt->row) { //FR part 892 DPRINTF(DRAM, "Row buffer hit\n"); 893 readQueue.erase(i); 894 readQueue.push_front(dram_pkt); 895 break; 896 } else { //FCFS part 897 ; 898 } 899 } 900 } else 901 panic("No scheduling policy chosen!\n"); 902 903 DPRINTF(DRAM, "Selected next read request\n"); 904 return true; 905} 906 907void 908SimpleDRAM::accessAndRespond(PacketPtr pkt, Tick static_latency) 909{ 910 DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr()); 911 912 bool needsResponse = pkt->needsResponse(); 913 // do the actual memory access which also turns the packet into a 914 // response 915 access(pkt); 916 917 // turn packet around to go back to requester if response expected 918 if (needsResponse) { 919 // access already turned the packet into a response 920 assert(pkt->isResponse()); 921 922 // @todo someone should pay for this 923 pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; 924 925 // queue the packet in the response queue to be sent out after 926 // the static latency has passed 927 port.schedTimingResp(pkt, curTick() + static_latency); 928 } else { 929 // @todo the packet is going to be deleted, and the DRAMPacket 930 // is still having a pointer to it 931 pendingDelete.push_back(pkt); 932 } 933 934 DPRINTF(DRAM, "Done\n"); 935 936 return; 937} 938 939pair<Tick, Tick> 940SimpleDRAM::estimateLatency(DRAMPacket* dram_pkt, Tick inTime) 941{ 942 // If a request reaches a bank at tick 'inTime', how much time 943 // *after* that does it take to finish the request, depending 944 // on bank status and page open policy. Note that this method 945 // considers only the time taken for the actual read or write 946 // to complete, NOT any additional time thereafter for tRAS or 947 // tRP. 948 Tick accLat = 0; 949 Tick bankLat = 0; 950 rowHitFlag = false; 951 952 const Bank& bank = dram_pkt->bank_ref; 953 if (pageMgmt == Enums::open) { // open-page policy 954 if (bank.openRow == dram_pkt->row) { 955 // When we have a row-buffer hit, 956 // we don't care about tRAS having expired or not, 957 // but do care about bank being free for access 958 rowHitFlag = true; 959 960 if (bank.freeAt < inTime) { 961 // CAS latency only 962 accLat += tCL; 963 bankLat += tCL; 964 } else { 965 accLat += 0; 966 bankLat += 0; 967 } 968 969 } else { 970 // Row-buffer miss, need to close existing row 971 // once tRAS has expired, then open the new one, 972 // then add cas latency. 973 Tick freeTime = std::max(bank.tRASDoneAt, bank.freeAt); 974 975 if (freeTime > inTime) 976 accLat += freeTime - inTime; 977 978 accLat += tRP + tRCD + tCL; 979 bankLat += tRP + tRCD + tCL; 980 } 981 } else if (pageMgmt == Enums::close) { 982 // With a close page policy, no notion of 983 // bank.tRASDoneAt 984 if (bank.freeAt > inTime) 985 accLat += bank.freeAt - inTime; 986 987 // page already closed, simply open the row, and 988 // add cas latency 989 accLat += tRCD + tCL; 990 bankLat += tRCD + tCL; 991 } else 992 panic("No page management policy chosen\n"); 993 994 DPRINTF(DRAM, "Returning < %lld, %lld > from estimateLatency()\n", 995 bankLat, accLat); 996 997 return make_pair(bankLat, accLat); 998} 999 1000void 1001SimpleDRAM::processNextReqEvent() 1002{ 1003 scheduleNextReq(); 1004} 1005 1006void 1007SimpleDRAM::recordActivate(Tick act_tick) 1008{ 1009 assert(actTicks.size() == activationLimit); 1010 1011 DPRINTF(DRAM, "Activate at tick %d\n", act_tick); 1012 1013 // if the activation limit is disabled then we are done 1014 if (actTicks.empty()) 1015 return; 1016 1017 // sanity check 1018 if (actTicks.back() && (act_tick - actTicks.back()) < tXAW) { 1019 // @todo For now, stick with a warning 1020 warn("Got %d activates in window %d (%d - %d) which is smaller " 1021 "than %d\n", activationLimit, act_tick - actTicks.back(), 1022 act_tick, actTicks.back(), tXAW); 1023 } 1024 1025 // shift the times used for the book keeping, the last element 1026 // (highest index) is the oldest one and hence the lowest value 1027 actTicks.pop_back(); 1028 1029 // record an new activation (in the future) 1030 actTicks.push_front(act_tick); 1031 1032 // cannot activate more than X times in time window tXAW, push the 1033 // next one (the X + 1'st activate) to be tXAW away from the 1034 // oldest in our window of X 1035 if (actTicks.back() && (act_tick - actTicks.back()) < tXAW) { 1036 DPRINTF(DRAM, "Enforcing tXAW with X = %d, next activate no earlier " 1037 "than %d\n", activationLimit, actTicks.back() + tXAW); 1038 for(int i = 0; i < ranksPerChannel; i++) 1039 for(int j = 0; j < banksPerRank; j++) 1040 // next activate must not happen before end of window 1041 banks[i][j].freeAt = std::max(banks[i][j].freeAt, 1042 actTicks.back() + tXAW); 1043 } 1044} 1045 1046void 1047SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt) 1048{ 1049 1050 DPRINTF(DRAM, "Timing access to addr %lld, rank/bank/row %d %d %d\n", 1051 dram_pkt->addr, dram_pkt->rank, dram_pkt->bank, dram_pkt->row); 1052 1053 // estimate the bank and access latency 1054 pair<Tick, Tick> lat = estimateLatency(dram_pkt, curTick()); 1055 Tick bankLat = lat.first; 1056 Tick accessLat = lat.second; 1057 Tick actTick; 1058 1059 // This request was woken up at this time based on a prior call 1060 // to estimateLatency(). However, between then and now, both the 1061 // accessLatency and/or busBusyUntil may have changed. We need 1062 // to correct for that. 1063 1064 Tick addDelay = (curTick() + accessLat < busBusyUntil) ? 1065 busBusyUntil - (curTick() + accessLat) : 0; 1066 1067 Bank& bank = dram_pkt->bank_ref; 1068 1069 // Update bank state 1070 if (pageMgmt == Enums::open) { 1071 bank.openRow = dram_pkt->row; 1072 bank.freeAt = curTick() + addDelay + accessLat; 1073 bank.bytesAccessed += burstSize; 1074 1075 // If you activated a new row do to this access, the next access 1076 // will have to respect tRAS for this bank. 1077 if (!rowHitFlag) { 1078 // any waiting for banks account for in freeAt 1079 actTick = bank.freeAt - tCL - tRCD; 1080 bank.tRASDoneAt = actTick + tRAS; 1081 recordActivate(actTick); 1082 1083 // sample the number of bytes accessed and reset it as 1084 // we are now closing this row 1085 bytesPerActivate.sample(bank.bytesAccessed); 1086 bank.bytesAccessed = 0; 1087 } 1088 } else if (pageMgmt == Enums::close) { 1089 actTick = curTick() + addDelay + accessLat - tRCD - tCL; 1090 recordActivate(actTick); 1091 1092 // If the DRAM has a very quick tRAS, bank can be made free 1093 // after consecutive tCL,tRCD,tRP times. In general, however, 1094 // an additional wait is required to respect tRAS. 1095 bank.freeAt = std::max(actTick + tRAS + tRP, 1096 actTick + tRCD + tCL + tRP); 1097 1098 DPRINTF(DRAM,"doDRAMAccess::bank.freeAt is %lld\n",bank.freeAt); 1099 bytesPerActivate.sample(burstSize); 1100 } else 1101 panic("No page management policy chosen\n"); 1102 1103 // Update request parameters 1104 dram_pkt->readyTime = curTick() + addDelay + accessLat + tBURST; 1105 1106 1107 DPRINTF(DRAM, "Req %lld: curtick is %lld accessLat is %d " \ 1108 "readytime is %lld busbusyuntil is %lld. " \ 1109 "Scheduling at readyTime\n", dram_pkt->addr, 1110 curTick(), accessLat, dram_pkt->readyTime, busBusyUntil); 1111 1112 // Make sure requests are not overlapping on the databus 1113 assert (dram_pkt->readyTime - busBusyUntil >= tBURST); 1114 1115 // Update bus state 1116 busBusyUntil = dram_pkt->readyTime; 1117 1118 DPRINTF(DRAM,"Access time is %lld\n", 1119 dram_pkt->readyTime - dram_pkt->entryTime); 1120 1121 // Update stats 1122 totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime; 1123 totBankLat += bankLat; 1124 totBusLat += tBURST; 1125 totQLat += dram_pkt->readyTime - dram_pkt->entryTime - bankLat - tBURST; 1126 1127 if (rowHitFlag) 1128 readRowHits++; 1129 1130 // At this point we're done dealing with the request 1131 // It will be moved to a separate response queue with a 1132 // correct readyTime, and eventually be sent back at that 1133 //time 1134 moveToRespQ(); 1135 1136 // The absolute soonest you have to start thinking about the 1137 // next request is the longest access time that can occur before 1138 // busBusyUntil. Assuming you need to meet tRAS, then precharge, 1139 // open a new row, and access, it is ~4*tRCD. 1140 1141 1142 Tick newTime = (busBusyUntil > 4 * tRCD) ? 1143 std::max(busBusyUntil - 4 * tRCD, curTick()) : 1144 curTick(); 1145 1146 if (!nextReqEvent.scheduled() && !stopReads){ 1147 schedule(nextReqEvent, newTime); 1148 } else { 1149 if (newTime < nextReqEvent.when()) 1150 reschedule(nextReqEvent, newTime); 1151 } 1152 1153 1154} 1155 1156void 1157SimpleDRAM::moveToRespQ() 1158{ 1159 // Remove from read queue 1160 DRAMPacket* dram_pkt = readQueue.front(); 1161 readQueue.pop_front(); 1162 1163 // sanity check 1164 assert(dram_pkt->size <= burstSize); 1165 1166 // Insert into response queue sorted by readyTime 1167 // It will be sent back to the requestor at its 1168 // readyTime 1169 if (respQueue.empty()) { 1170 respQueue.push_front(dram_pkt); 1171 assert(!respondEvent.scheduled()); 1172 assert(dram_pkt->readyTime >= curTick()); 1173 schedule(respondEvent, dram_pkt->readyTime); 1174 } else { 1175 bool done = false; 1176 auto i = respQueue.begin(); 1177 while (!done && i != respQueue.end()) { 1178 if ((*i)->readyTime > dram_pkt->readyTime) { 1179 respQueue.insert(i, dram_pkt); 1180 done = true; 1181 } 1182 ++i; 1183 } 1184 1185 if (!done) 1186 respQueue.push_back(dram_pkt); 1187 1188 assert(respondEvent.scheduled()); 1189 1190 if (respQueue.front()->readyTime < respondEvent.when()) { 1191 assert(respQueue.front()->readyTime >= curTick()); 1192 reschedule(respondEvent, respQueue.front()->readyTime); 1193 } 1194 } 1195} 1196 1197void 1198SimpleDRAM::scheduleNextReq() 1199{ 1200 DPRINTF(DRAM, "Reached scheduleNextReq()\n"); 1201 1202 // Figure out which read request goes next, and move it to the 1203 // front of the read queue 1204 if (!chooseNextRead()) { 1205 // In the case there is no read request to go next, see if we 1206 // are asked to drain, and if so trigger writes, this also 1207 // ensures that if we hit the write limit we will do this 1208 // multiple times until we are completely drained 1209 if (drainManager && !writeQueue.empty() && !writeEvent.scheduled()) 1210 triggerWrites(); 1211 } else { 1212 doDRAMAccess(readQueue.front()); 1213 } 1214} 1215 1216Tick 1217SimpleDRAM::maxBankFreeAt() const 1218{ 1219 Tick banksFree = 0; 1220 1221 for(int i = 0; i < ranksPerChannel; i++) 1222 for(int j = 0; j < banksPerRank; j++) 1223 banksFree = std::max(banks[i][j].freeAt, banksFree); 1224 1225 return banksFree; 1226} 1227 1228void 1229SimpleDRAM::processRefreshEvent() 1230{ 1231 DPRINTF(DRAM, "Refreshing at tick %ld\n", curTick()); 1232 1233 Tick banksFree = std::max(curTick(), maxBankFreeAt()) + tRFC; 1234 1235 for(int i = 0; i < ranksPerChannel; i++) 1236 for(int j = 0; j < banksPerRank; j++) 1237 banks[i][j].freeAt = banksFree; 1238 1239 schedule(refreshEvent, curTick() + tREFI); 1240} 1241 1242void 1243SimpleDRAM::regStats() 1244{ 1245 using namespace Stats; 1246 1247 AbstractMemory::regStats(); 1248 1249 readReqs 1250 .name(name() + ".readReqs") 1251 .desc("Total number of read requests accepted by DRAM controller"); 1252 1253 writeReqs 1254 .name(name() + ".writeReqs") 1255 .desc("Total number of write requests accepted by DRAM controller"); 1256 1257 readBursts 1258 .name(name() + ".readBursts") 1259 .desc("Total number of DRAM read bursts. " 1260 "Each DRAM read request translates to either one or multiple " 1261 "DRAM read bursts"); 1262 1263 writeBursts 1264 .name(name() + ".writeBursts") 1265 .desc("Total number of DRAM write bursts. " 1266 "Each DRAM write request translates to either one or multiple " 1267 "DRAM write bursts"); 1268 1269 servicedByWrQ 1270 .name(name() + ".servicedByWrQ") 1271 .desc("Number of DRAM read bursts serviced by write Q"); 1272 1273 neitherReadNorWrite 1274 .name(name() + ".neitherReadNorWrite") 1275 .desc("Reqs where no action is needed"); 1276 1277 perBankRdReqs 1278 .init(banksPerRank * ranksPerChannel) 1279 .name(name() + ".perBankRdReqs") 1280 .desc("Track reads on a per bank basis"); 1281 1282 perBankWrReqs 1283 .init(banksPerRank * ranksPerChannel) 1284 .name(name() + ".perBankWrReqs") 1285 .desc("Track writes on a per bank basis"); 1286 1287 avgRdQLen 1288 .name(name() + ".avgRdQLen") 1289 .desc("Average read queue length over time") 1290 .precision(2); 1291 1292 avgWrQLen 1293 .name(name() + ".avgWrQLen") 1294 .desc("Average write queue length over time") 1295 .precision(2); 1296 1297 totQLat 1298 .name(name() + ".totQLat") 1299 .desc("Total cycles spent in queuing delays"); 1300 1301 totBankLat 1302 .name(name() + ".totBankLat") 1303 .desc("Total cycles spent in bank access"); 1304 1305 totBusLat 1306 .name(name() + ".totBusLat") 1307 .desc("Total cycles spent in databus access"); 1308 1309 totMemAccLat 1310 .name(name() + ".totMemAccLat") 1311 .desc("Sum of mem lat for all requests"); 1312 1313 avgQLat 1314 .name(name() + ".avgQLat") 1315 .desc("Average queueing delay per request") 1316 .precision(2); 1317 1318 avgQLat = totQLat / (readBursts - servicedByWrQ); 1319 1320 avgBankLat 1321 .name(name() + ".avgBankLat") 1322 .desc("Average bank access latency per request") 1323 .precision(2); 1324 1325 avgBankLat = totBankLat / (readBursts - servicedByWrQ); 1326 1327 avgBusLat 1328 .name(name() + ".avgBusLat") 1329 .desc("Average bus latency per request") 1330 .precision(2); 1331 1332 avgBusLat = totBusLat / (readBursts - servicedByWrQ); 1333 1334 avgMemAccLat 1335 .name(name() + ".avgMemAccLat") 1336 .desc("Average memory access latency") 1337 .precision(2); 1338 1339 avgMemAccLat = totMemAccLat / (readBursts - servicedByWrQ); 1340 1341 numRdRetry 1342 .name(name() + ".numRdRetry") 1343 .desc("Number of times rd buffer was full causing retry"); 1344 1345 numWrRetry 1346 .name(name() + ".numWrRetry") 1347 .desc("Number of times wr buffer was full causing retry"); 1348 1349 readRowHits 1350 .name(name() + ".readRowHits") 1351 .desc("Number of row buffer hits during reads"); 1352 1353 writeRowHits 1354 .name(name() + ".writeRowHits") 1355 .desc("Number of row buffer hits during writes"); 1356 1357 readRowHitRate 1358 .name(name() + ".readRowHitRate") 1359 .desc("Row buffer hit rate for reads") 1360 .precision(2); 1361 1362 readRowHitRate = (readRowHits / (readBursts - servicedByWrQ)) * 100; 1363 1364 writeRowHitRate 1365 .name(name() + ".writeRowHitRate") 1366 .desc("Row buffer hit rate for writes") 1367 .precision(2); 1368 1369 writeRowHitRate = (writeRowHits / writeBursts) * 100; 1370 1371 readPktSize 1372 .init(ceilLog2(burstSize) + 1) 1373 .name(name() + ".readPktSize") 1374 .desc("Categorize read packet sizes"); 1375 1376 writePktSize 1377 .init(ceilLog2(burstSize) + 1) 1378 .name(name() + ".writePktSize") 1379 .desc("Categorize write packet sizes"); 1380 1381 rdQLenPdf 1382 .init(readBufferSize) 1383 .name(name() + ".rdQLenPdf") 1384 .desc("What read queue length does an incoming req see"); 1385 1386 wrQLenPdf 1387 .init(writeBufferSize) 1388 .name(name() + ".wrQLenPdf") 1389 .desc("What write queue length does an incoming req see"); 1390 1391 bytesPerActivate 1392 .init(rowBufferSize) 1393 .name(name() + ".bytesPerActivate") 1394 .desc("Bytes accessed per row activation") 1395 .flags(nozero); 1396 1397 bytesRead 1398 .name(name() + ".bytesRead") 1399 .desc("Total number of bytes read from memory"); 1400 1401 bytesWritten 1402 .name(name() + ".bytesWritten") 1403 .desc("Total number of bytes written to memory"); 1404 1405 bytesConsumedRd 1406 .name(name() + ".bytesConsumedRd") 1407 .desc("bytesRead derated as per pkt->getSize()"); 1408 1409 bytesConsumedWr 1410 .name(name() + ".bytesConsumedWr") 1411 .desc("bytesWritten derated as per pkt->getSize()"); 1412 1413 avgRdBW 1414 .name(name() + ".avgRdBW") 1415 .desc("Average achieved read bandwidth in MB/s") 1416 .precision(2); 1417 1418 avgRdBW = (bytesRead / 1000000) / simSeconds; 1419 1420 avgWrBW 1421 .name(name() + ".avgWrBW") 1422 .desc("Average achieved write bandwidth in MB/s") 1423 .precision(2); 1424 1425 avgWrBW = (bytesWritten / 1000000) / simSeconds; 1426 1427 avgConsumedRdBW 1428 .name(name() + ".avgConsumedRdBW") 1429 .desc("Average consumed read bandwidth in MB/s") 1430 .precision(2); 1431 1432 avgConsumedRdBW = (bytesConsumedRd / 1000000) / simSeconds; 1433 1434 avgConsumedWrBW 1435 .name(name() + ".avgConsumedWrBW") 1436 .desc("Average consumed write bandwidth in MB/s") 1437 .precision(2); 1438 1439 avgConsumedWrBW = (bytesConsumedWr / 1000000) / simSeconds; 1440 1441 peakBW 1442 .name(name() + ".peakBW") 1443 .desc("Theoretical peak bandwidth in MB/s") 1444 .precision(2); 1445 1446 peakBW = (SimClock::Frequency / tBURST) * burstSize / 1000000; 1447 1448 busUtil 1449 .name(name() + ".busUtil") 1450 .desc("Data bus utilization in percentage") 1451 .precision(2); 1452 1453 busUtil = (avgRdBW + avgWrBW) / peakBW * 100; 1454 1455 totGap 1456 .name(name() + ".totGap") 1457 .desc("Total gap between requests"); 1458 1459 avgGap 1460 .name(name() + ".avgGap") 1461 .desc("Average gap between requests") 1462 .precision(2); 1463 1464 avgGap = totGap / (readReqs + writeReqs); 1465} 1466 1467void 1468SimpleDRAM::recvFunctional(PacketPtr pkt) 1469{ 1470 // rely on the abstract memory 1471 functionalAccess(pkt); 1472} 1473 1474BaseSlavePort& 1475SimpleDRAM::getSlavePort(const string &if_name, PortID idx) 1476{ 1477 if (if_name != "port") { 1478 return MemObject::getSlavePort(if_name, idx); 1479 } else { 1480 return port; 1481 } 1482} 1483 1484unsigned int 1485SimpleDRAM::drain(DrainManager *dm) 1486{ 1487 unsigned int count = port.drain(dm); 1488 1489 // if there is anything in any of our internal queues, keep track 1490 // of that as well 1491 if (!(writeQueue.empty() && readQueue.empty() && 1492 respQueue.empty())) { 1493 DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d," 1494 " resp: %d\n", writeQueue.size(), readQueue.size(), 1495 respQueue.size()); 1496 ++count; 1497 drainManager = dm; 1498 // the only part that is not drained automatically over time 1499 // is the write queue, thus trigger writes if there are any 1500 // waiting and no reads waiting, otherwise wait until the 1501 // reads are done 1502 if (readQueue.empty() && !writeQueue.empty() && 1503 !writeEvent.scheduled()) 1504 triggerWrites(); 1505 } 1506 1507 if (count) 1508 setDrainState(Drainable::Draining); 1509 else 1510 setDrainState(Drainable::Drained); 1511 return count; 1512} 1513 1514SimpleDRAM::MemoryPort::MemoryPort(const std::string& name, SimpleDRAM& _memory) 1515 : QueuedSlavePort(name, &_memory, queue), queue(_memory, *this), 1516 memory(_memory) 1517{ } 1518 1519AddrRangeList 1520SimpleDRAM::MemoryPort::getAddrRanges() const 1521{ 1522 AddrRangeList ranges; 1523 ranges.push_back(memory.getAddrRange()); 1524 return ranges; 1525} 1526 1527void 1528SimpleDRAM::MemoryPort::recvFunctional(PacketPtr pkt) 1529{ 1530 pkt->pushLabel(memory.name()); 1531 1532 if (!queue.checkFunctional(pkt)) { 1533 // Default implementation of SimpleTimingPort::recvFunctional() 1534 // calls recvAtomic() and throws away the latency; we can save a 1535 // little here by just not calculating the latency. 1536 memory.recvFunctional(pkt); 1537 } 1538 1539 pkt->popLabel(); 1540} 1541 1542Tick 1543SimpleDRAM::MemoryPort::recvAtomic(PacketPtr pkt) 1544{ 1545 return memory.recvAtomic(pkt); 1546} 1547 1548bool 1549SimpleDRAM::MemoryPort::recvTimingReq(PacketPtr pkt) 1550{ 1551 // pass it to the memory controller 1552 return memory.recvTimingReq(pkt); 1553} 1554 1555SimpleDRAM* 1556SimpleDRAMParams::create() 1557{ 1558 return new SimpleDRAM(this); 1559} 1560