dram_ctrl.cc revision 10141
14661Sksewell@umich.edu/* 24661Sksewell@umich.edu * Copyright (c) 2010-2013 ARM Limited 34661Sksewell@umich.edu * All rights reserved 44661Sksewell@umich.edu * 54661Sksewell@umich.edu * The license below extends only to copyright in the software and shall 64661Sksewell@umich.edu * not be construed as granting a license to any other intellectual 74661Sksewell@umich.edu * property including but not limited to intellectual property relating 84661Sksewell@umich.edu * to a hardware implementation of the functionality of the software 94661Sksewell@umich.edu * licensed hereunder. You may use the software subject to the license 104661Sksewell@umich.edu * terms below provided that you ensure that this notice is replicated 114661Sksewell@umich.edu * unmodified and in its entirety in all distributions of the software, 124661Sksewell@umich.edu * modified or unmodified, in source code or in binary form. 134661Sksewell@umich.edu * 144661Sksewell@umich.edu * Copyright (c) 2013 Amin Farmahini-Farahani 154661Sksewell@umich.edu * All rights reserved. 164661Sksewell@umich.edu * 174661Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 184661Sksewell@umich.edu * modification, are permitted provided that the following conditions are 194661Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 204661Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 214661Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 224661Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 234661Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 244661Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 254661Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 264661Sksewell@umich.edu * this software without specific prior written permission. 274661Sksewell@umich.edu * 284661Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 294661Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 304661Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 314661Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 324661Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 334661Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 344661Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 354661Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 364661Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 374661Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 384661Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 394661Sksewell@umich.edu * 404661Sksewell@umich.edu * Authors: Andreas Hansson 414661Sksewell@umich.edu * Ani Udipi 424661Sksewell@umich.edu * Neha Agarwal 434661Sksewell@umich.edu */ 444661Sksewell@umich.edu 454661Sksewell@umich.edu#include "base/trace.hh" 464661Sksewell@umich.edu#include "base/bitfield.hh" 474661Sksewell@umich.edu#include "debug/Drain.hh" 484661Sksewell@umich.edu#include "debug/DRAM.hh" 494661Sksewell@umich.edu#include "mem/simple_dram.hh" 504661Sksewell@umich.edu#include "sim/system.hh" 514661Sksewell@umich.edu 524661Sksewell@umich.eduusing namespace std; 534661Sksewell@umich.edu 544661Sksewell@umich.eduSimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) : 554661Sksewell@umich.edu AbstractMemory(p), 564661Sksewell@umich.edu port(name() + ".port", *this), 574661Sksewell@umich.edu retryRdReq(false), retryWrReq(false), 584661Sksewell@umich.edu rowHitFlag(false), stopReads(false), 594661Sksewell@umich.edu writeEvent(this), respondEvent(this), 604661Sksewell@umich.edu refreshEvent(this), nextReqEvent(this), drainManager(NULL), 614661Sksewell@umich.edu deviceBusWidth(p->device_bus_width), burstLength(p->burst_length), 624661Sksewell@umich.edu deviceRowBufferSize(p->device_rowbuffer_size), 634661Sksewell@umich.edu devicesPerRank(p->devices_per_rank), 644661Sksewell@umich.edu burstSize((devicesPerRank * burstLength * deviceBusWidth) / 8), 654661Sksewell@umich.edu rowBufferSize(devicesPerRank * deviceRowBufferSize), 664661Sksewell@umich.edu columnsPerRowBuffer(rowBufferSize / burstSize), 674661Sksewell@umich.edu ranksPerChannel(p->ranks_per_channel), 684661Sksewell@umich.edu banksPerRank(p->banks_per_rank), channels(p->channels), rowsPerBank(0), 694661Sksewell@umich.edu readBufferSize(p->read_buffer_size), 704661Sksewell@umich.edu writeBufferSize(p->write_buffer_size), 714661Sksewell@umich.edu writeHighThreshold(writeBufferSize * p->write_high_thresh_perc / 100.0), 724661Sksewell@umich.edu writeLowThreshold(writeBufferSize * p->write_low_thresh_perc / 100.0), 734661Sksewell@umich.edu minWritesPerSwitch(p->min_writes_per_switch), writesThisTime(0), 744661Sksewell@umich.edu tWTR(p->tWTR), tBURST(p->tBURST), 754661Sksewell@umich.edu tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP), tRAS(p->tRAS), 764661Sksewell@umich.edu tRFC(p->tRFC), tREFI(p->tREFI), tRRD(p->tRRD), 774661Sksewell@umich.edu tXAW(p->tXAW), activationLimit(p->activation_limit), 784661Sksewell@umich.edu memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping), 794661Sksewell@umich.edu pageMgmt(p->page_policy), 804661Sksewell@umich.edu maxAccessesPerRow(p->max_accesses_per_row), 814661Sksewell@umich.edu frontendLatency(p->static_frontend_latency), 824661Sksewell@umich.edu backendLatency(p->static_backend_latency), 834661Sksewell@umich.edu busBusyUntil(0), writeStartTime(0), 844661Sksewell@umich.edu prevArrival(0), numReqs(0), 854661Sksewell@umich.edu newTime(0), startTickPrechargeAll(0), numBanksActive(0) 864661Sksewell@umich.edu{ 874661Sksewell@umich.edu // create the bank states based on the dimensions of the ranks and 884661Sksewell@umich.edu // banks 894661Sksewell@umich.edu banks.resize(ranksPerChannel); 904661Sksewell@umich.edu actTicks.resize(ranksPerChannel); 914661Sksewell@umich.edu for (size_t c = 0; c < ranksPerChannel; ++c) { 924661Sksewell@umich.edu banks[c].resize(banksPerRank); 934661Sksewell@umich.edu actTicks[c].resize(activationLimit, 0); 944661Sksewell@umich.edu } 954661Sksewell@umich.edu 964661Sksewell@umich.edu // perform a basic check of the write thresholds 974661Sksewell@umich.edu if (p->write_low_thresh_perc >= p->write_high_thresh_perc) 984661Sksewell@umich.edu fatal("Write buffer low threshold %d must be smaller than the " 994661Sksewell@umich.edu "high threshold %d\n", p->write_low_thresh_perc, 1004661Sksewell@umich.edu p->write_high_thresh_perc); 1014661Sksewell@umich.edu 1024661Sksewell@umich.edu // determine the rows per bank by looking at the total capacity 1034661Sksewell@umich.edu uint64_t capacity = ULL(1) << ceilLog2(AbstractMemory::size()); 1044661Sksewell@umich.edu 1054661Sksewell@umich.edu DPRINTF(DRAM, "Memory capacity %lld (%lld) bytes\n", capacity, 1064661Sksewell@umich.edu AbstractMemory::size()); 1074661Sksewell@umich.edu 1084661Sksewell@umich.edu DPRINTF(DRAM, "Row buffer size %d bytes with %d columns per row buffer\n", 1094661Sksewell@umich.edu rowBufferSize, columnsPerRowBuffer); 1104661Sksewell@umich.edu 1114661Sksewell@umich.edu rowsPerBank = capacity / (rowBufferSize * banksPerRank * ranksPerChannel); 1124661Sksewell@umich.edu 1134661Sksewell@umich.edu if (range.interleaved()) { 1144661Sksewell@umich.edu if (channels != range.stripes()) 1154661Sksewell@umich.edu panic("%s has %d interleaved address stripes but %d channel(s)\n", 1164661Sksewell@umich.edu name(), range.stripes(), channels); 1174661Sksewell@umich.edu 1184661Sksewell@umich.edu if (addrMapping == Enums::RoRaBaChCo) { 1194661Sksewell@umich.edu if (rowBufferSize != range.granularity()) { 1204661Sksewell@umich.edu panic("Interleaving of %s doesn't match RoRaBaChCo " 1214661Sksewell@umich.edu "address map\n", name()); 1224661Sksewell@umich.edu } 1234661Sksewell@umich.edu } else if (addrMapping == Enums::RoRaBaCoCh) { 1244661Sksewell@umich.edu if (system()->cacheLineSize() != range.granularity()) { 1254661Sksewell@umich.edu panic("Interleaving of %s doesn't match RoRaBaCoCh " 1264661Sksewell@umich.edu "address map\n", name()); 1274661Sksewell@umich.edu } 1284661Sksewell@umich.edu } else if (addrMapping == Enums::RoCoRaBaCh) { 1294661Sksewell@umich.edu if (system()->cacheLineSize() != range.granularity()) 1304661Sksewell@umich.edu panic("Interleaving of %s doesn't match RoCoRaBaCh " 1314661Sksewell@umich.edu "address map\n", name()); 1324661Sksewell@umich.edu } 1334661Sksewell@umich.edu } 1344661Sksewell@umich.edu} 1354661Sksewell@umich.edu 1364661Sksewell@umich.eduvoid 1374661Sksewell@umich.eduSimpleDRAM::init() 1384661Sksewell@umich.edu{ 1394661Sksewell@umich.edu if (!port.isConnected()) { 1404661Sksewell@umich.edu fatal("SimpleDRAM %s is unconnected!\n", name()); 1414661Sksewell@umich.edu } else { 1424661Sksewell@umich.edu port.sendRangeChange(); 1434661Sksewell@umich.edu } 1444661Sksewell@umich.edu} 1454661Sksewell@umich.edu 1464661Sksewell@umich.eduvoid 1474661Sksewell@umich.eduSimpleDRAM::startup() 1484661Sksewell@umich.edu{ 1494661Sksewell@umich.edu // print the configuration of the controller 1504661Sksewell@umich.edu printParams(); 1514661Sksewell@umich.edu 1524661Sksewell@umich.edu // kick off the refresh 1534661Sksewell@umich.edu schedule(refreshEvent, curTick() + tREFI); 1544661Sksewell@umich.edu} 1554661Sksewell@umich.edu 1564661Sksewell@umich.eduTick 1574661Sksewell@umich.eduSimpleDRAM::recvAtomic(PacketPtr pkt) 1584661Sksewell@umich.edu{ 1594661Sksewell@umich.edu DPRINTF(DRAM, "recvAtomic: %s 0x%x\n", pkt->cmdString(), pkt->getAddr()); 1604661Sksewell@umich.edu 1614661Sksewell@umich.edu // do the actual memory access and turn the packet into a response 1624661Sksewell@umich.edu access(pkt); 1634661Sksewell@umich.edu 1644661Sksewell@umich.edu Tick latency = 0; 1654661Sksewell@umich.edu if (!pkt->memInhibitAsserted() && pkt->hasData()) { 1664661Sksewell@umich.edu // this value is not supposed to be accurate, just enough to 1674661Sksewell@umich.edu // keep things going, mimic a closed page 1684661Sksewell@umich.edu latency = tRP + tRCD + tCL; 1694661Sksewell@umich.edu } 1704661Sksewell@umich.edu return latency; 1714661Sksewell@umich.edu} 1724661Sksewell@umich.edu 1734661Sksewell@umich.edubool 1744661Sksewell@umich.eduSimpleDRAM::readQueueFull(unsigned int neededEntries) const 1754661Sksewell@umich.edu{ 1764661Sksewell@umich.edu DPRINTF(DRAM, "Read queue limit %d, current size %d, entries needed %d\n", 1774661Sksewell@umich.edu readBufferSize, readQueue.size() + respQueue.size(), 1784661Sksewell@umich.edu neededEntries); 1794661Sksewell@umich.edu 1804661Sksewell@umich.edu return 1814661Sksewell@umich.edu (readQueue.size() + respQueue.size() + neededEntries) > readBufferSize; 1824661Sksewell@umich.edu} 1834661Sksewell@umich.edu 1844661Sksewell@umich.edubool 1854661Sksewell@umich.eduSimpleDRAM::writeQueueFull(unsigned int neededEntries) const 1864661Sksewell@umich.edu{ 1874661Sksewell@umich.edu DPRINTF(DRAM, "Write queue limit %d, current size %d, entries needed %d\n", 1884661Sksewell@umich.edu writeBufferSize, writeQueue.size(), neededEntries); 1894661Sksewell@umich.edu return (writeQueue.size() + neededEntries) > writeBufferSize; 1904661Sksewell@umich.edu} 1914661Sksewell@umich.edu 1924661Sksewell@umich.eduSimpleDRAM::DRAMPacket* 1934661Sksewell@umich.eduSimpleDRAM::decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned size, bool isRead) 1944661Sksewell@umich.edu{ 1954661Sksewell@umich.edu // decode the address based on the address mapping scheme, with 1964661Sksewell@umich.edu // Ro, Ra, Co, Ba and Ch denoting row, rank, column, bank and 1974661Sksewell@umich.edu // channel, respectively 1984661Sksewell@umich.edu uint8_t rank; 1994661Sksewell@umich.edu uint8_t bank; 2004661Sksewell@umich.edu uint16_t row; 2014661Sksewell@umich.edu 2024661Sksewell@umich.edu // truncate the address to the access granularity 2034661Sksewell@umich.edu Addr addr = dramPktAddr / burstSize; 2044661Sksewell@umich.edu 2054661Sksewell@umich.edu // we have removed the lowest order address bits that denote the 2064661Sksewell@umich.edu // position within the column 2074661Sksewell@umich.edu if (addrMapping == Enums::RoRaBaChCo) { 2084661Sksewell@umich.edu // the lowest order bits denote the column to ensure that 2094661Sksewell@umich.edu // sequential cache lines occupy the same row 2104661Sksewell@umich.edu addr = addr / columnsPerRowBuffer; 2114661Sksewell@umich.edu 2124661Sksewell@umich.edu // take out the channel part of the address 2134661Sksewell@umich.edu addr = addr / channels; 2144661Sksewell@umich.edu 2154661Sksewell@umich.edu // after the channel bits, get the bank bits to interleave 2164661Sksewell@umich.edu // over the banks 2174661Sksewell@umich.edu bank = addr % banksPerRank; 2184661Sksewell@umich.edu addr = addr / banksPerRank; 2194661Sksewell@umich.edu 2204661Sksewell@umich.edu // after the bank, we get the rank bits which thus interleaves 2214661Sksewell@umich.edu // over the ranks 2224661Sksewell@umich.edu rank = addr % ranksPerChannel; 2234661Sksewell@umich.edu addr = addr / ranksPerChannel; 2244661Sksewell@umich.edu 2254661Sksewell@umich.edu // lastly, get the row bits 2264661Sksewell@umich.edu row = addr % rowsPerBank; 2274661Sksewell@umich.edu addr = addr / rowsPerBank; 2284661Sksewell@umich.edu } else if (addrMapping == Enums::RoRaBaCoCh) { 2294661Sksewell@umich.edu // take out the channel part of the address 2304661Sksewell@umich.edu addr = addr / channels; 2314661Sksewell@umich.edu 2324661Sksewell@umich.edu // next, the column 2334661Sksewell@umich.edu addr = addr / columnsPerRowBuffer; 2344661Sksewell@umich.edu 2354661Sksewell@umich.edu // after the column bits, we get the bank bits to interleave 2364661Sksewell@umich.edu // over the banks 2374661Sksewell@umich.edu bank = addr % banksPerRank; 2384661Sksewell@umich.edu addr = addr / banksPerRank; 2394661Sksewell@umich.edu 2404661Sksewell@umich.edu // after the bank, we get the rank bits which thus interleaves 2414661Sksewell@umich.edu // over the ranks 2424661Sksewell@umich.edu rank = addr % ranksPerChannel; 2434661Sksewell@umich.edu addr = addr / ranksPerChannel; 2444661Sksewell@umich.edu 2454661Sksewell@umich.edu // lastly, get the row bits 2464661Sksewell@umich.edu row = addr % rowsPerBank; 2474661Sksewell@umich.edu addr = addr / rowsPerBank; 2484661Sksewell@umich.edu } else if (addrMapping == Enums::RoCoRaBaCh) { 2494661Sksewell@umich.edu // optimise for closed page mode and utilise maximum 2504661Sksewell@umich.edu // parallelism of the DRAM (at the cost of power) 2514661Sksewell@umich.edu 2524661Sksewell@umich.edu // take out the channel part of the address, not that this has 2534661Sksewell@umich.edu // to match with how accesses are interleaved between the 2544661Sksewell@umich.edu // controllers in the address mapping 2554661Sksewell@umich.edu addr = addr / channels; 2564661Sksewell@umich.edu 2574661Sksewell@umich.edu // start with the bank bits, as this provides the maximum 2584661Sksewell@umich.edu // opportunity for parallelism between requests 2594661Sksewell@umich.edu bank = addr % banksPerRank; 2604661Sksewell@umich.edu addr = addr / banksPerRank; 2614661Sksewell@umich.edu 2624661Sksewell@umich.edu // next get the rank bits 2634661Sksewell@umich.edu rank = addr % ranksPerChannel; 2644661Sksewell@umich.edu addr = addr / ranksPerChannel; 2654661Sksewell@umich.edu 2664661Sksewell@umich.edu // next the column bits which we do not need to keep track of 2674661Sksewell@umich.edu // and simply skip past 2684661Sksewell@umich.edu addr = addr / columnsPerRowBuffer; 2694661Sksewell@umich.edu 2704661Sksewell@umich.edu // lastly, get the row bits 2714661Sksewell@umich.edu row = addr % rowsPerBank; 2724661Sksewell@umich.edu addr = addr / rowsPerBank; 2734661Sksewell@umich.edu } else 2744661Sksewell@umich.edu panic("Unknown address mapping policy chosen!"); 2754661Sksewell@umich.edu 2764661Sksewell@umich.edu assert(rank < ranksPerChannel); 2774661Sksewell@umich.edu assert(bank < banksPerRank); 2784661Sksewell@umich.edu assert(row < rowsPerBank); 2794661Sksewell@umich.edu 2804661Sksewell@umich.edu DPRINTF(DRAM, "Address: %lld Rank %d Bank %d Row %d\n", 2814661Sksewell@umich.edu dramPktAddr, rank, bank, row); 2824661Sksewell@umich.edu 2834661Sksewell@umich.edu // create the corresponding DRAM packet with the entry time and 2844661Sksewell@umich.edu // ready time set to the current tick, the latter will be updated 2854661Sksewell@umich.edu // later 2864661Sksewell@umich.edu uint16_t bank_id = banksPerRank * rank + bank; 2874661Sksewell@umich.edu return new DRAMPacket(pkt, isRead, rank, bank, row, bank_id, dramPktAddr, 2884661Sksewell@umich.edu size, banks[rank][bank]); 2894661Sksewell@umich.edu} 2904661Sksewell@umich.edu 2914661Sksewell@umich.eduvoid 2924661Sksewell@umich.eduSimpleDRAM::addToReadQueue(PacketPtr pkt, unsigned int pktCount) 2934661Sksewell@umich.edu{ 2944661Sksewell@umich.edu // only add to the read queue here. whenever the request is 2954661Sksewell@umich.edu // eventually done, set the readyTime, and call schedule() 2964661Sksewell@umich.edu assert(!pkt->isWrite()); 2974661Sksewell@umich.edu 2984661Sksewell@umich.edu assert(pktCount != 0); 2994661Sksewell@umich.edu 3004661Sksewell@umich.edu // if the request size is larger than burst size, the pkt is split into 3014661Sksewell@umich.edu // multiple DRAM packets 3024661Sksewell@umich.edu // Note if the pkt starting address is not aligened to burst size, the 3034661Sksewell@umich.edu // address of first DRAM packet is kept unaliged. Subsequent DRAM packets 3044661Sksewell@umich.edu // are aligned to burst size boundaries. This is to ensure we accurately 3054661Sksewell@umich.edu // check read packets against packets in write queue. 3064661Sksewell@umich.edu Addr addr = pkt->getAddr(); 3074661Sksewell@umich.edu unsigned pktsServicedByWrQ = 0; 3084661Sksewell@umich.edu BurstHelper* burst_helper = NULL; 3094661Sksewell@umich.edu for (int cnt = 0; cnt < pktCount; ++cnt) { 3104661Sksewell@umich.edu unsigned size = std::min((addr | (burstSize - 1)) + 1, 3114661Sksewell@umich.edu pkt->getAddr() + pkt->getSize()) - addr; 3124661Sksewell@umich.edu readPktSize[ceilLog2(size)]++; 3134661Sksewell@umich.edu readBursts++; 3144661Sksewell@umich.edu 3154661Sksewell@umich.edu // First check write buffer to see if the data is already at 3164661Sksewell@umich.edu // the controller 3174661Sksewell@umich.edu bool foundInWrQ = false; 3184661Sksewell@umich.edu for (auto i = writeQueue.begin(); i != writeQueue.end(); ++i) { 3194661Sksewell@umich.edu // check if the read is subsumed in the write entry we are 3204661Sksewell@umich.edu // looking at 3214661Sksewell@umich.edu if ((*i)->addr <= addr && 3224661Sksewell@umich.edu (addr + size) <= ((*i)->addr + (*i)->size)) { 3234661Sksewell@umich.edu foundInWrQ = true; 3244661Sksewell@umich.edu servicedByWrQ++; 3254661Sksewell@umich.edu pktsServicedByWrQ++; 3264661Sksewell@umich.edu DPRINTF(DRAM, "Read to addr %lld with size %d serviced by " 3274661Sksewell@umich.edu "write queue\n", addr, size); 3284661Sksewell@umich.edu bytesReadWrQ += burstSize; 3294661Sksewell@umich.edu break; 3304661Sksewell@umich.edu } 3314661Sksewell@umich.edu } 3324661Sksewell@umich.edu 3334661Sksewell@umich.edu // If not found in the write q, make a DRAM packet and 3344661Sksewell@umich.edu // push it onto the read queue 3354661Sksewell@umich.edu if (!foundInWrQ) { 3364661Sksewell@umich.edu 3374661Sksewell@umich.edu // Make the burst helper for split packets 3384661Sksewell@umich.edu if (pktCount > 1 && burst_helper == NULL) { 3394661Sksewell@umich.edu DPRINTF(DRAM, "Read to addr %lld translates to %d " 3404661Sksewell@umich.edu "dram requests\n", pkt->getAddr(), pktCount); 3414661Sksewell@umich.edu burst_helper = new BurstHelper(pktCount); 3424661Sksewell@umich.edu } 3434661Sksewell@umich.edu 3444661Sksewell@umich.edu DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, true); 3454661Sksewell@umich.edu dram_pkt->burstHelper = burst_helper; 3464661Sksewell@umich.edu 3474661Sksewell@umich.edu assert(!readQueueFull(1)); 3484661Sksewell@umich.edu rdQLenPdf[readQueue.size() + respQueue.size()]++; 3494661Sksewell@umich.edu 3504661Sksewell@umich.edu DPRINTF(DRAM, "Adding to read queue\n"); 3514661Sksewell@umich.edu 3524661Sksewell@umich.edu readQueue.push_back(dram_pkt); 3534661Sksewell@umich.edu 3544661Sksewell@umich.edu // Update stats 3554661Sksewell@umich.edu avgRdQLen = readQueue.size() + respQueue.size(); 3564661Sksewell@umich.edu } 3574661Sksewell@umich.edu 3584661Sksewell@umich.edu // Starting address of next dram pkt (aligend to burstSize boundary) 3594661Sksewell@umich.edu addr = (addr | (burstSize - 1)) + 1; 3604661Sksewell@umich.edu } 3614661Sksewell@umich.edu 3624661Sksewell@umich.edu // If all packets are serviced by write queue, we send the repsonse back 3634661Sksewell@umich.edu if (pktsServicedByWrQ == pktCount) { 3644661Sksewell@umich.edu accessAndRespond(pkt, frontendLatency); 3654661Sksewell@umich.edu return; 3664661Sksewell@umich.edu } 3674661Sksewell@umich.edu 3684661Sksewell@umich.edu // Update how many split packets are serviced by write queue 3694661Sksewell@umich.edu if (burst_helper != NULL) 3704661Sksewell@umich.edu burst_helper->burstsServiced = pktsServicedByWrQ; 3714661Sksewell@umich.edu 3724661Sksewell@umich.edu // If we are not already scheduled to get the read request out of 3734661Sksewell@umich.edu // the queue, do so now 3744661Sksewell@umich.edu if (!nextReqEvent.scheduled() && !stopReads) { 3754661Sksewell@umich.edu DPRINTF(DRAM, "Request scheduled immediately\n"); 3764661Sksewell@umich.edu schedule(nextReqEvent, curTick()); 3774661Sksewell@umich.edu } 3784661Sksewell@umich.edu} 3794661Sksewell@umich.edu 3804661Sksewell@umich.eduvoid 3814661Sksewell@umich.eduSimpleDRAM::processWriteEvent() 3824661Sksewell@umich.edu{ 3834661Sksewell@umich.edu assert(!writeQueue.empty()); 3844661Sksewell@umich.edu 3854661Sksewell@umich.edu DPRINTF(DRAM, "Beginning DRAM Write\n"); 3864661Sksewell@umich.edu Tick temp1 M5_VAR_USED = std::max(curTick(), busBusyUntil); 3874661Sksewell@umich.edu Tick temp2 M5_VAR_USED = std::max(curTick(), maxBankFreeAt()); 3884661Sksewell@umich.edu 3894661Sksewell@umich.edu chooseNextWrite(); 3904661Sksewell@umich.edu DRAMPacket* dram_pkt = writeQueue.front(); 3914661Sksewell@umich.edu // sanity check 3924661Sksewell@umich.edu assert(dram_pkt->size <= burstSize); 3934661Sksewell@umich.edu doDRAMAccess(dram_pkt); 3944661Sksewell@umich.edu 3954661Sksewell@umich.edu writeQueue.pop_front(); 3964661Sksewell@umich.edu delete dram_pkt; 3974661Sksewell@umich.edu 3984661Sksewell@umich.edu ++writesThisTime; 3994661Sksewell@umich.edu 4004661Sksewell@umich.edu DPRINTF(DRAM, "Writing, bus busy for %lld ticks, banks busy " 4014661Sksewell@umich.edu "for %lld ticks\n", busBusyUntil - temp1, maxBankFreeAt() - temp2); 4024661Sksewell@umich.edu 4034661Sksewell@umich.edu // Update stats 4044661Sksewell@umich.edu avgWrQLen = writeQueue.size(); 4054661Sksewell@umich.edu 4064661Sksewell@umich.edu // If we emptied the write queue, or got below the threshold and 4074661Sksewell@umich.edu // are not draining, or we have reads waiting and have done enough 4084661Sksewell@umich.edu // writes, then switch to reads. The retry above could already 4094661Sksewell@umich.edu // have caused it to be scheduled, so first check 4104661Sksewell@umich.edu if (writeQueue.empty() || 4114661Sksewell@umich.edu (writeQueue.size() < writeLowThreshold && !drainManager) || 4124661Sksewell@umich.edu (!readQueue.empty() && writesThisTime >= minWritesPerSwitch)) { 4134661Sksewell@umich.edu // turn the bus back around for reads again 4144661Sksewell@umich.edu busBusyUntil += tWTR; 4154661Sksewell@umich.edu stopReads = false; 4164661Sksewell@umich.edu writesThisTime = 0; 4174661Sksewell@umich.edu 4184661Sksewell@umich.edu if (!nextReqEvent.scheduled()) 4194661Sksewell@umich.edu schedule(nextReqEvent, busBusyUntil); 4204661Sksewell@umich.edu } else { 4214661Sksewell@umich.edu assert(!writeEvent.scheduled()); 4224661Sksewell@umich.edu DPRINTF(DRAM, "Next write scheduled at %lld\n", newTime); 4234661Sksewell@umich.edu schedule(writeEvent, newTime); 4244661Sksewell@umich.edu } 4254661Sksewell@umich.edu 4264661Sksewell@umich.edu if (retryWrReq) { 4274661Sksewell@umich.edu retryWrReq = false; 4284661Sksewell@umich.edu port.sendRetry(); 4294661Sksewell@umich.edu } 4304661Sksewell@umich.edu 4314661Sksewell@umich.edu // if there is nothing left in any queue, signal a drain 4324661Sksewell@umich.edu if (writeQueue.empty() && readQueue.empty() && 4334661Sksewell@umich.edu respQueue.empty () && drainManager) { 4344661Sksewell@umich.edu drainManager->signalDrainDone(); 4354661Sksewell@umich.edu drainManager = NULL; 4364661Sksewell@umich.edu } 4374661Sksewell@umich.edu} 4384661Sksewell@umich.edu 4394661Sksewell@umich.edu 4404661Sksewell@umich.eduvoid 4414661Sksewell@umich.eduSimpleDRAM::triggerWrites() 4424661Sksewell@umich.edu{ 4434661Sksewell@umich.edu DPRINTF(DRAM, "Writes triggered at %lld\n", curTick()); 4444661Sksewell@umich.edu // Flag variable to stop any more read scheduling 4454661Sksewell@umich.edu stopReads = true; 4464661Sksewell@umich.edu 4474661Sksewell@umich.edu writeStartTime = std::max(busBusyUntil, curTick()) + tWTR; 4484661Sksewell@umich.edu 4494661Sksewell@umich.edu DPRINTF(DRAM, "Writes scheduled at %lld\n", writeStartTime); 4504661Sksewell@umich.edu 4514661Sksewell@umich.edu assert(writeStartTime >= curTick()); 4524661Sksewell@umich.edu assert(!writeEvent.scheduled()); 4534661Sksewell@umich.edu schedule(writeEvent, writeStartTime); 4544661Sksewell@umich.edu} 4554661Sksewell@umich.edu 4564661Sksewell@umich.eduvoid 4574661Sksewell@umich.eduSimpleDRAM::addToWriteQueue(PacketPtr pkt, unsigned int pktCount) 4584661Sksewell@umich.edu{ 4594661Sksewell@umich.edu // only add to the write queue here. whenever the request is 4604661Sksewell@umich.edu // eventually done, set the readyTime, and call schedule() 4614661Sksewell@umich.edu assert(pkt->isWrite()); 4624661Sksewell@umich.edu 4634661Sksewell@umich.edu // if the request size is larger than burst size, the pkt is split into 4644661Sksewell@umich.edu // multiple DRAM packets 4654661Sksewell@umich.edu Addr addr = pkt->getAddr(); 4664661Sksewell@umich.edu for (int cnt = 0; cnt < pktCount; ++cnt) { 4674661Sksewell@umich.edu unsigned size = std::min((addr | (burstSize - 1)) + 1, 4684661Sksewell@umich.edu pkt->getAddr() + pkt->getSize()) - addr; 4694661Sksewell@umich.edu writePktSize[ceilLog2(size)]++; 4704661Sksewell@umich.edu writeBursts++; 4714661Sksewell@umich.edu 4724661Sksewell@umich.edu // see if we can merge with an existing item in the write 4734661Sksewell@umich.edu // queue and keep track of whether we have merged or not so we 4744661Sksewell@umich.edu // can stop at that point and also avoid enqueueing a new 4754661Sksewell@umich.edu // request 4764661Sksewell@umich.edu bool merged = false; 4774661Sksewell@umich.edu auto w = writeQueue.begin(); 4784661Sksewell@umich.edu 4794661Sksewell@umich.edu while(!merged && w != writeQueue.end()) { 4804661Sksewell@umich.edu // either of the two could be first, if they are the same 4814661Sksewell@umich.edu // it does not matter which way we go 4824661Sksewell@umich.edu if ((*w)->addr >= addr) { 4834661Sksewell@umich.edu // the existing one starts after the new one, figure 4844661Sksewell@umich.edu // out where the new one ends with respect to the 4854661Sksewell@umich.edu // existing one 4864661Sksewell@umich.edu if ((addr + size) >= ((*w)->addr + (*w)->size)) { 4874661Sksewell@umich.edu // check if the existing one is completely 4884661Sksewell@umich.edu // subsumed in the new one 4894661Sksewell@umich.edu DPRINTF(DRAM, "Merging write covering existing burst\n"); 4904661Sksewell@umich.edu merged = true; 4914661Sksewell@umich.edu // update both the address and the size 4924661Sksewell@umich.edu (*w)->addr = addr; 4934661Sksewell@umich.edu (*w)->size = size; 4944661Sksewell@umich.edu } else if ((addr + size) >= (*w)->addr && 4954661Sksewell@umich.edu ((*w)->addr + (*w)->size - addr) <= burstSize) { 4964661Sksewell@umich.edu // the new one is just before or partially 4974661Sksewell@umich.edu // overlapping with the existing one, and together 4984661Sksewell@umich.edu // they fit within a burst 4994661Sksewell@umich.edu DPRINTF(DRAM, "Merging write before existing burst\n"); 5004661Sksewell@umich.edu merged = true; 5014661Sksewell@umich.edu // the existing queue item needs to be adjusted with 5024661Sksewell@umich.edu // respect to both address and size 5034661Sksewell@umich.edu (*w)->size = (*w)->addr + (*w)->size - addr; 5044661Sksewell@umich.edu (*w)->addr = addr; 5054661Sksewell@umich.edu } 5064661Sksewell@umich.edu } else { 5074661Sksewell@umich.edu // the new one starts after the current one, figure 5084661Sksewell@umich.edu // out where the existing one ends with respect to the 5094661Sksewell@umich.edu // new one 5104661Sksewell@umich.edu if (((*w)->addr + (*w)->size) >= (addr + size)) { 5114661Sksewell@umich.edu // check if the new one is completely subsumed in the 5124661Sksewell@umich.edu // existing one 5134661Sksewell@umich.edu DPRINTF(DRAM, "Merging write into existing burst\n"); 5144661Sksewell@umich.edu merged = true; 5154661Sksewell@umich.edu // no adjustments necessary 5164661Sksewell@umich.edu } else if (((*w)->addr + (*w)->size) >= addr && 5174661Sksewell@umich.edu (addr + size - (*w)->addr) <= burstSize) { 5184661Sksewell@umich.edu // the existing one is just before or partially 5194661Sksewell@umich.edu // overlapping with the new one, and together 5204661Sksewell@umich.edu // they fit within a burst 5214661Sksewell@umich.edu DPRINTF(DRAM, "Merging write after existing burst\n"); 5224661Sksewell@umich.edu merged = true; 5234661Sksewell@umich.edu // the address is right, and only the size has 5244661Sksewell@umich.edu // to be adjusted 5254661Sksewell@umich.edu (*w)->size = addr + size - (*w)->addr; 5264661Sksewell@umich.edu } 5274661Sksewell@umich.edu } 5284661Sksewell@umich.edu ++w; 5294661Sksewell@umich.edu } 5304661Sksewell@umich.edu 5314661Sksewell@umich.edu // if the item was not merged we need to create a new write 5324661Sksewell@umich.edu // and enqueue it 5334661Sksewell@umich.edu if (!merged) { 5344661Sksewell@umich.edu DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, false); 5354661Sksewell@umich.edu 5364661Sksewell@umich.edu assert(writeQueue.size() < writeBufferSize); 5374661Sksewell@umich.edu wrQLenPdf[writeQueue.size()]++; 5384661Sksewell@umich.edu 5394661Sksewell@umich.edu DPRINTF(DRAM, "Adding to write queue\n"); 5404661Sksewell@umich.edu 5414661Sksewell@umich.edu writeQueue.push_back(dram_pkt); 5424661Sksewell@umich.edu 5434661Sksewell@umich.edu // Update stats 5444661Sksewell@umich.edu avgWrQLen = writeQueue.size(); 5454661Sksewell@umich.edu } else { 5464661Sksewell@umich.edu // keep track of the fact that this burst effectively 5474661Sksewell@umich.edu // disappeared as it was merged with an existing one 5484661Sksewell@umich.edu mergedWrBursts++; 5494661Sksewell@umich.edu } 5504661Sksewell@umich.edu 5514661Sksewell@umich.edu // Starting address of next dram pkt (aligend to burstSize boundary) 5524661Sksewell@umich.edu addr = (addr | (burstSize - 1)) + 1; 5534661Sksewell@umich.edu } 5544661Sksewell@umich.edu 5554661Sksewell@umich.edu // we do not wait for the writes to be send to the actual memory, 5564661Sksewell@umich.edu // but instead take responsibility for the consistency here and 5574661Sksewell@umich.edu // snoop the write queue for any upcoming reads 5584661Sksewell@umich.edu // @todo, if a pkt size is larger than burst size, we might need a 5594661Sksewell@umich.edu // different front end latency 5604661Sksewell@umich.edu accessAndRespond(pkt, frontendLatency); 5614661Sksewell@umich.edu 5624661Sksewell@umich.edu // If your write buffer is starting to fill up, drain it! 5634661Sksewell@umich.edu if (writeQueue.size() >= writeHighThreshold && !stopReads){ 5644661Sksewell@umich.edu triggerWrites(); 5654661Sksewell@umich.edu } 5664661Sksewell@umich.edu} 5674661Sksewell@umich.edu 5684661Sksewell@umich.eduvoid 5694661Sksewell@umich.eduSimpleDRAM::printParams() const 5704661Sksewell@umich.edu{ 5714661Sksewell@umich.edu // Sanity check print of important parameters 5724661Sksewell@umich.edu DPRINTF(DRAM, 5734661Sksewell@umich.edu "Memory controller %s physical organization\n" \ 5744661Sksewell@umich.edu "Number of devices per rank %d\n" \ 5754661Sksewell@umich.edu "Device bus width (in bits) %d\n" \ 5764661Sksewell@umich.edu "DRAM data bus burst %d\n" \ 5774661Sksewell@umich.edu "Row buffer size %d\n" \ 5784661Sksewell@umich.edu "Columns per row buffer %d\n" \ 5794661Sksewell@umich.edu "Rows per bank %d\n" \ 5804661Sksewell@umich.edu "Banks per rank %d\n" \ 5814661Sksewell@umich.edu "Ranks per channel %d\n" \ 5824661Sksewell@umich.edu "Total mem capacity %u\n", 5834661Sksewell@umich.edu name(), devicesPerRank, deviceBusWidth, burstSize, rowBufferSize, 5844661Sksewell@umich.edu columnsPerRowBuffer, rowsPerBank, banksPerRank, ranksPerChannel, 5854661Sksewell@umich.edu rowBufferSize * rowsPerBank * banksPerRank * ranksPerChannel); 5864661Sksewell@umich.edu 5874661Sksewell@umich.edu string scheduler = memSchedPolicy == Enums::fcfs ? "FCFS" : "FR-FCFS"; 5884661Sksewell@umich.edu string address_mapping = addrMapping == Enums::RoRaBaChCo ? "RoRaBaChCo" : 5894661Sksewell@umich.edu (addrMapping == Enums::RoRaBaCoCh ? "RoRaBaCoCh" : "RoCoRaBaCh"); 5904661Sksewell@umich.edu string page_policy = pageMgmt == Enums::open ? "OPEN" : 5914661Sksewell@umich.edu (pageMgmt == Enums::open_adaptive ? "OPEN (adaptive)" : "CLOSE"); 5924661Sksewell@umich.edu 5934661Sksewell@umich.edu DPRINTF(DRAM, 5944661Sksewell@umich.edu "Memory controller %s characteristics\n" \ 5954661Sksewell@umich.edu "Read buffer size %d\n" \ 5964661Sksewell@umich.edu "Write buffer size %d\n" \ 5974661Sksewell@umich.edu "Write high thresh %d\n" \ 5984661Sksewell@umich.edu "Write low thresh %d\n" \ 5994661Sksewell@umich.edu "Scheduler %s\n" \ 6004661Sksewell@umich.edu "Address mapping %s\n" \ 6014661Sksewell@umich.edu "Page policy %s\n", 6024661Sksewell@umich.edu name(), readBufferSize, writeBufferSize, writeHighThreshold, 6034661Sksewell@umich.edu writeLowThreshold, scheduler, address_mapping, page_policy); 6044661Sksewell@umich.edu 6054661Sksewell@umich.edu DPRINTF(DRAM, "Memory controller %s timing specs\n" \ 6064661Sksewell@umich.edu "tRCD %d ticks\n" \ 6074661Sksewell@umich.edu "tCL %d ticks\n" \ 6084661Sksewell@umich.edu "tRP %d ticks\n" \ 6094661Sksewell@umich.edu "tBURST %d ticks\n" \ 6104661Sksewell@umich.edu "tRFC %d ticks\n" \ 6114661Sksewell@umich.edu "tREFI %d ticks\n" \ 6124661Sksewell@umich.edu "tWTR %d ticks\n" \ 6134661Sksewell@umich.edu "tXAW (%d) %d ticks\n", 6144661Sksewell@umich.edu name(), tRCD, tCL, tRP, tBURST, tRFC, tREFI, tWTR, 6154661Sksewell@umich.edu activationLimit, tXAW); 6164661Sksewell@umich.edu} 6174661Sksewell@umich.edu 6184661Sksewell@umich.eduvoid 6194661Sksewell@umich.eduSimpleDRAM::printQs() const { 6204661Sksewell@umich.edu DPRINTF(DRAM, "===READ QUEUE===\n\n"); 6214661Sksewell@umich.edu for (auto i = readQueue.begin() ; i != readQueue.end() ; ++i) { 6224661Sksewell@umich.edu DPRINTF(DRAM, "Read %lu\n", (*i)->addr); 6234661Sksewell@umich.edu } 6244661Sksewell@umich.edu DPRINTF(DRAM, "\n===RESP QUEUE===\n\n"); 6254661Sksewell@umich.edu for (auto i = respQueue.begin() ; i != respQueue.end() ; ++i) { 6264661Sksewell@umich.edu DPRINTF(DRAM, "Response %lu\n", (*i)->addr); 6274661Sksewell@umich.edu } 6284661Sksewell@umich.edu DPRINTF(DRAM, "\n===WRITE QUEUE===\n\n"); 6294661Sksewell@umich.edu for (auto i = writeQueue.begin() ; i != writeQueue.end() ; ++i) { 6304661Sksewell@umich.edu DPRINTF(DRAM, "Write %lu\n", (*i)->addr); 6314661Sksewell@umich.edu } 6324661Sksewell@umich.edu} 6334661Sksewell@umich.edu 6344661Sksewell@umich.edubool 6354661Sksewell@umich.eduSimpleDRAM::recvTimingReq(PacketPtr pkt) 6364661Sksewell@umich.edu{ 6374661Sksewell@umich.edu /// @todo temporary hack to deal with memory corruption issues until 6384661Sksewell@umich.edu /// 4-phase transactions are complete 6394661Sksewell@umich.edu for (int x = 0; x < pendingDelete.size(); x++) 6404661Sksewell@umich.edu delete pendingDelete[x]; 6414661Sksewell@umich.edu pendingDelete.clear(); 6424661Sksewell@umich.edu 6434661Sksewell@umich.edu // This is where we enter from the outside world 6444661Sksewell@umich.edu DPRINTF(DRAM, "recvTimingReq: request %s addr %lld size %d\n", 6454661Sksewell@umich.edu pkt->cmdString(), pkt->getAddr(), pkt->getSize()); 6464661Sksewell@umich.edu 6474661Sksewell@umich.edu // simply drop inhibited packets for now 6484661Sksewell@umich.edu if (pkt->memInhibitAsserted()) { 6494661Sksewell@umich.edu DPRINTF(DRAM,"Inhibited packet -- Dropping it now\n"); 6504661Sksewell@umich.edu pendingDelete.push_back(pkt); 6514661Sksewell@umich.edu return true; 6524661Sksewell@umich.edu } 6534661Sksewell@umich.edu 6544661Sksewell@umich.edu // Every million accesses, print the state of the queues 6554661Sksewell@umich.edu if (numReqs % 1000000 == 0) 6564661Sksewell@umich.edu printQs(); 6574661Sksewell@umich.edu 6584661Sksewell@umich.edu // Calc avg gap between requests 6594661Sksewell@umich.edu if (prevArrival != 0) { 6604661Sksewell@umich.edu totGap += curTick() - prevArrival; 6614661Sksewell@umich.edu } 6624661Sksewell@umich.edu prevArrival = curTick(); 6634661Sksewell@umich.edu 6644661Sksewell@umich.edu 6654661Sksewell@umich.edu // Find out how many dram packets a pkt translates to 6664661Sksewell@umich.edu // If the burst size is equal or larger than the pkt size, then a pkt 6674661Sksewell@umich.edu // translates to only one dram packet. Otherwise, a pkt translates to 6684661Sksewell@umich.edu // multiple dram packets 6694661Sksewell@umich.edu unsigned size = pkt->getSize(); 6704661Sksewell@umich.edu unsigned offset = pkt->getAddr() & (burstSize - 1); 6714661Sksewell@umich.edu unsigned int dram_pkt_count = divCeil(offset + size, burstSize); 6724661Sksewell@umich.edu 6734661Sksewell@umich.edu // check local buffers and do not accept if full 6744661Sksewell@umich.edu if (pkt->isRead()) { 6754661Sksewell@umich.edu assert(size != 0); 6764661Sksewell@umich.edu if (readQueueFull(dram_pkt_count)) { 6774661Sksewell@umich.edu DPRINTF(DRAM, "Read queue full, not accepting\n"); 6784661Sksewell@umich.edu // remember that we have to retry this port 6794661Sksewell@umich.edu retryRdReq = true; 6804661Sksewell@umich.edu numRdRetry++; 6814661Sksewell@umich.edu return false; 6824661Sksewell@umich.edu } else { 6834661Sksewell@umich.edu addToReadQueue(pkt, dram_pkt_count); 6844661Sksewell@umich.edu readReqs++; 6854661Sksewell@umich.edu numReqs++; 6864661Sksewell@umich.edu bytesReadSys += size; 6874661Sksewell@umich.edu } 6884661Sksewell@umich.edu } else if (pkt->isWrite()) { 6894661Sksewell@umich.edu assert(size != 0); 6904661Sksewell@umich.edu if (writeQueueFull(dram_pkt_count)) { 6914661Sksewell@umich.edu DPRINTF(DRAM, "Write queue full, not accepting\n"); 6924661Sksewell@umich.edu // remember that we have to retry this port 6934661Sksewell@umich.edu retryWrReq = true; 6944661Sksewell@umich.edu numWrRetry++; 6954661Sksewell@umich.edu return false; 6964661Sksewell@umich.edu } else { 6974661Sksewell@umich.edu addToWriteQueue(pkt, dram_pkt_count); 6984661Sksewell@umich.edu writeReqs++; 6994661Sksewell@umich.edu numReqs++; 7004661Sksewell@umich.edu bytesWrittenSys += size; 7014661Sksewell@umich.edu } 7024661Sksewell@umich.edu } else { 7034661Sksewell@umich.edu DPRINTF(DRAM,"Neither read nor write, ignore timing\n"); 7044661Sksewell@umich.edu neitherReadNorWrite++; 7054661Sksewell@umich.edu accessAndRespond(pkt, 1); 7064661Sksewell@umich.edu } 7074661Sksewell@umich.edu 7084661Sksewell@umich.edu retryRdReq = false; 7094661Sksewell@umich.edu retryWrReq = false; 7104661Sksewell@umich.edu return true; 7114661Sksewell@umich.edu} 7124661Sksewell@umich.edu 7134661Sksewell@umich.eduvoid 7144661Sksewell@umich.eduSimpleDRAM::processRespondEvent() 7154661Sksewell@umich.edu{ 7164661Sksewell@umich.edu DPRINTF(DRAM, 7174661Sksewell@umich.edu "processRespondEvent(): Some req has reached its readyTime\n"); 7184661Sksewell@umich.edu 7194661Sksewell@umich.edu DRAMPacket* dram_pkt = respQueue.front(); 7204661Sksewell@umich.edu 7214661Sksewell@umich.edu if (dram_pkt->burstHelper) { 7224661Sksewell@umich.edu // it is a split packet 7234661Sksewell@umich.edu dram_pkt->burstHelper->burstsServiced++; 7244661Sksewell@umich.edu if (dram_pkt->burstHelper->burstsServiced == 7254661Sksewell@umich.edu dram_pkt->burstHelper->burstCount) { 7264661Sksewell@umich.edu // we have now serviced all children packets of a system packet 7274661Sksewell@umich.edu // so we can now respond to the requester 7284661Sksewell@umich.edu // @todo we probably want to have a different front end and back 7294661Sksewell@umich.edu // end latency for split packets 7304661Sksewell@umich.edu accessAndRespond(dram_pkt->pkt, frontendLatency + backendLatency); 7314661Sksewell@umich.edu delete dram_pkt->burstHelper; 7324661Sksewell@umich.edu dram_pkt->burstHelper = NULL; 7334661Sksewell@umich.edu } 7344661Sksewell@umich.edu } else { 7354661Sksewell@umich.edu // it is not a split packet 7364661Sksewell@umich.edu accessAndRespond(dram_pkt->pkt, frontendLatency + backendLatency); 7374661Sksewell@umich.edu } 7384661Sksewell@umich.edu 7394661Sksewell@umich.edu delete respQueue.front(); 7404661Sksewell@umich.edu respQueue.pop_front(); 7414661Sksewell@umich.edu 7424661Sksewell@umich.edu // Update stats 7434661Sksewell@umich.edu avgRdQLen = readQueue.size() + respQueue.size(); 7444661Sksewell@umich.edu 7454661Sksewell@umich.edu if (!respQueue.empty()) { 7464661Sksewell@umich.edu assert(respQueue.front()->readyTime >= curTick()); 7474661Sksewell@umich.edu assert(!respondEvent.scheduled()); 7484661Sksewell@umich.edu schedule(respondEvent, respQueue.front()->readyTime); 7494661Sksewell@umich.edu } else { 7504661Sksewell@umich.edu // if there is nothing left in any queue, signal a drain 7514661Sksewell@umich.edu if (writeQueue.empty() && readQueue.empty() && 7524661Sksewell@umich.edu drainManager) { 7534661Sksewell@umich.edu drainManager->signalDrainDone(); 7544661Sksewell@umich.edu drainManager = NULL; 7554661Sksewell@umich.edu } 7564661Sksewell@umich.edu } 7574661Sksewell@umich.edu 7584661Sksewell@umich.edu // We have made a location in the queue available at this point, 7594661Sksewell@umich.edu // so if there is a read that was forced to wait, retry now 7604661Sksewell@umich.edu if (retryRdReq) { 7614661Sksewell@umich.edu retryRdReq = false; 7624661Sksewell@umich.edu port.sendRetry(); 7634661Sksewell@umich.edu } 7644661Sksewell@umich.edu} 7654661Sksewell@umich.edu 7664661Sksewell@umich.eduvoid 7674661Sksewell@umich.eduSimpleDRAM::chooseNextWrite() 7684661Sksewell@umich.edu{ 7694661Sksewell@umich.edu // This method does the arbitration between write requests. The 7704661Sksewell@umich.edu // chosen packet is simply moved to the head of the write 7714661Sksewell@umich.edu // queue. The other methods know that this is the place to 7724661Sksewell@umich.edu // look. For example, with FCFS, this method does nothing 7734661Sksewell@umich.edu assert(!writeQueue.empty()); 7744661Sksewell@umich.edu 7754661Sksewell@umich.edu if (writeQueue.size() == 1) { 7764661Sksewell@umich.edu DPRINTF(DRAM, "Single write request, nothing to do\n"); 7774661Sksewell@umich.edu return; 7784661Sksewell@umich.edu } 7794661Sksewell@umich.edu 7804661Sksewell@umich.edu if (memSchedPolicy == Enums::fcfs) { 7814661Sksewell@umich.edu // Do nothing, since the correct request is already head 7824661Sksewell@umich.edu } else if (memSchedPolicy == Enums::frfcfs) { 7834661Sksewell@umich.edu reorderQueue(writeQueue); 7844661Sksewell@umich.edu } else 7854661Sksewell@umich.edu panic("No scheduling policy chosen\n"); 7864661Sksewell@umich.edu 7874661Sksewell@umich.edu DPRINTF(DRAM, "Selected next write request\n"); 7884661Sksewell@umich.edu} 7894661Sksewell@umich.edu 7904661Sksewell@umich.edubool 7914661Sksewell@umich.eduSimpleDRAM::chooseNextRead() 7924661Sksewell@umich.edu{ 7934661Sksewell@umich.edu // This method does the arbitration between read requests. The 7944661Sksewell@umich.edu // chosen packet is simply moved to the head of the queue. The 7954661Sksewell@umich.edu // other methods know that this is the place to look. For example, 7964661Sksewell@umich.edu // with FCFS, this method does nothing 7974661Sksewell@umich.edu if (readQueue.empty()) { 7984661Sksewell@umich.edu DPRINTF(DRAM, "No read request to select\n"); 7994661Sksewell@umich.edu return false; 8004661Sksewell@umich.edu } 8014661Sksewell@umich.edu 8024661Sksewell@umich.edu // If there is only one request then there is nothing left to do 8034661Sksewell@umich.edu if (readQueue.size() == 1) 8044661Sksewell@umich.edu return true; 8054661Sksewell@umich.edu 8064661Sksewell@umich.edu if (memSchedPolicy == Enums::fcfs) { 8074661Sksewell@umich.edu // Do nothing, since the request to serve is already the first 8084661Sksewell@umich.edu // one in the read queue 8094661Sksewell@umich.edu } else if (memSchedPolicy == Enums::frfcfs) { 8104661Sksewell@umich.edu reorderQueue(readQueue); 8114661Sksewell@umich.edu } else 8124661Sksewell@umich.edu panic("No scheduling policy chosen!\n"); 8134661Sksewell@umich.edu 8144661Sksewell@umich.edu DPRINTF(DRAM, "Selected next read request\n"); 8154661Sksewell@umich.edu return true; 8164661Sksewell@umich.edu} 8174661Sksewell@umich.edu 8184661Sksewell@umich.eduvoid 8194661Sksewell@umich.eduSimpleDRAM::reorderQueue(std::deque<DRAMPacket*>& queue) 8204661Sksewell@umich.edu{ 8214661Sksewell@umich.edu // Only determine this when needed 8224661Sksewell@umich.edu uint64_t earliest_banks = 0; 8234661Sksewell@umich.edu 8244661Sksewell@umich.edu // Search for row hits first, if no row hit is found then schedule the 8254661Sksewell@umich.edu // packet to one of the earliest banks available 8264661Sksewell@umich.edu bool found_earliest_pkt = false; 8274661Sksewell@umich.edu auto selected_pkt_it = queue.begin(); 8284661Sksewell@umich.edu 8294661Sksewell@umich.edu for (auto i = queue.begin(); i != queue.end() ; ++i) { 8304661Sksewell@umich.edu DRAMPacket* dram_pkt = *i; 8314661Sksewell@umich.edu const Bank& bank = dram_pkt->bankRef; 8324661Sksewell@umich.edu // Check if it is a row hit 8334661Sksewell@umich.edu if (bank.openRow == dram_pkt->row) { 8344661Sksewell@umich.edu DPRINTF(DRAM, "Row buffer hit\n"); 8354661Sksewell@umich.edu selected_pkt_it = i; 8364661Sksewell@umich.edu break; 8374661Sksewell@umich.edu } else if (!found_earliest_pkt) { 8384661Sksewell@umich.edu // No row hit, go for first ready 8394661Sksewell@umich.edu if (earliest_banks == 0) 8404661Sksewell@umich.edu earliest_banks = minBankFreeAt(queue); 8414661Sksewell@umich.edu 8424661Sksewell@umich.edu // Bank is ready or is the first available bank 8434661Sksewell@umich.edu if (bank.freeAt <= curTick() || 8444661Sksewell@umich.edu bits(earliest_banks, dram_pkt->bankId, dram_pkt->bankId)) { 8454661Sksewell@umich.edu // Remember the packet to be scheduled to one of the earliest 8464661Sksewell@umich.edu // banks available 8474661Sksewell@umich.edu selected_pkt_it = i; 8484661Sksewell@umich.edu found_earliest_pkt = true; 8494661Sksewell@umich.edu } 8504661Sksewell@umich.edu } 8514661Sksewell@umich.edu } 8524661Sksewell@umich.edu 8534661Sksewell@umich.edu DRAMPacket* selected_pkt = *selected_pkt_it; 8544661Sksewell@umich.edu queue.erase(selected_pkt_it); 8554661Sksewell@umich.edu queue.push_front(selected_pkt); 8564661Sksewell@umich.edu} 8574661Sksewell@umich.edu 8584661Sksewell@umich.eduvoid 8594661Sksewell@umich.eduSimpleDRAM::accessAndRespond(PacketPtr pkt, Tick static_latency) 8604661Sksewell@umich.edu{ 8614661Sksewell@umich.edu DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr()); 8624661Sksewell@umich.edu 8634661Sksewell@umich.edu bool needsResponse = pkt->needsResponse(); 8644661Sksewell@umich.edu // do the actual memory access which also turns the packet into a 8654661Sksewell@umich.edu // response 8664661Sksewell@umich.edu access(pkt); 8674661Sksewell@umich.edu 8684661Sksewell@umich.edu // turn packet around to go back to requester if response expected 8694661Sksewell@umich.edu if (needsResponse) { 8704661Sksewell@umich.edu // access already turned the packet into a response 8714661Sksewell@umich.edu assert(pkt->isResponse()); 8724661Sksewell@umich.edu 8734661Sksewell@umich.edu // @todo someone should pay for this 8744661Sksewell@umich.edu pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; 8754661Sksewell@umich.edu 8764661Sksewell@umich.edu // queue the packet in the response queue to be sent out after 8774661Sksewell@umich.edu // the static latency has passed 8784661Sksewell@umich.edu port.schedTimingResp(pkt, curTick() + static_latency); 8794661Sksewell@umich.edu } else { 8804661Sksewell@umich.edu // @todo the packet is going to be deleted, and the DRAMPacket 8814661Sksewell@umich.edu // is still having a pointer to it 8824661Sksewell@umich.edu pendingDelete.push_back(pkt); 8834661Sksewell@umich.edu } 8844661Sksewell@umich.edu 8854661Sksewell@umich.edu DPRINTF(DRAM, "Done\n"); 8864661Sksewell@umich.edu 8874661Sksewell@umich.edu return; 8884661Sksewell@umich.edu} 8894661Sksewell@umich.edu 8904661Sksewell@umich.edupair<Tick, Tick> 8914661Sksewell@umich.eduSimpleDRAM::estimateLatency(DRAMPacket* dram_pkt, Tick inTime) 8924661Sksewell@umich.edu{ 8934661Sksewell@umich.edu // If a request reaches a bank at tick 'inTime', how much time 8944661Sksewell@umich.edu // *after* that does it take to finish the request, depending 8954661Sksewell@umich.edu // on bank status and page open policy. Note that this method 8964661Sksewell@umich.edu // considers only the time taken for the actual read or write 8974661Sksewell@umich.edu // to complete, NOT any additional time thereafter for tRAS or 8984661Sksewell@umich.edu // tRP. 8994661Sksewell@umich.edu Tick accLat = 0; 9004661Sksewell@umich.edu Tick bankLat = 0; 9014661Sksewell@umich.edu rowHitFlag = false; 9024661Sksewell@umich.edu Tick potentialActTick; 9034661Sksewell@umich.edu 9044661Sksewell@umich.edu const Bank& bank = dram_pkt->bankRef; 9054661Sksewell@umich.edu // open-page policy 9064661Sksewell@umich.edu if (pageMgmt == Enums::open || pageMgmt == Enums::open_adaptive) { 9074661Sksewell@umich.edu if (bank.openRow == dram_pkt->row) { 9084661Sksewell@umich.edu // When we have a row-buffer hit, 9094661Sksewell@umich.edu // we don't care about tRAS having expired or not, 9104661Sksewell@umich.edu // but do care about bank being free for access 9114661Sksewell@umich.edu rowHitFlag = true; 9124661Sksewell@umich.edu 9134661Sksewell@umich.edu // When a series of requests arrive to the same row, 9144661Sksewell@umich.edu // DDR systems are capable of streaming data continuously 9154661Sksewell@umich.edu // at maximum bandwidth (subject to tCCD). Here, we approximate 9164661Sksewell@umich.edu // this condition, and assume that if whenever a bank is already 9174661Sksewell@umich.edu // busy and a new request comes in, it can be completed with no 9184661Sksewell@umich.edu // penalty beyond waiting for the existing read to complete. 9194661Sksewell@umich.edu if (bank.freeAt > inTime) { 9204661Sksewell@umich.edu accLat += bank.freeAt - inTime; 9214661Sksewell@umich.edu bankLat += 0; 9224661Sksewell@umich.edu } else { 9234661Sksewell@umich.edu // CAS latency only 9244661Sksewell@umich.edu accLat += tCL; 9254661Sksewell@umich.edu bankLat += tCL; 9264661Sksewell@umich.edu } 9274661Sksewell@umich.edu 9284661Sksewell@umich.edu } else { 9294661Sksewell@umich.edu // Row-buffer miss, need to close existing row 9304661Sksewell@umich.edu // once tRAS has expired, then open the new one, 9314661Sksewell@umich.edu // then add cas latency. 9324661Sksewell@umich.edu Tick freeTime = std::max(bank.tRASDoneAt, bank.freeAt); 9334661Sksewell@umich.edu 9344661Sksewell@umich.edu if (freeTime > inTime) 9354661Sksewell@umich.edu accLat += freeTime - inTime; 9364661Sksewell@umich.edu 9374661Sksewell@umich.edu // If the there is no open row (open adaptive), then there 9384661Sksewell@umich.edu // is no precharge delay, otherwise go with tRP 9394661Sksewell@umich.edu Tick precharge_delay = bank.openRow == -1 ? 0 : tRP; 9404661Sksewell@umich.edu 9414661Sksewell@umich.edu //The bank is free, and you may be able to activate 9424661Sksewell@umich.edu potentialActTick = inTime + accLat + precharge_delay; 9434661Sksewell@umich.edu if (potentialActTick < bank.actAllowedAt) 9444661Sksewell@umich.edu accLat += bank.actAllowedAt - potentialActTick; 9454661Sksewell@umich.edu 9464661Sksewell@umich.edu accLat += precharge_delay + tRCD + tCL; 9474661Sksewell@umich.edu bankLat += precharge_delay + tRCD + tCL; 9484661Sksewell@umich.edu } 9494661Sksewell@umich.edu } else if (pageMgmt == Enums::close) { 9504661Sksewell@umich.edu // With a close page policy, no notion of 9514661Sksewell@umich.edu // bank.tRASDoneAt 9524661Sksewell@umich.edu if (bank.freeAt > inTime) 9534661Sksewell@umich.edu accLat += bank.freeAt - inTime; 9544661Sksewell@umich.edu 9554661Sksewell@umich.edu //The bank is free, and you may be able to activate 9564661Sksewell@umich.edu potentialActTick = inTime + accLat; 9574661Sksewell@umich.edu if (potentialActTick < bank.actAllowedAt) 9584661Sksewell@umich.edu accLat += bank.actAllowedAt - potentialActTick; 9594661Sksewell@umich.edu 9604661Sksewell@umich.edu // page already closed, simply open the row, and 9614661Sksewell@umich.edu // add cas latency 9624661Sksewell@umich.edu accLat += tRCD + tCL; 9634661Sksewell@umich.edu bankLat += tRCD + tCL; 9644661Sksewell@umich.edu } else 9654661Sksewell@umich.edu panic("No page management policy chosen\n"); 9664661Sksewell@umich.edu 9674661Sksewell@umich.edu DPRINTF(DRAM, "Returning < %lld, %lld > from estimateLatency()\n", 9684661Sksewell@umich.edu bankLat, accLat); 9694661Sksewell@umich.edu 9704661Sksewell@umich.edu return make_pair(bankLat, accLat); 9714661Sksewell@umich.edu} 9724661Sksewell@umich.edu 9734661Sksewell@umich.eduvoid 9744661Sksewell@umich.eduSimpleDRAM::processNextReqEvent() 9754661Sksewell@umich.edu{ 9764661Sksewell@umich.edu scheduleNextReq(); 9774661Sksewell@umich.edu} 9784661Sksewell@umich.edu 9794661Sksewell@umich.eduvoid 9804661Sksewell@umich.eduSimpleDRAM::recordActivate(Tick act_tick, uint8_t rank, uint8_t bank) 9814661Sksewell@umich.edu{ 9824661Sksewell@umich.edu assert(0 <= rank && rank < ranksPerChannel); 9834661Sksewell@umich.edu assert(actTicks[rank].size() == activationLimit); 9844661Sksewell@umich.edu 9854661Sksewell@umich.edu DPRINTF(DRAM, "Activate at tick %d\n", act_tick); 9864661Sksewell@umich.edu 9874661Sksewell@umich.edu // Tracking accesses after all banks are precharged. 9884661Sksewell@umich.edu // startTickPrechargeAll: is the tick when all the banks were again 9894661Sksewell@umich.edu // precharged. The difference between act_tick and startTickPrechargeAll 9904661Sksewell@umich.edu // gives the time for which DRAM doesn't get any accesses after refreshing 9914661Sksewell@umich.edu // or after a page is closed in closed-page or open-adaptive-page policy. 9924661Sksewell@umich.edu if ((numBanksActive == 0) && (act_tick > startTickPrechargeAll)) { 9934661Sksewell@umich.edu prechargeAllTime += act_tick - startTickPrechargeAll; 9944661Sksewell@umich.edu } 9954661Sksewell@umich.edu 9964661Sksewell@umich.edu // No need to update number of active banks for closed-page policy as only 1 9974661Sksewell@umich.edu // bank will be activated at any given point, which will be instatntly 9984661Sksewell@umich.edu // precharged 9994661Sksewell@umich.edu if (pageMgmt == Enums::open || pageMgmt == Enums::open_adaptive) 10004661Sksewell@umich.edu ++numBanksActive; 10014661Sksewell@umich.edu 10024661Sksewell@umich.edu // start by enforcing tRRD 10034661Sksewell@umich.edu for(int i = 0; i < banksPerRank; i++) { 10044661Sksewell@umich.edu // next activate must not happen before tRRD 10054661Sksewell@umich.edu banks[rank][i].actAllowedAt = act_tick + tRRD; 10064661Sksewell@umich.edu } 10074661Sksewell@umich.edu // tRC should be added to activation tick of the bank currently accessed, 10084661Sksewell@umich.edu // where tRC = tRAS + tRP, this is just for a check as actAllowedAt for same 10094661Sksewell@umich.edu // bank is already captured by bank.freeAt and bank.tRASDoneAt 10104661Sksewell@umich.edu banks[rank][bank].actAllowedAt = act_tick + tRAS + tRP; 10114661Sksewell@umich.edu 10124661Sksewell@umich.edu // next, we deal with tXAW, if the activation limit is disabled 10134661Sksewell@umich.edu // then we are done 10144661Sksewell@umich.edu if (actTicks[rank].empty()) 10154661Sksewell@umich.edu return; 10164661Sksewell@umich.edu 10174661Sksewell@umich.edu // sanity check 10184661Sksewell@umich.edu if (actTicks[rank].back() && (act_tick - actTicks[rank].back()) < tXAW) { 10194661Sksewell@umich.edu // @todo For now, stick with a warning 10204661Sksewell@umich.edu warn("Got %d activates in window %d (%d - %d) which is smaller " 10214661Sksewell@umich.edu "than %d\n", activationLimit, act_tick - actTicks[rank].back(), 10224661Sksewell@umich.edu act_tick, actTicks[rank].back(), tXAW); 10234661Sksewell@umich.edu } 10244661Sksewell@umich.edu 10254661Sksewell@umich.edu // shift the times used for the book keeping, the last element 10264661Sksewell@umich.edu // (highest index) is the oldest one and hence the lowest value 10274661Sksewell@umich.edu actTicks[rank].pop_back(); 10284661Sksewell@umich.edu 10294661Sksewell@umich.edu // record an new activation (in the future) 10304661Sksewell@umich.edu actTicks[rank].push_front(act_tick); 10314661Sksewell@umich.edu 10324661Sksewell@umich.edu // cannot activate more than X times in time window tXAW, push the 10334661Sksewell@umich.edu // next one (the X + 1'st activate) to be tXAW away from the 10344661Sksewell@umich.edu // oldest in our window of X 10354661Sksewell@umich.edu if (actTicks[rank].back() && (act_tick - actTicks[rank].back()) < tXAW) { 10364661Sksewell@umich.edu DPRINTF(DRAM, "Enforcing tXAW with X = %d, next activate no earlier " 10374661Sksewell@umich.edu "than %d\n", activationLimit, actTicks[rank].back() + tXAW); 10384661Sksewell@umich.edu for(int j = 0; j < banksPerRank; j++) 10394661Sksewell@umich.edu // next activate must not happen before end of window 10404661Sksewell@umich.edu banks[rank][j].actAllowedAt = actTicks[rank].back() + tXAW; 10414661Sksewell@umich.edu } 10424661Sksewell@umich.edu} 10434661Sksewell@umich.edu 10444661Sksewell@umich.eduvoid 10454661Sksewell@umich.eduSimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt) 10464661Sksewell@umich.edu{ 10474661Sksewell@umich.edu 10484661Sksewell@umich.edu DPRINTF(DRAM, "Timing access to addr %lld, rank/bank/row %d %d %d\n", 10494661Sksewell@umich.edu dram_pkt->addr, dram_pkt->rank, dram_pkt->bank, dram_pkt->row); 10504661Sksewell@umich.edu 10514661Sksewell@umich.edu // estimate the bank and access latency 10524661Sksewell@umich.edu pair<Tick, Tick> lat = estimateLatency(dram_pkt, curTick()); 10534661Sksewell@umich.edu Tick bankLat = lat.first; 10544661Sksewell@umich.edu Tick accessLat = lat.second; 10554661Sksewell@umich.edu Tick actTick; 10564661Sksewell@umich.edu 10574661Sksewell@umich.edu // This request was woken up at this time based on a prior call 10584661Sksewell@umich.edu // to estimateLatency(). However, between then and now, both the 10594661Sksewell@umich.edu // accessLatency and/or busBusyUntil may have changed. We need 10604661Sksewell@umich.edu // to correct for that. 10614661Sksewell@umich.edu 10624661Sksewell@umich.edu Tick addDelay = (curTick() + accessLat < busBusyUntil) ? 10634661Sksewell@umich.edu busBusyUntil - (curTick() + accessLat) : 0; 10644661Sksewell@umich.edu 10654661Sksewell@umich.edu Bank& bank = dram_pkt->bankRef; 10664661Sksewell@umich.edu 10674661Sksewell@umich.edu // Update bank state 10684661Sksewell@umich.edu if (pageMgmt == Enums::open || pageMgmt == Enums::open_adaptive) { 10694661Sksewell@umich.edu bank.openRow = dram_pkt->row; 10704661Sksewell@umich.edu bank.freeAt = curTick() + addDelay + accessLat; 10714661Sksewell@umich.edu 10724661Sksewell@umich.edu // If you activated a new row do to this access, the next access 10734661Sksewell@umich.edu // will have to respect tRAS for this bank. 10744661Sksewell@umich.edu if (!rowHitFlag) { 10754661Sksewell@umich.edu // any waiting for banks account for in freeAt 10764661Sksewell@umich.edu actTick = bank.freeAt - tCL - tRCD; 10774661Sksewell@umich.edu bank.tRASDoneAt = actTick + tRAS; 10784661Sksewell@umich.edu recordActivate(actTick, dram_pkt->rank, dram_pkt->bank); 10794661Sksewell@umich.edu 10804661Sksewell@umich.edu // sample the number of bytes accessed and reset it as 10814661Sksewell@umich.edu // we are now closing this row 10824661Sksewell@umich.edu bytesPerActivate.sample(bank.bytesAccessed); 10834661Sksewell@umich.edu bank.bytesAccessed = 0; 10844661Sksewell@umich.edu bank.rowAccesses = 0; 10854661Sksewell@umich.edu } 10864661Sksewell@umich.edu 10874661Sksewell@umich.edu // increment the bytes accessed and the accesses per row 10884661Sksewell@umich.edu bank.bytesAccessed += burstSize; 10894661Sksewell@umich.edu ++bank.rowAccesses; 10904661Sksewell@umich.edu 10914661Sksewell@umich.edu // if we reached the max, then issue with an auto-precharge 10924661Sksewell@umich.edu bool auto_precharge = bank.rowAccesses == maxAccessesPerRow; 10934661Sksewell@umich.edu 10944661Sksewell@umich.edu // if we did not hit the limit, we might still want to 10954661Sksewell@umich.edu // auto-precharge 10964661Sksewell@umich.edu if (!auto_precharge && pageMgmt == Enums::open_adaptive) { 10974661Sksewell@umich.edu // a twist on the open page policy is to not blindly keep the 10984661Sksewell@umich.edu // page open, but close it if there are no row hits, and there 10994661Sksewell@umich.edu // are bank conflicts in the queue 11004661Sksewell@umich.edu bool got_more_hits = false; 11014661Sksewell@umich.edu bool got_bank_conflict = false; 11024661Sksewell@umich.edu 11034661Sksewell@umich.edu // either look at the read queue or write queue 11044661Sksewell@umich.edu const deque<DRAMPacket*>& queue = dram_pkt->isRead ? readQueue : 11054661Sksewell@umich.edu writeQueue; 11064661Sksewell@umich.edu auto p = queue.begin(); 11074661Sksewell@umich.edu // make sure we are not considering the packet that we are 11084661Sksewell@umich.edu // currently dealing with (which is the head of the queue) 11094661Sksewell@umich.edu ++p; 11104661Sksewell@umich.edu 11114661Sksewell@umich.edu // keep on looking until we have found both or reached 11124661Sksewell@umich.edu // the end 11134661Sksewell@umich.edu while (!(got_more_hits && got_bank_conflict) && 11144661Sksewell@umich.edu p != queue.end()) { 11154661Sksewell@umich.edu bool same_rank_bank = (dram_pkt->rank == (*p)->rank) && 11164661Sksewell@umich.edu (dram_pkt->bank == (*p)->bank); 11174661Sksewell@umich.edu bool same_row = dram_pkt->row == (*p)->row; 11184661Sksewell@umich.edu got_more_hits |= same_rank_bank && same_row; 11194661Sksewell@umich.edu got_bank_conflict |= same_rank_bank && !same_row; 11204661Sksewell@umich.edu ++p; 11214661Sksewell@umich.edu } 11224661Sksewell@umich.edu 11234661Sksewell@umich.edu // auto pre-charge if we have not got any more hits, and 11244661Sksewell@umich.edu // have a bank conflict 11254661Sksewell@umich.edu auto_precharge = !got_more_hits && got_bank_conflict; 11264661Sksewell@umich.edu } 11274661Sksewell@umich.edu 11284661Sksewell@umich.edu // if this access should use auto-precharge, then we are 11294661Sksewell@umich.edu // closing the row 11304661Sksewell@umich.edu if (auto_precharge) { 11314661Sksewell@umich.edu bank.openRow = -1; 11324661Sksewell@umich.edu bank.freeAt = std::max(bank.freeAt, bank.tRASDoneAt) + tRP; 11334661Sksewell@umich.edu --numBanksActive; 11344661Sksewell@umich.edu if (numBanksActive == 0) { 11354661Sksewell@umich.edu startTickPrechargeAll = std::max(startTickPrechargeAll, 11364661Sksewell@umich.edu bank.freeAt); 11374661Sksewell@umich.edu DPRINTF(DRAM, "All banks precharged at tick: %ld\n", 11384661Sksewell@umich.edu startTickPrechargeAll); 11394661Sksewell@umich.edu } 11404661Sksewell@umich.edu DPRINTF(DRAM, "Auto-precharged bank: %d\n", dram_pkt->bankId); 11414661Sksewell@umich.edu } 11424661Sksewell@umich.edu 11434661Sksewell@umich.edu DPRINTF(DRAM, "doDRAMAccess::bank.freeAt is %lld\n", bank.freeAt); 11444661Sksewell@umich.edu } else if (pageMgmt == Enums::close) { 11454661Sksewell@umich.edu actTick = curTick() + addDelay + accessLat - tRCD - tCL; 11464661Sksewell@umich.edu recordActivate(actTick, dram_pkt->rank, dram_pkt->bank); 11474661Sksewell@umich.edu 11484661Sksewell@umich.edu // If the DRAM has a very quick tRAS, bank can be made free 11494661Sksewell@umich.edu // after consecutive tCL,tRCD,tRP times. In general, however, 11504661Sksewell@umich.edu // an additional wait is required to respect tRAS. 11514661Sksewell@umich.edu bank.freeAt = std::max(actTick + tRAS + tRP, 11524661Sksewell@umich.edu actTick + tRCD + tCL + tRP); 11534661Sksewell@umich.edu DPRINTF(DRAM, "doDRAMAccess::bank.freeAt is %lld\n", bank.freeAt); 11544661Sksewell@umich.edu bytesPerActivate.sample(burstSize); 11554661Sksewell@umich.edu startTickPrechargeAll = std::max(startTickPrechargeAll, bank.freeAt); 11564661Sksewell@umich.edu } else 11574661Sksewell@umich.edu panic("No page management policy chosen\n"); 11584661Sksewell@umich.edu 11594661Sksewell@umich.edu // Update request parameters 11604661Sksewell@umich.edu dram_pkt->readyTime = curTick() + addDelay + accessLat + tBURST; 11614661Sksewell@umich.edu 11624661Sksewell@umich.edu 11634661Sksewell@umich.edu DPRINTF(DRAM, "Req %lld: curtick is %lld accessLat is %d " \ 11644661Sksewell@umich.edu "readytime is %lld busbusyuntil is %lld. " \ 11654661Sksewell@umich.edu "Scheduling at readyTime\n", dram_pkt->addr, 11664661Sksewell@umich.edu curTick(), accessLat, dram_pkt->readyTime, busBusyUntil); 11674661Sksewell@umich.edu 11684661Sksewell@umich.edu // Make sure requests are not overlapping on the databus 11694661Sksewell@umich.edu assert (dram_pkt->readyTime - busBusyUntil >= tBURST); 11704661Sksewell@umich.edu 11714661Sksewell@umich.edu // Update bus state 11724661Sksewell@umich.edu busBusyUntil = dram_pkt->readyTime; 11734661Sksewell@umich.edu 11744661Sksewell@umich.edu DPRINTF(DRAM,"Access time is %lld\n", 11754661Sksewell@umich.edu dram_pkt->readyTime - dram_pkt->entryTime); 11764661Sksewell@umich.edu 11774661Sksewell@umich.edu // Update the minimum timing between the requests 11784661Sksewell@umich.edu newTime = (busBusyUntil > tRP + tRCD + tCL) ? 11794661Sksewell@umich.edu std::max(busBusyUntil - (tRP + tRCD + tCL), curTick()) : curTick(); 11804661Sksewell@umich.edu 11814661Sksewell@umich.edu // Update the access related stats 11824661Sksewell@umich.edu if (dram_pkt->isRead) { 11834661Sksewell@umich.edu if (rowHitFlag) 11844661Sksewell@umich.edu readRowHits++; 11854661Sksewell@umich.edu bytesReadDRAM += burstSize; 11864661Sksewell@umich.edu perBankRdBursts[dram_pkt->bankId]++; 11874661Sksewell@umich.edu } else { 11884661Sksewell@umich.edu if (rowHitFlag) 11894661Sksewell@umich.edu writeRowHits++; 11904661Sksewell@umich.edu bytesWritten += burstSize; 11914661Sksewell@umich.edu perBankWrBursts[dram_pkt->bankId]++; 11924661Sksewell@umich.edu 11934661Sksewell@umich.edu // At this point, commonality between reads and writes ends. 11944661Sksewell@umich.edu // For writes, we are done since we long ago responded to the 11954661Sksewell@umich.edu // requestor. 11964661Sksewell@umich.edu return; 11974661Sksewell@umich.edu } 11984661Sksewell@umich.edu 11994661Sksewell@umich.edu // Update latency stats 12004661Sksewell@umich.edu totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime; 12014661Sksewell@umich.edu totBankLat += bankLat; 12024661Sksewell@umich.edu totBusLat += tBURST; 12034661Sksewell@umich.edu totQLat += dram_pkt->readyTime - dram_pkt->entryTime - bankLat - tBURST; 12044661Sksewell@umich.edu 12054661Sksewell@umich.edu 12064661Sksewell@umich.edu // At this point we're done dealing with the request 12074661Sksewell@umich.edu // It will be moved to a separate response queue with a 12084661Sksewell@umich.edu // correct readyTime, and eventually be sent back at that 12094661Sksewell@umich.edu //time 12104661Sksewell@umich.edu moveToRespQ(); 12114661Sksewell@umich.edu 12124661Sksewell@umich.edu // Schedule the next read event 12134661Sksewell@umich.edu if (!nextReqEvent.scheduled() && !stopReads){ 12144661Sksewell@umich.edu schedule(nextReqEvent, newTime); 12154661Sksewell@umich.edu } else { 12164661Sksewell@umich.edu if (newTime < nextReqEvent.when()) 12174661Sksewell@umich.edu reschedule(nextReqEvent, newTime); 12184661Sksewell@umich.edu } 12194661Sksewell@umich.edu} 12204661Sksewell@umich.edu 12214661Sksewell@umich.eduvoid 12224661Sksewell@umich.eduSimpleDRAM::moveToRespQ() 12234661Sksewell@umich.edu{ 12244661Sksewell@umich.edu // Remove from read queue 12254661Sksewell@umich.edu DRAMPacket* dram_pkt = readQueue.front(); 12264661Sksewell@umich.edu readQueue.pop_front(); 12274661Sksewell@umich.edu 1228 // sanity check 1229 assert(dram_pkt->size <= burstSize); 1230 1231 // Insert into response queue sorted by readyTime 1232 // It will be sent back to the requestor at its 1233 // readyTime 1234 if (respQueue.empty()) { 1235 respQueue.push_front(dram_pkt); 1236 assert(!respondEvent.scheduled()); 1237 assert(dram_pkt->readyTime >= curTick()); 1238 schedule(respondEvent, dram_pkt->readyTime); 1239 } else { 1240 bool done = false; 1241 auto i = respQueue.begin(); 1242 while (!done && i != respQueue.end()) { 1243 if ((*i)->readyTime > dram_pkt->readyTime) { 1244 respQueue.insert(i, dram_pkt); 1245 done = true; 1246 } 1247 ++i; 1248 } 1249 1250 if (!done) 1251 respQueue.push_back(dram_pkt); 1252 1253 assert(respondEvent.scheduled()); 1254 1255 if (respQueue.front()->readyTime < respondEvent.when()) { 1256 assert(respQueue.front()->readyTime >= curTick()); 1257 reschedule(respondEvent, respQueue.front()->readyTime); 1258 } 1259 } 1260} 1261 1262void 1263SimpleDRAM::scheduleNextReq() 1264{ 1265 DPRINTF(DRAM, "Reached scheduleNextReq()\n"); 1266 1267 // Figure out which read request goes next, and move it to the 1268 // front of the read queue 1269 if (!chooseNextRead()) { 1270 // In the case there is no read request to go next, trigger 1271 // writes if we have passed the low threshold (or if we are 1272 // draining) 1273 if (!writeQueue.empty() && !writeEvent.scheduled() && 1274 (writeQueue.size() > writeLowThreshold || drainManager)) 1275 triggerWrites(); 1276 } else { 1277 doDRAMAccess(readQueue.front()); 1278 } 1279} 1280 1281Tick 1282SimpleDRAM::maxBankFreeAt() const 1283{ 1284 Tick banksFree = 0; 1285 1286 for(int i = 0; i < ranksPerChannel; i++) 1287 for(int j = 0; j < banksPerRank; j++) 1288 banksFree = std::max(banks[i][j].freeAt, banksFree); 1289 1290 return banksFree; 1291} 1292 1293uint64_t 1294SimpleDRAM::minBankFreeAt(const deque<DRAMPacket*>& queue) const 1295{ 1296 uint64_t bank_mask = 0; 1297 Tick freeAt = MaxTick; 1298 1299 // detemrine if we have queued transactions targetting the 1300 // bank in question 1301 vector<bool> got_waiting(ranksPerChannel * banksPerRank, false); 1302 for (auto p = queue.begin(); p != queue.end(); ++p) { 1303 got_waiting[(*p)->bankId] = true; 1304 } 1305 1306 for (int i = 0; i < ranksPerChannel; i++) { 1307 for (int j = 0; j < banksPerRank; j++) { 1308 // if we have waiting requests for the bank, and it is 1309 // amongst the first available, update the mask 1310 if (got_waiting[i * banksPerRank + j] && 1311 banks[i][j].freeAt <= freeAt) { 1312 // reset bank mask if new minimum is found 1313 if (banks[i][j].freeAt < freeAt) 1314 bank_mask = 0; 1315 // set the bit corresponding to the available bank 1316 uint8_t bit_index = i * ranksPerChannel + j; 1317 replaceBits(bank_mask, bit_index, bit_index, 1); 1318 freeAt = banks[i][j].freeAt; 1319 } 1320 } 1321 } 1322 return bank_mask; 1323} 1324 1325void 1326SimpleDRAM::processRefreshEvent() 1327{ 1328 DPRINTF(DRAM, "Refreshing at tick %ld\n", curTick()); 1329 1330 Tick banksFree = std::max(curTick(), maxBankFreeAt()) + tRFC; 1331 1332 for(int i = 0; i < ranksPerChannel; i++) 1333 for(int j = 0; j < banksPerRank; j++) { 1334 banks[i][j].freeAt = banksFree; 1335 banks[i][j].openRow = -1; 1336 } 1337 1338 // updating startTickPrechargeAll, isprechargeAll 1339 numBanksActive = 0; 1340 startTickPrechargeAll = banksFree; 1341 1342 schedule(refreshEvent, curTick() + tREFI); 1343} 1344 1345void 1346SimpleDRAM::regStats() 1347{ 1348 using namespace Stats; 1349 1350 AbstractMemory::regStats(); 1351 1352 readReqs 1353 .name(name() + ".readReqs") 1354 .desc("Number of read requests accepted"); 1355 1356 writeReqs 1357 .name(name() + ".writeReqs") 1358 .desc("Number of write requests accepted"); 1359 1360 readBursts 1361 .name(name() + ".readBursts") 1362 .desc("Number of DRAM read bursts, " 1363 "including those serviced by the write queue"); 1364 1365 writeBursts 1366 .name(name() + ".writeBursts") 1367 .desc("Number of DRAM write bursts, " 1368 "including those merged in the write queue"); 1369 1370 servicedByWrQ 1371 .name(name() + ".servicedByWrQ") 1372 .desc("Number of DRAM read bursts serviced by the write queue"); 1373 1374 mergedWrBursts 1375 .name(name() + ".mergedWrBursts") 1376 .desc("Number of DRAM write bursts merged with an existing one"); 1377 1378 neitherReadNorWrite 1379 .name(name() + ".neitherReadNorWriteReqs") 1380 .desc("Number of requests that are neither read nor write"); 1381 1382 perBankRdBursts 1383 .init(banksPerRank * ranksPerChannel) 1384 .name(name() + ".perBankRdBursts") 1385 .desc("Per bank write bursts"); 1386 1387 perBankWrBursts 1388 .init(banksPerRank * ranksPerChannel) 1389 .name(name() + ".perBankWrBursts") 1390 .desc("Per bank write bursts"); 1391 1392 avgRdQLen 1393 .name(name() + ".avgRdQLen") 1394 .desc("Average read queue length when enqueuing") 1395 .precision(2); 1396 1397 avgWrQLen 1398 .name(name() + ".avgWrQLen") 1399 .desc("Average write queue length when enqueuing") 1400 .precision(2); 1401 1402 totQLat 1403 .name(name() + ".totQLat") 1404 .desc("Total ticks spent queuing"); 1405 1406 totBankLat 1407 .name(name() + ".totBankLat") 1408 .desc("Total ticks spent accessing banks"); 1409 1410 totBusLat 1411 .name(name() + ".totBusLat") 1412 .desc("Total ticks spent in databus transfers"); 1413 1414 totMemAccLat 1415 .name(name() + ".totMemAccLat") 1416 .desc("Total ticks spent from burst creation until serviced " 1417 "by the DRAM"); 1418 1419 avgQLat 1420 .name(name() + ".avgQLat") 1421 .desc("Average queueing delay per DRAM burst") 1422 .precision(2); 1423 1424 avgQLat = totQLat / (readBursts - servicedByWrQ); 1425 1426 avgBankLat 1427 .name(name() + ".avgBankLat") 1428 .desc("Average bank access latency per DRAM burst") 1429 .precision(2); 1430 1431 avgBankLat = totBankLat / (readBursts - servicedByWrQ); 1432 1433 avgBusLat 1434 .name(name() + ".avgBusLat") 1435 .desc("Average bus latency per DRAM burst") 1436 .precision(2); 1437 1438 avgBusLat = totBusLat / (readBursts - servicedByWrQ); 1439 1440 avgMemAccLat 1441 .name(name() + ".avgMemAccLat") 1442 .desc("Average memory access latency per DRAM burst") 1443 .precision(2); 1444 1445 avgMemAccLat = totMemAccLat / (readBursts - servicedByWrQ); 1446 1447 numRdRetry 1448 .name(name() + ".numRdRetry") 1449 .desc("Number of times read queue was full causing retry"); 1450 1451 numWrRetry 1452 .name(name() + ".numWrRetry") 1453 .desc("Number of times write queue was full causing retry"); 1454 1455 readRowHits 1456 .name(name() + ".readRowHits") 1457 .desc("Number of row buffer hits during reads"); 1458 1459 writeRowHits 1460 .name(name() + ".writeRowHits") 1461 .desc("Number of row buffer hits during writes"); 1462 1463 readRowHitRate 1464 .name(name() + ".readRowHitRate") 1465 .desc("Row buffer hit rate for reads") 1466 .precision(2); 1467 1468 readRowHitRate = (readRowHits / (readBursts - servicedByWrQ)) * 100; 1469 1470 writeRowHitRate 1471 .name(name() + ".writeRowHitRate") 1472 .desc("Row buffer hit rate for writes") 1473 .precision(2); 1474 1475 writeRowHitRate = (writeRowHits / (writeBursts - mergedWrBursts)) * 100; 1476 1477 readPktSize 1478 .init(ceilLog2(burstSize) + 1) 1479 .name(name() + ".readPktSize") 1480 .desc("Read request sizes (log2)"); 1481 1482 writePktSize 1483 .init(ceilLog2(burstSize) + 1) 1484 .name(name() + ".writePktSize") 1485 .desc("Write request sizes (log2)"); 1486 1487 rdQLenPdf 1488 .init(readBufferSize) 1489 .name(name() + ".rdQLenPdf") 1490 .desc("What read queue length does an incoming req see"); 1491 1492 wrQLenPdf 1493 .init(writeBufferSize) 1494 .name(name() + ".wrQLenPdf") 1495 .desc("What write queue length does an incoming req see"); 1496 1497 bytesPerActivate 1498 .init(maxAccessesPerRow) 1499 .name(name() + ".bytesPerActivate") 1500 .desc("Bytes accessed per row activation") 1501 .flags(nozero); 1502 1503 bytesReadDRAM 1504 .name(name() + ".bytesReadDRAM") 1505 .desc("Total number of bytes read from DRAM"); 1506 1507 bytesReadWrQ 1508 .name(name() + ".bytesReadWrQ") 1509 .desc("Total number of bytes read from write queue"); 1510 1511 bytesWritten 1512 .name(name() + ".bytesWritten") 1513 .desc("Total number of bytes written to DRAM"); 1514 1515 bytesReadSys 1516 .name(name() + ".bytesReadSys") 1517 .desc("Total read bytes from the system interface side"); 1518 1519 bytesWrittenSys 1520 .name(name() + ".bytesWrittenSys") 1521 .desc("Total written bytes from the system interface side"); 1522 1523 avgRdBW 1524 .name(name() + ".avgRdBW") 1525 .desc("Average DRAM read bandwidth in MiByte/s") 1526 .precision(2); 1527 1528 avgRdBW = (bytesReadDRAM / 1000000) / simSeconds; 1529 1530 avgWrBW 1531 .name(name() + ".avgWrBW") 1532 .desc("Average achieved write bandwidth in MiByte/s") 1533 .precision(2); 1534 1535 avgWrBW = (bytesWritten / 1000000) / simSeconds; 1536 1537 avgRdBWSys 1538 .name(name() + ".avgRdBWSys") 1539 .desc("Average system read bandwidth in MiByte/s") 1540 .precision(2); 1541 1542 avgRdBWSys = (bytesReadSys / 1000000) / simSeconds; 1543 1544 avgWrBWSys 1545 .name(name() + ".avgWrBWSys") 1546 .desc("Average system write bandwidth in MiByte/s") 1547 .precision(2); 1548 1549 avgWrBWSys = (bytesWrittenSys / 1000000) / simSeconds; 1550 1551 peakBW 1552 .name(name() + ".peakBW") 1553 .desc("Theoretical peak bandwidth in MiByte/s") 1554 .precision(2); 1555 1556 peakBW = (SimClock::Frequency / tBURST) * burstSize / 1000000; 1557 1558 busUtil 1559 .name(name() + ".busUtil") 1560 .desc("Data bus utilization in percentage") 1561 .precision(2); 1562 1563 busUtil = (avgRdBW + avgWrBW) / peakBW * 100; 1564 1565 totGap 1566 .name(name() + ".totGap") 1567 .desc("Total gap between requests"); 1568 1569 avgGap 1570 .name(name() + ".avgGap") 1571 .desc("Average gap between requests") 1572 .precision(2); 1573 1574 avgGap = totGap / (readReqs + writeReqs); 1575 1576 // Stats for DRAM Power calculation based on Micron datasheet 1577 busUtilRead 1578 .name(name() + ".busUtilRead") 1579 .desc("Data bus utilization in percentage for reads") 1580 .precision(2); 1581 1582 busUtilRead = avgRdBW / peakBW * 100; 1583 1584 busUtilWrite 1585 .name(name() + ".busUtilWrite") 1586 .desc("Data bus utilization in percentage for writes") 1587 .precision(2); 1588 1589 busUtilWrite = avgWrBW / peakBW * 100; 1590 1591 pageHitRate 1592 .name(name() + ".pageHitRate") 1593 .desc("Row buffer hit rate, read and write combined") 1594 .precision(2); 1595 1596 pageHitRate = (writeRowHits + readRowHits) / 1597 (writeBursts - mergedWrBursts + readBursts - servicedByWrQ) * 100; 1598 1599 prechargeAllPercent 1600 .name(name() + ".prechargeAllPercent") 1601 .desc("Percentage of time for which DRAM has all the banks in " 1602 "precharge state") 1603 .precision(2); 1604 1605 prechargeAllPercent = prechargeAllTime / simTicks * 100; 1606} 1607 1608void 1609SimpleDRAM::recvFunctional(PacketPtr pkt) 1610{ 1611 // rely on the abstract memory 1612 functionalAccess(pkt); 1613} 1614 1615BaseSlavePort& 1616SimpleDRAM::getSlavePort(const string &if_name, PortID idx) 1617{ 1618 if (if_name != "port") { 1619 return MemObject::getSlavePort(if_name, idx); 1620 } else { 1621 return port; 1622 } 1623} 1624 1625unsigned int 1626SimpleDRAM::drain(DrainManager *dm) 1627{ 1628 unsigned int count = port.drain(dm); 1629 1630 // if there is anything in any of our internal queues, keep track 1631 // of that as well 1632 if (!(writeQueue.empty() && readQueue.empty() && 1633 respQueue.empty())) { 1634 DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d," 1635 " resp: %d\n", writeQueue.size(), readQueue.size(), 1636 respQueue.size()); 1637 ++count; 1638 drainManager = dm; 1639 // the only part that is not drained automatically over time 1640 // is the write queue, thus trigger writes if there are any 1641 // waiting and no reads waiting, otherwise wait until the 1642 // reads are done 1643 if (readQueue.empty() && !writeQueue.empty() && 1644 !writeEvent.scheduled()) 1645 triggerWrites(); 1646 } 1647 1648 if (count) 1649 setDrainState(Drainable::Draining); 1650 else 1651 setDrainState(Drainable::Drained); 1652 return count; 1653} 1654 1655SimpleDRAM::MemoryPort::MemoryPort(const std::string& name, SimpleDRAM& _memory) 1656 : QueuedSlavePort(name, &_memory, queue), queue(_memory, *this), 1657 memory(_memory) 1658{ } 1659 1660AddrRangeList 1661SimpleDRAM::MemoryPort::getAddrRanges() const 1662{ 1663 AddrRangeList ranges; 1664 ranges.push_back(memory.getAddrRange()); 1665 return ranges; 1666} 1667 1668void 1669SimpleDRAM::MemoryPort::recvFunctional(PacketPtr pkt) 1670{ 1671 pkt->pushLabel(memory.name()); 1672 1673 if (!queue.checkFunctional(pkt)) { 1674 // Default implementation of SimpleTimingPort::recvFunctional() 1675 // calls recvAtomic() and throws away the latency; we can save a 1676 // little here by just not calculating the latency. 1677 memory.recvFunctional(pkt); 1678 } 1679 1680 pkt->popLabel(); 1681} 1682 1683Tick 1684SimpleDRAM::MemoryPort::recvAtomic(PacketPtr pkt) 1685{ 1686 return memory.recvAtomic(pkt); 1687} 1688 1689bool 1690SimpleDRAM::MemoryPort::recvTimingReq(PacketPtr pkt) 1691{ 1692 // pass it to the memory controller 1693 return memory.recvTimingReq(pkt); 1694} 1695 1696SimpleDRAM* 1697SimpleDRAMParams::create() 1698{ 1699 return new SimpleDRAM(this); 1700} 1701