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