dram_ctrl.cc revision 10142
17404SAli.Saidi@ARM.com/*
211574SCurtis.Dunham@arm.com * Copyright (c) 2010-2013 ARM Limited
37404SAli.Saidi@ARM.com * All rights reserved
47404SAli.Saidi@ARM.com *
57404SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall
67404SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual
77404SAli.Saidi@ARM.com * property including but not limited to intellectual property relating
87404SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software
97404SAli.Saidi@ARM.com * licensed hereunder.  You may use the software subject to the license
107404SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated
117404SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software,
127404SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form.
137404SAli.Saidi@ARM.com *
147404SAli.Saidi@ARM.com * Copyright (c) 2013 Amin Farmahini-Farahani
157404SAli.Saidi@ARM.com * All rights reserved.
167404SAli.Saidi@ARM.com *
177404SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without
187404SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are
197404SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright
207404SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer;
217404SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright
227404SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the
237404SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
247404SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its
257404SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from
267404SAli.Saidi@ARM.com * this software without specific prior written permission.
277404SAli.Saidi@ARM.com *
287404SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
297404SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
307404SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
317404SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
327404SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
337404SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
347404SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
357404SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
367404SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
377404SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3810037SARM gem5 Developers * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
397404SAli.Saidi@ARM.com *
4010873Sandreas.sandberg@arm.com * Authors: Andreas Hansson
417404SAli.Saidi@ARM.com *          Ani Udipi
4210474Sandreas.hansson@arm.com *          Neha Agarwal
4310474Sandreas.hansson@arm.com */
447404SAli.Saidi@ARM.com
4510037SARM gem5 Developers#include "base/trace.hh"
4610037SARM gem5 Developers#include "base/bitfield.hh"
477404SAli.Saidi@ARM.com#include "debug/Drain.hh"
487728SAli.Saidi@ARM.com#include "debug/DRAM.hh"
497404SAli.Saidi@ARM.com#include "mem/simple_dram.hh"
508245Snate@binkert.org#include "sim/system.hh"
519152Satgutier@umich.edu
528245Snate@binkert.orgusing namespace std;
538245Snate@binkert.org
5410873Sandreas.sandberg@arm.comSimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
557748SAli.Saidi@ARM.com    AbstractMemory(p),
567404SAli.Saidi@ARM.com    port(name() + ".port", *this),
577404SAli.Saidi@ARM.com    retryRdReq(false), retryWrReq(false),
587404SAli.Saidi@ARM.com    rowHitFlag(false), stopReads(false),
597404SAli.Saidi@ARM.com    writeEvent(this), respondEvent(this),
6010913Sandreas.sandberg@arm.com    refreshEvent(this), nextReqEvent(this), drainManager(NULL),
6110717Sandreas.hansson@arm.com    deviceBusWidth(p->device_bus_width), burstLength(p->burst_length),
6210717Sandreas.hansson@arm.com    deviceRowBufferSize(p->device_rowbuffer_size),
6310717Sandreas.hansson@arm.com    devicesPerRank(p->devices_per_rank),
649258SAli.Saidi@ARM.com    burstSize((devicesPerRank * burstLength * deviceBusWidth) / 8),
6510621SCurtis.Dunham@arm.com    rowBufferSize(devicesPerRank * deviceRowBufferSize),
6610621SCurtis.Dunham@arm.com    columnsPerRowBuffer(rowBufferSize / burstSize),
6710037SARM gem5 Developers    ranksPerChannel(p->ranks_per_channel),
6810037SARM gem5 Developers    banksPerRank(p->banks_per_rank), channels(p->channels), rowsPerBank(0),
6910037SARM gem5 Developers    readBufferSize(p->read_buffer_size),
7010037SARM gem5 Developers    writeBufferSize(p->write_buffer_size),
717439Sdam.sunwoo@arm.com    writeHighThreshold(writeBufferSize * p->write_high_thresh_perc / 100.0),
727576SAli.Saidi@ARM.com    writeLowThreshold(writeBufferSize * p->write_low_thresh_perc / 100.0),
7310037SARM gem5 Developers    minWritesPerSwitch(p->min_writes_per_switch), writesThisTime(0),
7410037SARM gem5 Developers    tWTR(p->tWTR), tBURST(p->tBURST),
7510037SARM gem5 Developers    tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP), tRAS(p->tRAS),
7610717Sandreas.hansson@arm.com    tRFC(p->tRFC), tREFI(p->tREFI), tRRD(p->tRRD),
7710037SARM gem5 Developers    tXAW(p->tXAW), activationLimit(p->activation_limit),
7810037SARM gem5 Developers    memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping),
7910037SARM gem5 Developers    pageMgmt(p->page_policy),
8010037SARM gem5 Developers    maxAccessesPerRow(p->max_accesses_per_row),
8110037SARM gem5 Developers    frontendLatency(p->static_frontend_latency),
8210037SARM gem5 Developers    backendLatency(p->static_backend_latency),
8310037SARM gem5 Developers    busBusyUntil(0), writeStartTime(0),
8410037SARM gem5 Developers    prevArrival(0), numReqs(0),
8510037SARM gem5 Developers    newTime(0), startTickPrechargeAll(0), numBanksActive(0)
8610037SARM gem5 Developers{
8710037SARM gem5 Developers    // create the bank states based on the dimensions of the ranks and
8810037SARM gem5 Developers    // banks
897439Sdam.sunwoo@arm.com    banks.resize(ranksPerChannel);
907404SAli.Saidi@ARM.com    actTicks.resize(ranksPerChannel);
917404SAli.Saidi@ARM.com    for (size_t c = 0; c < ranksPerChannel; ++c) {
927404SAli.Saidi@ARM.com        banks[c].resize(banksPerRank);
937404SAli.Saidi@ARM.com        actTicks[c].resize(activationLimit, 0);
947404SAli.Saidi@ARM.com    }
957404SAli.Saidi@ARM.com
9610717Sandreas.hansson@arm.com    // perform a basic check of the write thresholds
9710717Sandreas.hansson@arm.com    if (p->write_low_thresh_perc >= p->write_high_thresh_perc)
9810717Sandreas.hansson@arm.com        fatal("Write buffer low threshold %d must be smaller than the "
9910717Sandreas.hansson@arm.com              "high threshold %d\n", p->write_low_thresh_perc,
10010717Sandreas.hansson@arm.com              p->write_high_thresh_perc);
10110717Sandreas.hansson@arm.com
10210717Sandreas.hansson@arm.com    // determine the rows per bank by looking at the total capacity
10310717Sandreas.hansson@arm.com    uint64_t capacity = ULL(1) << ceilLog2(AbstractMemory::size());
10410717Sandreas.hansson@arm.com
10510717Sandreas.hansson@arm.com    DPRINTF(DRAM, "Memory capacity %lld (%lld) bytes\n", capacity,
10610717Sandreas.hansson@arm.com            AbstractMemory::size());
10710717Sandreas.hansson@arm.com
10810717Sandreas.hansson@arm.com    DPRINTF(DRAM, "Row buffer size %d bytes with %d columns per row buffer\n",
10910717Sandreas.hansson@arm.com            rowBufferSize, columnsPerRowBuffer);
11010717Sandreas.hansson@arm.com
11110717Sandreas.hansson@arm.com    rowsPerBank = capacity / (rowBufferSize * banksPerRank * ranksPerChannel);
11210717Sandreas.hansson@arm.com
11310717Sandreas.hansson@arm.com    if (range.interleaved()) {
11410717Sandreas.hansson@arm.com        if (channels != range.stripes())
11510717Sandreas.hansson@arm.com            panic("%s has %d interleaved address stripes but %d channel(s)\n",
11610717Sandreas.hansson@arm.com                  name(), range.stripes(), channels);
11710717Sandreas.hansson@arm.com
11810717Sandreas.hansson@arm.com        if (addrMapping == Enums::RoRaBaChCo) {
11910717Sandreas.hansson@arm.com            if (rowBufferSize != range.granularity()) {
12010717Sandreas.hansson@arm.com                panic("Interleaving of %s doesn't match RoRaBaChCo "
12110717Sandreas.hansson@arm.com                      "address map\n", name());
12210717Sandreas.hansson@arm.com            }
12310717Sandreas.hansson@arm.com        } else if (addrMapping == Enums::RoRaBaCoCh) {
12410717Sandreas.hansson@arm.com            if (system()->cacheLineSize() != range.granularity()) {
12510537Sandreas.hansson@arm.com                panic("Interleaving of %s doesn't match RoRaBaCoCh "
12610537Sandreas.hansson@arm.com                      "address map\n", name());
12710537Sandreas.hansson@arm.com            }
12810537Sandreas.hansson@arm.com        } else if (addrMapping == Enums::RoCoRaBaCh) {
12910537Sandreas.hansson@arm.com            if (system()->cacheLineSize() != range.granularity())
13010537Sandreas.hansson@arm.com                panic("Interleaving of %s doesn't match RoCoRaBaCh "
13110537Sandreas.hansson@arm.com                      "address map\n", name());
13210537Sandreas.hansson@arm.com        }
13310537Sandreas.hansson@arm.com    }
13410037SARM gem5 Developers}
13510037SARM gem5 Developers
13610037SARM gem5 Developersvoid
1379152Satgutier@umich.eduSimpleDRAM::init()
1389152Satgutier@umich.edu{
1399152Satgutier@umich.edu    if (!port.isConnected()) {
14010913Sandreas.sandberg@arm.com        fatal("SimpleDRAM %s is unconnected!\n", name());
14110913Sandreas.sandberg@arm.com    } else {
1429152Satgutier@umich.edu        port.sendRangeChange();
14310913Sandreas.sandberg@arm.com    }
1449152Satgutier@umich.edu}
14510913Sandreas.sandberg@arm.com
1469152Satgutier@umich.eduvoid
1479152Satgutier@umich.eduSimpleDRAM::startup()
1489152Satgutier@umich.edu{
14910913Sandreas.sandberg@arm.com    // print the configuration of the controller
15010913Sandreas.sandberg@arm.com    printParams();
1517404SAli.Saidi@ARM.com
15210037SARM gem5 Developers    // kick off the refresh
1539152Satgutier@umich.edu    schedule(refreshEvent, curTick() + tREFI);
15410037SARM gem5 Developers}
15510037SARM gem5 Developers
15610037SARM gem5 DevelopersTick
15710037SARM gem5 DevelopersSimpleDRAM::recvAtomic(PacketPtr pkt)
15810037SARM gem5 Developers{
15910037SARM gem5 Developers    DPRINTF(DRAM, "recvAtomic: %s 0x%x\n", pkt->cmdString(), pkt->getAddr());
16010037SARM gem5 Developers
16110037SARM gem5 Developers    // do the actual memory access and turn the packet into a response
1629152Satgutier@umich.edu    access(pkt);
16310913Sandreas.sandberg@arm.com
16410037SARM gem5 Developers    Tick latency = 0;
16510037SARM gem5 Developers    if (!pkt->memInhibitAsserted() && pkt->hasData()) {
16610913Sandreas.sandberg@arm.com        // this value is not supposed to be accurate, just enough to
1677733SAli.Saidi@ARM.com        // keep things going, mimic a closed page
1687404SAli.Saidi@ARM.com        latency = tRP + tRCD + tCL;
1697404SAli.Saidi@ARM.com    }
1707748SAli.Saidi@ARM.com    return latency;
1719342SAndreas.Sandberg@arm.com}
1727748SAli.Saidi@ARM.com
1739524SAndreas.Sandberg@ARM.combool
1749152Satgutier@umich.eduSimpleDRAM::readQueueFull(unsigned int neededEntries) const
1759152Satgutier@umich.edu{
17610621SCurtis.Dunham@arm.com    DPRINTF(DRAM, "Read queue limit %d, current size %d, entries needed %d\n",
1777748SAli.Saidi@ARM.com            readBufferSize, readQueue.size() + respQueue.size(),
1787748SAli.Saidi@ARM.com            neededEntries);
1797748SAli.Saidi@ARM.com
1807404SAli.Saidi@ARM.com    return
18110037SARM gem5 Developers        (readQueue.size() + respQueue.size() + neededEntries) > readBufferSize;
18210037SARM gem5 Developers}
18310037SARM gem5 Developers
18411580SDylan.Johnson@ARM.combool
18511580SDylan.Johnson@ARM.comSimpleDRAM::writeQueueFull(unsigned int neededEntries) const
1867404SAli.Saidi@ARM.com{
1878733Sgeoffrey.blake@arm.com    DPRINTF(DRAM, "Write queue limit %d, current size %d, entries needed %d\n",
18810621SCurtis.Dunham@arm.com            writeBufferSize, writeQueue.size(), neededEntries);
18910621SCurtis.Dunham@arm.com    return (writeQueue.size() + neededEntries) > writeBufferSize;
19010109SGeoffrey.Blake@arm.com}
19110037SARM gem5 Developers
19210109SGeoffrey.Blake@arm.comSimpleDRAM::DRAMPacket*
1937439Sdam.sunwoo@arm.comSimpleDRAM::decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned size, bool isRead)
1947439Sdam.sunwoo@arm.com{
1957439Sdam.sunwoo@arm.com    // decode the address based on the address mapping scheme, with
1967439Sdam.sunwoo@arm.com    // Ro, Ra, Co, Ba and Ch denoting row, rank, column, bank and
1977404SAli.Saidi@ARM.com    // channel, respectively
1987439Sdam.sunwoo@arm.com    uint8_t rank;
1997439Sdam.sunwoo@arm.com    uint8_t bank;
20010109SGeoffrey.Blake@arm.com    uint16_t row;
20110109SGeoffrey.Blake@arm.com
20210109SGeoffrey.Blake@arm.com    // truncate the address to the access granularity
20310109SGeoffrey.Blake@arm.com    Addr addr = dramPktAddr / burstSize;
20410109SGeoffrey.Blake@arm.com
20510109SGeoffrey.Blake@arm.com    // we have removed the lowest order address bits that denote the
20610109SGeoffrey.Blake@arm.com    // position within the column
20710109SGeoffrey.Blake@arm.com    if (addrMapping == Enums::RoRaBaChCo) {
2088202SAli.Saidi@ARM.com        // the lowest order bits denote the column to ensure that
2098202SAli.Saidi@ARM.com        // sequential cache lines occupy the same row
2108202SAli.Saidi@ARM.com        addr = addr / columnsPerRowBuffer;
2118202SAli.Saidi@ARM.com
2128202SAli.Saidi@ARM.com        // take out the channel part of the address
2138202SAli.Saidi@ARM.com        addr = addr / channels;
2148202SAli.Saidi@ARM.com
21510037SARM gem5 Developers        // after the channel bits, get the bank bits to interleave
21610621SCurtis.Dunham@arm.com        // over the banks
21710474Sandreas.hansson@arm.com        bank = addr % banksPerRank;
2188202SAli.Saidi@ARM.com        addr = addr / banksPerRank;
2197439Sdam.sunwoo@arm.com
22010621SCurtis.Dunham@arm.com        // after the bank, we get the rank bits which thus interleaves
2217439Sdam.sunwoo@arm.com        // over the ranks
22210621SCurtis.Dunham@arm.com        rank = addr % ranksPerChannel;
2237439Sdam.sunwoo@arm.com        addr = addr / ranksPerChannel;
22411517SCurtis.Dunham@arm.com
22511517SCurtis.Dunham@arm.com        // lastly, get the row bits
22611517SCurtis.Dunham@arm.com        row = addr % rowsPerBank;
22711574SCurtis.Dunham@arm.com        addr = addr / rowsPerBank;
22811517SCurtis.Dunham@arm.com    } else if (addrMapping == Enums::RoRaBaCoCh) {
22910037SARM gem5 Developers        // take out the channel part of the address
2307439Sdam.sunwoo@arm.com        addr = addr / channels;
2317439Sdam.sunwoo@arm.com
2327439Sdam.sunwoo@arm.com        // next, the column
23310037SARM gem5 Developers        addr = addr / columnsPerRowBuffer;
23410037SARM gem5 Developers
23510037SARM gem5 Developers        // after the column bits, we get the bank bits to interleave
2367439Sdam.sunwoo@arm.com        // over the banks
2378733Sgeoffrey.blake@arm.com        bank = addr % banksPerRank;
2387439Sdam.sunwoo@arm.com        addr = addr / banksPerRank;
23910037SARM gem5 Developers
24010037SARM gem5 Developers        // after the bank, we get the rank bits which thus interleaves
24110037SARM gem5 Developers        // over the ranks
2427404SAli.Saidi@ARM.com        rank = addr % ranksPerChannel;
2437436Sdam.sunwoo@arm.com        addr = addr / ranksPerChannel;
2447436Sdam.sunwoo@arm.com
24510037SARM gem5 Developers        // lastly, get the row bits
24610037SARM gem5 Developers        row = addr % rowsPerBank;
24710037SARM gem5 Developers        addr = addr / rowsPerBank;
24810037SARM gem5 Developers    } else if (addrMapping == Enums::RoCoRaBaCh) {
24910037SARM gem5 Developers        // optimise for closed page mode and utilise maximum
25010037SARM gem5 Developers        // parallelism of the DRAM (at the cost of power)
25110037SARM gem5 Developers
25210037SARM gem5 Developers        // take out the channel part of the address, not that this has
25311575SDylan.Johnson@ARM.com        // to match with how accesses are interleaved between the
25411575SDylan.Johnson@ARM.com        // controllers in the address mapping
25511575SDylan.Johnson@ARM.com        addr = addr / channels;
25611575SDylan.Johnson@ARM.com
25710037SARM gem5 Developers        // start with the bank bits, as this provides the maximum
25810037SARM gem5 Developers        // opportunity for parallelism between requests
25910037SARM gem5 Developers        bank = addr % banksPerRank;
26010324SCurtis.Dunham@arm.com        addr = addr / banksPerRank;
26110037SARM gem5 Developers
26211574SCurtis.Dunham@arm.com        // next get the rank bits
26311574SCurtis.Dunham@arm.com        rank = addr % ranksPerChannel;
26411574SCurtis.Dunham@arm.com        addr = addr / ranksPerChannel;
26511574SCurtis.Dunham@arm.com
26611574SCurtis.Dunham@arm.com        // next the column bits which we do not need to keep track of
26710037SARM gem5 Developers        // and simply skip past
26810037SARM gem5 Developers        addr = addr / columnsPerRowBuffer;
26910037SARM gem5 Developers
27010324SCurtis.Dunham@arm.com        // lastly, get the row bits
27110037SARM gem5 Developers        row = addr % rowsPerBank;
27210037SARM gem5 Developers        addr = addr / rowsPerBank;
27310037SARM gem5 Developers    } else
27410037SARM gem5 Developers        panic("Unknown address mapping policy chosen!");
27510037SARM gem5 Developers
27611575SDylan.Johnson@ARM.com    assert(rank < ranksPerChannel);
27710037SARM gem5 Developers    assert(bank < banksPerRank);
27810037SARM gem5 Developers    assert(row < rowsPerBank);
27910037SARM gem5 Developers
28010037SARM gem5 Developers    DPRINTF(DRAM, "Address: %lld Rank %d Bank %d Row %d\n",
28110037SARM gem5 Developers            dramPktAddr, rank, bank, row);
28210037SARM gem5 Developers
28310037SARM gem5 Developers    // create the corresponding DRAM packet with the entry time and
28410037SARM gem5 Developers    // ready time set to the current tick, the latter will be updated
28510037SARM gem5 Developers    // later
2867439Sdam.sunwoo@arm.com    uint16_t bank_id = banksPerRank * rank + bank;
2877439Sdam.sunwoo@arm.com    return new DRAMPacket(pkt, isRead, rank, bank, row, bank_id, dramPktAddr,
2887439Sdam.sunwoo@arm.com                          size, banks[rank][bank]);
2897439Sdam.sunwoo@arm.com}
2907439Sdam.sunwoo@arm.com
29110621SCurtis.Dunham@arm.comvoid
29210621SCurtis.Dunham@arm.comSimpleDRAM::addToReadQueue(PacketPtr pkt, unsigned int pktCount)
29310037SARM gem5 Developers{
29410037SARM gem5 Developers    // only add to the read queue here. whenever the request is
29510037SARM gem5 Developers    // eventually done, set the readyTime, and call schedule()
29611580SDylan.Johnson@ARM.com    assert(!pkt->isWrite());
29710037SARM gem5 Developers
29811580SDylan.Johnson@ARM.com    assert(pktCount != 0);
2997728SAli.Saidi@ARM.com
30011517SCurtis.Dunham@arm.com    // if the request size is larger than burst size, the pkt is split into
30111517SCurtis.Dunham@arm.com    // multiple DRAM packets
30210037SARM gem5 Developers    // Note if the pkt starting address is not aligened to burst size, the
30310037SARM gem5 Developers    // address of first DRAM packet is kept unaliged. Subsequent DRAM packets
30410037SARM gem5 Developers    // are aligned to burst size boundaries. This is to ensure we accurately
30510037SARM gem5 Developers    // check read packets against packets in write queue.
30610037SARM gem5 Developers    Addr addr = pkt->getAddr();
30710037SARM gem5 Developers    unsigned pktsServicedByWrQ = 0;
30810037SARM gem5 Developers    BurstHelper* burst_helper = NULL;
30910037SARM gem5 Developers    for (int cnt = 0; cnt < pktCount; ++cnt) {
31010621SCurtis.Dunham@arm.com        unsigned size = std::min((addr | (burstSize - 1)) + 1,
31110621SCurtis.Dunham@arm.com                        pkt->getAddr() + pkt->getSize()) - addr;
31210621SCurtis.Dunham@arm.com        readPktSize[ceilLog2(size)]++;
31310621SCurtis.Dunham@arm.com        readBursts++;
31410037SARM gem5 Developers
31510037SARM gem5 Developers        // First check write buffer to see if the data is already at
31610037SARM gem5 Developers        // the controller
31710109SGeoffrey.Blake@arm.com        bool foundInWrQ = false;
31810037SARM gem5 Developers        for (auto i = writeQueue.begin(); i != writeQueue.end(); ++i) {
31910109SGeoffrey.Blake@arm.com            // check if the read is subsumed in the write entry we are
32010037SARM gem5 Developers            // looking at
32110109SGeoffrey.Blake@arm.com            if ((*i)->addr <= addr &&
32210037SARM gem5 Developers                (addr + size) <= ((*i)->addr + (*i)->size)) {
32310109SGeoffrey.Blake@arm.com                foundInWrQ = true;
32410109SGeoffrey.Blake@arm.com                servicedByWrQ++;
32510109SGeoffrey.Blake@arm.com                pktsServicedByWrQ++;
32610109SGeoffrey.Blake@arm.com                DPRINTF(DRAM, "Read to addr %lld with size %d serviced by "
32710109SGeoffrey.Blake@arm.com                        "write queue\n", addr, size);
32810109SGeoffrey.Blake@arm.com                bytesReadWrQ += burstSize;
32910109SGeoffrey.Blake@arm.com                break;
33010109SGeoffrey.Blake@arm.com            }
33110109SGeoffrey.Blake@arm.com        }
33210037SARM gem5 Developers
3337728SAli.Saidi@ARM.com        // If not found in the write q, make a DRAM packet and
3348067SAli.Saidi@ARM.com        // push it onto the read queue
3357728SAli.Saidi@ARM.com        if (!foundInWrQ) {
3367728SAli.Saidi@ARM.com
33710621SCurtis.Dunham@arm.com            // Make the burst helper for split packets
3387728SAli.Saidi@ARM.com            if (pktCount > 1 && burst_helper == NULL) {
3397728SAli.Saidi@ARM.com                DPRINTF(DRAM, "Read to addr %lld translates to %d "
34010621SCurtis.Dunham@arm.com                        "dram requests\n", pkt->getAddr(), pktCount);
34110037SARM gem5 Developers                burst_helper = new BurstHelper(pktCount);
34210037SARM gem5 Developers            }
34310037SARM gem5 Developers
34410037SARM gem5 Developers            DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, true);
34510037SARM gem5 Developers            dram_pkt->burstHelper = burst_helper;
34610037SARM gem5 Developers
3477728SAli.Saidi@ARM.com            assert(!readQueueFull(1));
3487728SAli.Saidi@ARM.com            rdQLenPdf[readQueue.size() + respQueue.size()]++;
3497728SAli.Saidi@ARM.com
3507728SAli.Saidi@ARM.com            DPRINTF(DRAM, "Adding to read queue\n");
3517728SAli.Saidi@ARM.com
3527728SAli.Saidi@ARM.com            readQueue.push_back(dram_pkt);
3537728SAli.Saidi@ARM.com
3547728SAli.Saidi@ARM.com            // Update stats
3557728SAli.Saidi@ARM.com            avgRdQLen = readQueue.size() + respQueue.size();
3567728SAli.Saidi@ARM.com        }
35710621SCurtis.Dunham@arm.com
3587728SAli.Saidi@ARM.com        // Starting address of next dram pkt (aligend to burstSize boundary)
3599258SAli.Saidi@ARM.com        addr = (addr | (burstSize - 1)) + 1;
36010037SARM gem5 Developers    }
36110037SARM gem5 Developers
36210037SARM gem5 Developers    // If all packets are serviced by write queue, we send the repsonse back
36310037SARM gem5 Developers    if (pktsServicedByWrQ == pktCount) {
36410037SARM gem5 Developers        accessAndRespond(pkt, frontendLatency);
36510037SARM gem5 Developers        return;
3669535Smrinmoy.ghosh@arm.com    }
36710037SARM gem5 Developers
36810037SARM gem5 Developers    // Update how many split packets are serviced by write queue
36910037SARM gem5 Developers    if (burst_helper != NULL)
37010037SARM gem5 Developers        burst_helper->burstsServiced = pktsServicedByWrQ;
3719258SAli.Saidi@ARM.com
3729535Smrinmoy.ghosh@arm.com    // If we are not already scheduled to get the read request out of
3739535Smrinmoy.ghosh@arm.com    // the queue, do so now
3749535Smrinmoy.ghosh@arm.com    if (!nextReqEvent.scheduled() && !stopReads) {
3759535Smrinmoy.ghosh@arm.com        DPRINTF(DRAM, "Request scheduled immediately\n");
3769535Smrinmoy.ghosh@arm.com        schedule(nextReqEvent, curTick());
3779535Smrinmoy.ghosh@arm.com    }
3789258SAli.Saidi@ARM.com}
3799258SAli.Saidi@ARM.com
3809258SAli.Saidi@ARM.comvoid
38110579SAndrew.Bardsley@arm.comSimpleDRAM::processWriteEvent()
38210579SAndrew.Bardsley@arm.com{
38310579SAndrew.Bardsley@arm.com    assert(!writeQueue.empty());
38410037SARM gem5 Developers
38510579SAndrew.Bardsley@arm.com    DPRINTF(DRAM, "Beginning DRAM Write\n");
38611517SCurtis.Dunham@arm.com    Tick temp1 M5_VAR_USED = std::max(curTick(), busBusyUntil);
38711517SCurtis.Dunham@arm.com    Tick temp2 M5_VAR_USED = std::max(curTick(), maxBankFreeAt());
38810579SAndrew.Bardsley@arm.com
38910037SARM gem5 Developers    chooseNextWrite();
39010579SAndrew.Bardsley@arm.com    DRAMPacket* dram_pkt = writeQueue.front();
39110579SAndrew.Bardsley@arm.com    // sanity check
39210579SAndrew.Bardsley@arm.com    assert(dram_pkt->size <= burstSize);
39310579SAndrew.Bardsley@arm.com    doDRAMAccess(dram_pkt);
39410579SAndrew.Bardsley@arm.com
39510579SAndrew.Bardsley@arm.com    writeQueue.pop_front();
39610579SAndrew.Bardsley@arm.com    delete dram_pkt;
39710579SAndrew.Bardsley@arm.com
3989258SAli.Saidi@ARM.com    ++writesThisTime;
3999258SAli.Saidi@ARM.com
4009258SAli.Saidi@ARM.com    DPRINTF(DRAM, "Writing, bus busy for %lld ticks, banks busy "
4019258SAli.Saidi@ARM.com            "for %lld ticks\n", busBusyUntil - temp1, maxBankFreeAt() - temp2);
4029258SAli.Saidi@ARM.com
4039258SAli.Saidi@ARM.com    // Update stats
4049258SAli.Saidi@ARM.com    avgWrQLen = writeQueue.size();
4059258SAli.Saidi@ARM.com
4069258SAli.Saidi@ARM.com    // If we emptied the write queue, or got below the threshold and
4079535Smrinmoy.ghosh@arm.com    // are not draining, or we have reads waiting and have done enough
4089258SAli.Saidi@ARM.com    // writes, then switch to reads. The retry above could already
4099258SAli.Saidi@ARM.com    // have caused it to be scheduled, so first check
41010621SCurtis.Dunham@arm.com    if (writeQueue.empty() ||
4119258SAli.Saidi@ARM.com        (writeQueue.size() < writeLowThreshold && !drainManager) ||
41210037SARM gem5 Developers        (!readQueue.empty() && writesThisTime >= minWritesPerSwitch)) {
41310037SARM gem5 Developers        // turn the bus back around for reads again
4149258SAli.Saidi@ARM.com        busBusyUntil += tWTR;
4159535Smrinmoy.ghosh@arm.com        stopReads = false;
4169535Smrinmoy.ghosh@arm.com        writesThisTime = 0;
41710474Sandreas.hansson@arm.com
41810474Sandreas.hansson@arm.com        if (!nextReqEvent.scheduled())
41910474Sandreas.hansson@arm.com            schedule(nextReqEvent, busBusyUntil);
4209535Smrinmoy.ghosh@arm.com    } else {
4219535Smrinmoy.ghosh@arm.com        assert(!writeEvent.scheduled());
42210621SCurtis.Dunham@arm.com        DPRINTF(DRAM, "Next write scheduled at %lld\n", newTime);
42310037SARM gem5 Developers        schedule(writeEvent, newTime);
42410037SARM gem5 Developers    }
42510037SARM gem5 Developers
4269535Smrinmoy.ghosh@arm.com    if (retryWrReq) {
4279258SAli.Saidi@ARM.com        retryWrReq = false;
4289258SAli.Saidi@ARM.com        port.sendRetry();
4299258SAli.Saidi@ARM.com    }
4309258SAli.Saidi@ARM.com
4319258SAli.Saidi@ARM.com    // if there is nothing left in any queue, signal a drain
4329535Smrinmoy.ghosh@arm.com    if (writeQueue.empty() && readQueue.empty() &&
4339258SAli.Saidi@ARM.com        respQueue.empty () && drainManager) {
43410037SARM gem5 Developers        drainManager->signalDrainDone();
43510037SARM gem5 Developers        drainManager = NULL;
43610037SARM gem5 Developers    }
4379535Smrinmoy.ghosh@arm.com}
4389535Smrinmoy.ghosh@arm.com
4399258SAli.Saidi@ARM.com
4409535Smrinmoy.ghosh@arm.comvoid
4419258SAli.Saidi@ARM.comSimpleDRAM::triggerWrites()
44210621SCurtis.Dunham@arm.com{
4439258SAli.Saidi@ARM.com    DPRINTF(DRAM, "Writes triggered at %lld\n", curTick());
44410621SCurtis.Dunham@arm.com    // Flag variable to stop any more read scheduling
4459258SAli.Saidi@ARM.com    stopReads = true;
4469258SAli.Saidi@ARM.com
4477728SAli.Saidi@ARM.com    writeStartTime = std::max(busBusyUntil, curTick()) + tWTR;
4487728SAli.Saidi@ARM.com
4497728SAli.Saidi@ARM.com    DPRINTF(DRAM, "Writes scheduled at %lld\n", writeStartTime);
4507728SAli.Saidi@ARM.com
4517728SAli.Saidi@ARM.com    assert(writeStartTime >= curTick());
4527404SAli.Saidi@ARM.com    assert(!writeEvent.scheduled());
4537404SAli.Saidi@ARM.com    schedule(writeEvent, writeStartTime);
4547404SAli.Saidi@ARM.com}
45510037SARM gem5 Developers
4567404SAli.Saidi@ARM.comvoid
45710037SARM gem5 DevelopersSimpleDRAM::addToWriteQueue(PacketPtr pkt, unsigned int pktCount)
45810037SARM gem5 Developers{
45910037SARM gem5 Developers    // only add to the write queue here. whenever the request is
4607406SAli.Saidi@ARM.com    // eventually done, set the readyTime, and call schedule()
46110621SCurtis.Dunham@arm.com    assert(pkt->isWrite());
46210621SCurtis.Dunham@arm.com
46310037SARM gem5 Developers    // if the request size is larger than burst size, the pkt is split into
46410037SARM gem5 Developers    // multiple DRAM packets
4657406SAli.Saidi@ARM.com    Addr addr = pkt->getAddr();
46610037SARM gem5 Developers    for (int cnt = 0; cnt < pktCount; ++cnt) {
46710037SARM gem5 Developers        unsigned size = std::min((addr | (burstSize - 1)) + 1,
46810037SARM gem5 Developers                        pkt->getAddr() + pkt->getSize()) - addr;
46910474Sandreas.hansson@arm.com        writePktSize[ceilLog2(size)]++;
47010474Sandreas.hansson@arm.com        writeBursts++;
47110474Sandreas.hansson@arm.com
47210474Sandreas.hansson@arm.com        // see if we can merge with an existing item in the write
47310474Sandreas.hansson@arm.com        // queue and keep track of whether we have merged or not so we
47410037SARM gem5 Developers        // can stop at that point and also avoid enqueueing a new
47510474Sandreas.hansson@arm.com        // request
47610474Sandreas.hansson@arm.com        bool merged = false;
47710474Sandreas.hansson@arm.com        auto w = writeQueue.begin();
47810474Sandreas.hansson@arm.com
47910474Sandreas.hansson@arm.com        while(!merged && w != writeQueue.end()) {
48010037SARM gem5 Developers            // either of the two could be first, if they are the same
48110037SARM gem5 Developers            // it does not matter which way we go
48210037SARM gem5 Developers            if ((*w)->addr >= addr) {
4837404SAli.Saidi@ARM.com                // the existing one starts after the new one, figure
4847406SAli.Saidi@ARM.com                // out where the new one ends with respect to the
48510037SARM gem5 Developers                // existing one
48610037SARM gem5 Developers                if ((addr + size) >= ((*w)->addr + (*w)->size)) {
48710037SARM gem5 Developers                    // check if the existing one is completely
48810474Sandreas.hansson@arm.com                    // subsumed in the new one
48910474Sandreas.hansson@arm.com                    DPRINTF(DRAM, "Merging write covering existing burst\n");
49010474Sandreas.hansson@arm.com                    merged = true;
49110474Sandreas.hansson@arm.com                    // update both the address and the size
49210474Sandreas.hansson@arm.com                    (*w)->addr = addr;
49310037SARM gem5 Developers                    (*w)->size = size;
49410474Sandreas.hansson@arm.com                } else if ((addr + size) >= (*w)->addr &&
49510474Sandreas.hansson@arm.com                           ((*w)->addr + (*w)->size - addr) <= burstSize) {
49610474Sandreas.hansson@arm.com                    // the new one is just before or partially
49710474Sandreas.hansson@arm.com                    // overlapping with the existing one, and together
49810474Sandreas.hansson@arm.com                    // they fit within a burst
49910037SARM gem5 Developers                    DPRINTF(DRAM, "Merging write before existing burst\n");
50010037SARM gem5 Developers                    merged = true;
50110037SARM gem5 Developers                    // the existing queue item needs to be adjusted with
50210037SARM gem5 Developers                    // respect to both address and size
5037404SAli.Saidi@ARM.com                    (*w)->size = (*w)->addr + (*w)->size - addr;
5047404SAli.Saidi@ARM.com                    (*w)->addr = addr;
50510037SARM gem5 Developers                }
50610037SARM gem5 Developers            } else {
50710037SARM gem5 Developers                // the new one starts after the current one, figure
50810037SARM gem5 Developers                // out where the existing one ends with respect to the
5097404SAli.Saidi@ARM.com                // new one
5107404SAli.Saidi@ARM.com                if (((*w)->addr + (*w)->size) >= (addr + size)) {
5117439Sdam.sunwoo@arm.com                    // check if the new one is completely subsumed in the
51211395Sandreas.sandberg@arm.com                    // existing one
51311395Sandreas.sandberg@arm.com                    DPRINTF(DRAM, "Merging write into existing burst\n");
5147439Sdam.sunwoo@arm.com                    merged = true;
51510037SARM gem5 Developers                    // no adjustments necessary
5167579Sminkyu.jeong@arm.com                } else if (((*w)->addr + (*w)->size) >= addr &&
5177728SAli.Saidi@ARM.com                           (addr + size - (*w)->addr) <= burstSize) {
5187728SAli.Saidi@ARM.com                    // the existing one is just before or partially
5197579Sminkyu.jeong@arm.com                    // overlapping with the new one, and together
5207579Sminkyu.jeong@arm.com                    // they fit within a burst
5217579Sminkyu.jeong@arm.com                    DPRINTF(DRAM, "Merging write after existing burst\n");
5227579Sminkyu.jeong@arm.com                    merged = true;
5237579Sminkyu.jeong@arm.com                    // the address is right, and only the size has
5247579Sminkyu.jeong@arm.com                    // to be adjusted
5257404SAli.Saidi@ARM.com                    (*w)->size = addr + size - (*w)->addr;
5267404SAli.Saidi@ARM.com                }
52710836Sandreas.hansson@arm.com            }
5287946SGiacomo.Gabrielli@arm.com            ++w;
52910836Sandreas.hansson@arm.com        }
5307946SGiacomo.Gabrielli@arm.com
5317946SGiacomo.Gabrielli@arm.com        // if the item was not merged we need to create a new write
53211181Snathananel.premillieu@arm.com        // and enqueue it
53311181Snathananel.premillieu@arm.com        if (!merged) {
53411181Snathananel.premillieu@arm.com            DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, false);
53511181Snathananel.premillieu@arm.com
53610037SARM gem5 Developers            assert(writeQueue.size() < writeBufferSize);
53710037SARM gem5 Developers            wrQLenPdf[writeQueue.size()]++;
53810037SARM gem5 Developers
53910037SARM gem5 Developers            DPRINTF(DRAM, "Adding to write queue\n");
54010037SARM gem5 Developers
54110037SARM gem5 Developers            writeQueue.push_back(dram_pkt);
54210037SARM gem5 Developers
54310037SARM gem5 Developers            // Update stats
54410037SARM gem5 Developers            avgWrQLen = writeQueue.size();
54510037SARM gem5 Developers        } else {
54610037SARM gem5 Developers            // keep track of the fact that this burst effectively
54710037SARM gem5 Developers            // disappeared as it was merged with an existing one
54810037SARM gem5 Developers            mergedWrBursts++;
54910037SARM gem5 Developers        }
55010037SARM gem5 Developers
55110037SARM gem5 Developers        // Starting address of next dram pkt (aligend to burstSize boundary)
55210037SARM gem5 Developers        addr = (addr | (burstSize - 1)) + 1;
55310037SARM gem5 Developers    }
55410037SARM gem5 Developers
55510037SARM gem5 Developers    // we do not wait for the writes to be send to the actual memory,
55610037SARM gem5 Developers    // but instead take responsibility for the consistency here and
55710621SCurtis.Dunham@arm.com    // snoop the write queue for any upcoming reads
55810621SCurtis.Dunham@arm.com    // @todo, if a pkt size is larger than burst size, we might need a
55910836Sandreas.hansson@arm.com    // different front end latency
56010037SARM gem5 Developers    accessAndRespond(pkt, frontendLatency);
56110037SARM gem5 Developers
56210037SARM gem5 Developers    // If your write buffer is starting to fill up, drain it!
56310037SARM gem5 Developers    if (writeQueue.size() >= writeHighThreshold && !stopReads){
56410037SARM gem5 Developers        triggerWrites();
56510037SARM gem5 Developers    }
56610037SARM gem5 Developers}
56710037SARM gem5 Developers
56810037SARM gem5 Developersvoid
56910037SARM gem5 DevelopersSimpleDRAM::printParams() const
57010037SARM gem5 Developers{
57110037SARM gem5 Developers    // Sanity check print of important parameters
57210037SARM gem5 Developers    DPRINTF(DRAM,
57310037SARM gem5 Developers            "Memory controller %s physical organization\n"      \
57410037SARM gem5 Developers            "Number of devices per rank   %d\n"                 \
57511517SCurtis.Dunham@arm.com            "Device bus width (in bits)   %d\n"                 \
57610037SARM gem5 Developers            "DRAM data bus burst          %d\n"                 \
57710037SARM gem5 Developers            "Row buffer size              %d\n"                 \
57810037SARM gem5 Developers            "Columns per row buffer       %d\n"                 \
57910037SARM gem5 Developers            "Rows    per bank             %d\n"                 \
58010037SARM gem5 Developers            "Banks   per rank             %d\n"                 \
58110037SARM gem5 Developers            "Ranks   per channel          %d\n"                 \
58210037SARM gem5 Developers            "Total mem capacity           %u\n",
58310037SARM gem5 Developers            name(), devicesPerRank, deviceBusWidth, burstSize, rowBufferSize,
58410037SARM gem5 Developers            columnsPerRowBuffer, rowsPerBank, banksPerRank, ranksPerChannel,
58510037SARM gem5 Developers            rowBufferSize * rowsPerBank * banksPerRank * ranksPerChannel);
58610037SARM gem5 Developers
58710037SARM gem5 Developers    string scheduler =  memSchedPolicy == Enums::fcfs ? "FCFS" : "FR-FCFS";
58810037SARM gem5 Developers    string address_mapping = addrMapping == Enums::RoRaBaChCo ? "RoRaBaChCo" :
58910037SARM gem5 Developers        (addrMapping == Enums::RoRaBaCoCh ? "RoRaBaCoCh" : "RoCoRaBaCh");
59010037SARM gem5 Developers    string page_policy = pageMgmt == Enums::open ? "OPEN" :
59110037SARM gem5 Developers        (pageMgmt == Enums::open_adaptive ? "OPEN (adaptive)" : "CLOSE");
59210037SARM gem5 Developers
59310037SARM gem5 Developers    DPRINTF(DRAM,
59410037SARM gem5 Developers            "Memory controller %s characteristics\n"    \
59510037SARM gem5 Developers            "Read buffer size     %d\n"                 \
59610037SARM gem5 Developers            "Write buffer size    %d\n"                 \
59710037SARM gem5 Developers            "Write high thresh    %d\n"                 \
59810037SARM gem5 Developers            "Write low thresh     %d\n"                 \
59910474Sandreas.hansson@arm.com            "Scheduler            %s\n"                 \
60010474Sandreas.hansson@arm.com            "Address mapping      %s\n"                 \
60110474Sandreas.hansson@arm.com            "Page policy          %s\n",
60210474Sandreas.hansson@arm.com            name(), readBufferSize, writeBufferSize, writeHighThreshold,
60310474Sandreas.hansson@arm.com            writeLowThreshold, scheduler, address_mapping, page_policy);
60410037SARM gem5 Developers
60510474Sandreas.hansson@arm.com    DPRINTF(DRAM, "Memory controller %s timing specs\n" \
60610474Sandreas.hansson@arm.com            "tRCD      %d ticks\n"                        \
60710474Sandreas.hansson@arm.com            "tCL       %d ticks\n"                        \
60810474Sandreas.hansson@arm.com            "tRP       %d ticks\n"                        \
60910474Sandreas.hansson@arm.com            "tBURST    %d ticks\n"                        \
61010474Sandreas.hansson@arm.com            "tRFC      %d ticks\n"                        \
61110474Sandreas.hansson@arm.com            "tREFI     %d ticks\n"                        \
61210037SARM gem5 Developers            "tWTR      %d ticks\n"                        \
61310037SARM gem5 Developers            "tXAW (%d) %d ticks\n",
61410037SARM gem5 Developers            name(), tRCD, tCL, tRP, tBURST, tRFC, tREFI, tWTR,
61510037SARM gem5 Developers            activationLimit, tXAW);
61610037SARM gem5 Developers}
61710037SARM gem5 Developers
61810037SARM gem5 Developersvoid
61910037SARM gem5 DevelopersSimpleDRAM::printQs() const {
62010037SARM gem5 Developers    DPRINTF(DRAM, "===READ QUEUE===\n\n");
62110037SARM gem5 Developers    for (auto i = readQueue.begin() ;  i != readQueue.end() ; ++i) {
62210037SARM gem5 Developers        DPRINTF(DRAM, "Read %lu\n", (*i)->addr);
62310474Sandreas.hansson@arm.com    }
62410474Sandreas.hansson@arm.com    DPRINTF(DRAM, "\n===RESP QUEUE===\n\n");
62510474Sandreas.hansson@arm.com    for (auto i = respQueue.begin() ;  i != respQueue.end() ; ++i) {
62610474Sandreas.hansson@arm.com        DPRINTF(DRAM, "Response %lu\n", (*i)->addr);
62710474Sandreas.hansson@arm.com    }
62810037SARM gem5 Developers    DPRINTF(DRAM, "\n===WRITE QUEUE===\n\n");
62910474Sandreas.hansson@arm.com    for (auto i = writeQueue.begin() ;  i != writeQueue.end() ; ++i) {
63010474Sandreas.hansson@arm.com        DPRINTF(DRAM, "Write %lu\n", (*i)->addr);
63110474Sandreas.hansson@arm.com    }
63210474Sandreas.hansson@arm.com}
63310474Sandreas.hansson@arm.com
63410474Sandreas.hansson@arm.combool
63510474Sandreas.hansson@arm.comSimpleDRAM::recvTimingReq(PacketPtr pkt)
63610037SARM gem5 Developers{
63710037SARM gem5 Developers    /// @todo temporary hack to deal with memory corruption issues until
63810037SARM gem5 Developers    /// 4-phase transactions are complete
63910037SARM gem5 Developers    for (int x = 0; x < pendingDelete.size(); x++)
64010037SARM gem5 Developers        delete pendingDelete[x];
64110037SARM gem5 Developers    pendingDelete.clear();
64210037SARM gem5 Developers
64310037SARM gem5 Developers    // This is where we enter from the outside world
64410037SARM gem5 Developers    DPRINTF(DRAM, "recvTimingReq: request %s addr %lld size %d\n",
64510474Sandreas.hansson@arm.com            pkt->cmdString(), pkt->getAddr(), pkt->getSize());
64610474Sandreas.hansson@arm.com
64710474Sandreas.hansson@arm.com    // simply drop inhibited packets for now
64810474Sandreas.hansson@arm.com    if (pkt->memInhibitAsserted()) {
64910474Sandreas.hansson@arm.com        DPRINTF(DRAM,"Inhibited packet -- Dropping it now\n");
65010037SARM gem5 Developers        pendingDelete.push_back(pkt);
65110474Sandreas.hansson@arm.com        return true;
65210474Sandreas.hansson@arm.com    }
65310474Sandreas.hansson@arm.com
65410474Sandreas.hansson@arm.com   // Every million accesses, print the state of the queues
65510474Sandreas.hansson@arm.com   if (numReqs % 1000000 == 0)
65610037SARM gem5 Developers       printQs();
65710037SARM gem5 Developers
65810037SARM gem5 Developers    // Calc avg gap between requests
65910037SARM gem5 Developers    if (prevArrival != 0) {
66010037SARM gem5 Developers        totGap += curTick() - prevArrival;
66110037SARM gem5 Developers    }
66210037SARM gem5 Developers    prevArrival = curTick();
66310037SARM gem5 Developers
66410037SARM gem5 Developers
66510037SARM gem5 Developers    // Find out how many dram packets a pkt translates to
66610037SARM gem5 Developers    // If the burst size is equal or larger than the pkt size, then a pkt
66710037SARM gem5 Developers    // translates to only one dram packet. Otherwise, a pkt translates to
66810037SARM gem5 Developers    // multiple dram packets
66910037SARM gem5 Developers    unsigned size = pkt->getSize();
67010037SARM gem5 Developers    unsigned offset = pkt->getAddr() & (burstSize - 1);
67110037SARM gem5 Developers    unsigned int dram_pkt_count = divCeil(offset + size, burstSize);
67210037SARM gem5 Developers
67310037SARM gem5 Developers    // check local buffers and do not accept if full
67410037SARM gem5 Developers    if (pkt->isRead()) {
67510037SARM gem5 Developers        assert(size != 0);
67610037SARM gem5 Developers        if (readQueueFull(dram_pkt_count)) {
67711395Sandreas.sandberg@arm.com            DPRINTF(DRAM, "Read queue full, not accepting\n");
67811395Sandreas.sandberg@arm.com            // remember that we have to retry this port
67910037SARM gem5 Developers            retryRdReq = true;
68010037SARM gem5 Developers            numRdRetry++;
68110037SARM gem5 Developers            return false;
68210037SARM gem5 Developers        } else {
68310037SARM gem5 Developers            addToReadQueue(pkt, dram_pkt_count);
68410037SARM gem5 Developers            readReqs++;
68510037SARM gem5 Developers            numReqs++;
68610037SARM gem5 Developers            bytesReadSys += size;
68710037SARM gem5 Developers        }
68810037SARM gem5 Developers    } else if (pkt->isWrite()) {
68910037SARM gem5 Developers        assert(size != 0);
69010037SARM gem5 Developers        if (writeQueueFull(dram_pkt_count)) {
69110037SARM gem5 Developers            DPRINTF(DRAM, "Write queue full, not accepting\n");
69210037SARM gem5 Developers            // remember that we have to retry this port
69310836Sandreas.hansson@arm.com            retryWrReq = true;
69410037SARM gem5 Developers            numWrRetry++;
69510037SARM gem5 Developers            return false;
69610037SARM gem5 Developers        } else {
69710037SARM gem5 Developers            addToWriteQueue(pkt, dram_pkt_count);
69810324SCurtis.Dunham@arm.com            writeReqs++;
69910037SARM gem5 Developers            numReqs++;
70010037SARM gem5 Developers            bytesWrittenSys += size;
70110037SARM gem5 Developers        }
70210037SARM gem5 Developers    } else {
70310037SARM gem5 Developers        DPRINTF(DRAM,"Neither read nor write, ignore timing\n");
70410037SARM gem5 Developers        neitherReadNorWrite++;
70510037SARM gem5 Developers        accessAndRespond(pkt, 1);
70610037SARM gem5 Developers    }
70710037SARM gem5 Developers
70810037SARM gem5 Developers    retryRdReq = false;
70910037SARM gem5 Developers    retryWrReq = false;
71010037SARM gem5 Developers    return true;
71110037SARM gem5 Developers}
71210037SARM gem5 Developers
71310037SARM gem5 Developersvoid
71410037SARM gem5 DevelopersSimpleDRAM::processRespondEvent()
71510037SARM gem5 Developers{
71610037SARM gem5 Developers    DPRINTF(DRAM,
71710037SARM gem5 Developers            "processRespondEvent(): Some req has reached its readyTime\n");
71810037SARM gem5 Developers
71910037SARM gem5 Developers    DRAMPacket* dram_pkt = respQueue.front();
72010037SARM gem5 Developers
72110037SARM gem5 Developers    if (dram_pkt->burstHelper) {
72210037SARM gem5 Developers        // it is a split packet
72310037SARM gem5 Developers        dram_pkt->burstHelper->burstsServiced++;
72410037SARM gem5 Developers        if (dram_pkt->burstHelper->burstsServiced ==
72510037SARM gem5 Developers                                  dram_pkt->burstHelper->burstCount) {
72610037SARM gem5 Developers            // we have now serviced all children packets of a system packet
72710037SARM gem5 Developers            // so we can now respond to the requester
72810037SARM gem5 Developers            // @todo we probably want to have a different front end and back
72910037SARM gem5 Developers            // end latency for split packets
73010037SARM gem5 Developers            accessAndRespond(dram_pkt->pkt, frontendLatency + backendLatency);
73110037SARM gem5 Developers            delete dram_pkt->burstHelper;
73210037SARM gem5 Developers            dram_pkt->burstHelper = NULL;
73310037SARM gem5 Developers        }
73410037SARM gem5 Developers    } else {
73510324SCurtis.Dunham@arm.com        // it is not a split packet
73610324SCurtis.Dunham@arm.com        accessAndRespond(dram_pkt->pkt, frontendLatency + backendLatency);
73710324SCurtis.Dunham@arm.com    }
73810324SCurtis.Dunham@arm.com
73910324SCurtis.Dunham@arm.com    delete respQueue.front();
74010324SCurtis.Dunham@arm.com    respQueue.pop_front();
74110324SCurtis.Dunham@arm.com
74210037SARM gem5 Developers    // Update stats
74310621SCurtis.Dunham@arm.com    avgRdQLen = readQueue.size() + respQueue.size();
74410621SCurtis.Dunham@arm.com
74510037SARM gem5 Developers    if (!respQueue.empty()) {
74610037SARM gem5 Developers        assert(respQueue.front()->readyTime >= curTick());
74710037SARM gem5 Developers        assert(!respondEvent.scheduled());
74810324SCurtis.Dunham@arm.com        schedule(respondEvent, respQueue.front()->readyTime);
74910037SARM gem5 Developers    } else {
75011575SDylan.Johnson@ARM.com        // if there is nothing left in any queue, signal a drain
75111575SDylan.Johnson@ARM.com        if (writeQueue.empty() && readQueue.empty() &&
75211575SDylan.Johnson@ARM.com            drainManager) {
75310037SARM gem5 Developers            drainManager->signalDrainDone();
75410037SARM gem5 Developers            drainManager = NULL;
75510037SARM gem5 Developers        }
75611575SDylan.Johnson@ARM.com    }
75711575SDylan.Johnson@ARM.com
75811575SDylan.Johnson@ARM.com    // We have made a location in the queue available at this point,
75911575SDylan.Johnson@ARM.com    // so if there is a read that was forced to wait, retry now
76011575SDylan.Johnson@ARM.com    if (retryRdReq) {
76111575SDylan.Johnson@ARM.com        retryRdReq = false;
76211575SDylan.Johnson@ARM.com        port.sendRetry();
76311575SDylan.Johnson@ARM.com    }
76411575SDylan.Johnson@ARM.com}
76511575SDylan.Johnson@ARM.com
76611575SDylan.Johnson@ARM.comvoid
76711575SDylan.Johnson@ARM.comSimpleDRAM::chooseNextWrite()
76811575SDylan.Johnson@ARM.com{
76911575SDylan.Johnson@ARM.com    // This method does the arbitration between write requests. The
77011575SDylan.Johnson@ARM.com    // chosen packet is simply moved to the head of the write
77111575SDylan.Johnson@ARM.com    // queue. The other methods know that this is the place to
77211575SDylan.Johnson@ARM.com    // look. For example, with FCFS, this method does nothing
77311575SDylan.Johnson@ARM.com    assert(!writeQueue.empty());
77411575SDylan.Johnson@ARM.com
77511575SDylan.Johnson@ARM.com    if (writeQueue.size() == 1) {
77610037SARM gem5 Developers        DPRINTF(DRAM, "Single write request, nothing to do\n");
77710037SARM gem5 Developers        return;
77810037SARM gem5 Developers    }
77910324SCurtis.Dunham@arm.com
78010324SCurtis.Dunham@arm.com    if (memSchedPolicy == Enums::fcfs) {
78110037SARM gem5 Developers        // Do nothing, since the correct request is already head
78210324SCurtis.Dunham@arm.com    } else if (memSchedPolicy == Enums::frfcfs) {
78310037SARM gem5 Developers        reorderQueue(writeQueue);
78410037SARM gem5 Developers    } else
78510037SARM gem5 Developers        panic("No scheduling policy chosen\n");
78610037SARM gem5 Developers
78710037SARM gem5 Developers    DPRINTF(DRAM, "Selected next write request\n");
78810324SCurtis.Dunham@arm.com}
78910324SCurtis.Dunham@arm.com
79010037SARM gem5 Developersbool
79110324SCurtis.Dunham@arm.comSimpleDRAM::chooseNextRead()
79210037SARM gem5 Developers{
79310037SARM gem5 Developers    // This method does the arbitration between read requests. The
79410037SARM gem5 Developers    // chosen packet is simply moved to the head of the queue. The
79510037SARM gem5 Developers    // other methods know that this is the place to look. For example,
79610037SARM gem5 Developers    // with FCFS, this method does nothing
79710037SARM gem5 Developers    if (readQueue.empty()) {
79810324SCurtis.Dunham@arm.com        DPRINTF(DRAM, "No read request to select\n");
79910037SARM gem5 Developers        return false;
80010037SARM gem5 Developers    }
80110037SARM gem5 Developers
80210037SARM gem5 Developers    // If there is only one request then there is nothing left to do
80310037SARM gem5 Developers    if (readQueue.size() == 1)
80410324SCurtis.Dunham@arm.com        return true;
80510324SCurtis.Dunham@arm.com
80610324SCurtis.Dunham@arm.com    if (memSchedPolicy == Enums::fcfs) {
80710324SCurtis.Dunham@arm.com        // Do nothing, since the request to serve is already the first
80810324SCurtis.Dunham@arm.com        // one in the read queue
80910324SCurtis.Dunham@arm.com    } else if (memSchedPolicy == Enums::frfcfs) {
81010324SCurtis.Dunham@arm.com        reorderQueue(readQueue);
81110037SARM gem5 Developers    } else
81210037SARM gem5 Developers        panic("No scheduling policy chosen!\n");
81310037SARM gem5 Developers
81410324SCurtis.Dunham@arm.com    DPRINTF(DRAM, "Selected next read request\n");
81510037SARM gem5 Developers    return true;
81610324SCurtis.Dunham@arm.com}
81710037SARM gem5 Developers
81810037SARM gem5 Developersvoid
81910037SARM gem5 DevelopersSimpleDRAM::reorderQueue(std::deque<DRAMPacket*>& queue)
82010037SARM gem5 Developers{
82110037SARM gem5 Developers    // Only determine this when needed
82210037SARM gem5 Developers    uint64_t earliest_banks = 0;
82310474Sandreas.hansson@arm.com
82410474Sandreas.hansson@arm.com    // Search for row hits first, if no row hit is found then schedule the
82510474Sandreas.hansson@arm.com    // packet to one of the earliest banks available
82610474Sandreas.hansson@arm.com    bool found_earliest_pkt = false;
82710037SARM gem5 Developers    auto selected_pkt_it = queue.begin();
82810474Sandreas.hansson@arm.com
82910474Sandreas.hansson@arm.com    for (auto i = queue.begin(); i != queue.end() ; ++i) {
83010474Sandreas.hansson@arm.com        DRAMPacket* dram_pkt = *i;
83110474Sandreas.hansson@arm.com        const Bank& bank = dram_pkt->bankRef;
83210474Sandreas.hansson@arm.com        // Check if it is a row hit
83310474Sandreas.hansson@arm.com        if (bank.openRow == dram_pkt->row) {
83410037SARM gem5 Developers            DPRINTF(DRAM, "Row buffer hit\n");
83510037SARM gem5 Developers            selected_pkt_it = i;
83610037SARM gem5 Developers            break;
83710037SARM gem5 Developers        } else if (!found_earliest_pkt) {
83810037SARM gem5 Developers            // No row hit, go for first ready
83910037SARM gem5 Developers            if (earliest_banks == 0)
84010037SARM gem5 Developers                earliest_banks = minBankFreeAt(queue);
84110037SARM gem5 Developers
84210037SARM gem5 Developers            // Bank is ready or is the first available bank
84310037SARM gem5 Developers            if (bank.freeAt <= curTick() ||
84410037SARM gem5 Developers                bits(earliest_banks, dram_pkt->bankId, dram_pkt->bankId)) {
84510037SARM gem5 Developers                // Remember the packet to be scheduled to one of the earliest
84610037SARM gem5 Developers                // banks available
84710324SCurtis.Dunham@arm.com                selected_pkt_it = i;
84810324SCurtis.Dunham@arm.com                found_earliest_pkt = true;
84910324SCurtis.Dunham@arm.com            }
85010324SCurtis.Dunham@arm.com        }
85110324SCurtis.Dunham@arm.com    }
85210324SCurtis.Dunham@arm.com
85310037SARM gem5 Developers    DRAMPacket* selected_pkt = *selected_pkt_it;
85410324SCurtis.Dunham@arm.com    queue.erase(selected_pkt_it);
85510324SCurtis.Dunham@arm.com    queue.push_front(selected_pkt);
85610324SCurtis.Dunham@arm.com}
85710324SCurtis.Dunham@arm.com
85810324SCurtis.Dunham@arm.comvoid
85911575SDylan.Johnson@ARM.comSimpleDRAM::accessAndRespond(PacketPtr pkt, Tick static_latency)
86010324SCurtis.Dunham@arm.com{
86110324SCurtis.Dunham@arm.com    DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr());
86210324SCurtis.Dunham@arm.com
86310324SCurtis.Dunham@arm.com    bool needsResponse = pkt->needsResponse();
86410324SCurtis.Dunham@arm.com    // do the actual memory access which also turns the packet into a
86510324SCurtis.Dunham@arm.com    // response
86610324SCurtis.Dunham@arm.com    access(pkt);
86710324SCurtis.Dunham@arm.com
86810324SCurtis.Dunham@arm.com    // turn packet around to go back to requester if response expected
86910324SCurtis.Dunham@arm.com    if (needsResponse) {
87010324SCurtis.Dunham@arm.com        // access already turned the packet into a response
87110324SCurtis.Dunham@arm.com        assert(pkt->isResponse());
87210324SCurtis.Dunham@arm.com
87310324SCurtis.Dunham@arm.com        // @todo someone should pay for this
87410324SCurtis.Dunham@arm.com        pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
87510324SCurtis.Dunham@arm.com
87610324SCurtis.Dunham@arm.com        // queue the packet in the response queue to be sent out after
87710324SCurtis.Dunham@arm.com        // the static latency has passed
87810324SCurtis.Dunham@arm.com        port.schedTimingResp(pkt, curTick() + static_latency);
87910324SCurtis.Dunham@arm.com    } else {
88010324SCurtis.Dunham@arm.com        // @todo the packet is going to be deleted, and the DRAMPacket
88110324SCurtis.Dunham@arm.com        // is still having a pointer to it
88210324SCurtis.Dunham@arm.com        pendingDelete.push_back(pkt);
88310324SCurtis.Dunham@arm.com    }
88410324SCurtis.Dunham@arm.com
88510324SCurtis.Dunham@arm.com    DPRINTF(DRAM, "Done\n");
88610324SCurtis.Dunham@arm.com
88710324SCurtis.Dunham@arm.com    return;
88810037SARM gem5 Developers}
88910037SARM gem5 Developers
89011575SDylan.Johnson@ARM.compair<Tick, Tick>
89111575SDylan.Johnson@ARM.comSimpleDRAM::estimateLatency(DRAMPacket* dram_pkt, Tick inTime)
89210037SARM gem5 Developers{
89310324SCurtis.Dunham@arm.com    // If a request reaches a bank at tick 'inTime', how much time
89410037SARM gem5 Developers    // *after* that does it take to finish the request, depending
89510037SARM gem5 Developers    // on bank status and page open policy. Note that this method
89610037SARM gem5 Developers    // considers only the time taken for the actual read or write
89710037SARM gem5 Developers    // to complete, NOT any additional time thereafter for tRAS or
89810037SARM gem5 Developers    // tRP.
89910037SARM gem5 Developers    Tick accLat = 0;
90010037SARM gem5 Developers    Tick bankLat = 0;
90110037SARM gem5 Developers    rowHitFlag = false;
90210037SARM gem5 Developers    Tick potentialActTick;
90310037SARM gem5 Developers
90410037SARM gem5 Developers    const Bank& bank = dram_pkt->bankRef;
90510037SARM gem5 Developers     // open-page policy
90610037SARM gem5 Developers    if (pageMgmt == Enums::open || pageMgmt == Enums::open_adaptive) {
90710037SARM gem5 Developers        if (bank.openRow == dram_pkt->row) {
90810474Sandreas.hansson@arm.com            // When we have a row-buffer hit,
90910474Sandreas.hansson@arm.com            // we don't care about tRAS having expired or not,
91010474Sandreas.hansson@arm.com            // but do care about bank being free for access
91110474Sandreas.hansson@arm.com            rowHitFlag = true;
91210474Sandreas.hansson@arm.com
91310037SARM gem5 Developers            // When a series of requests arrive to the same row,
91410474Sandreas.hansson@arm.com            // DDR systems are capable of streaming data continuously
91510474Sandreas.hansson@arm.com            // at maximum bandwidth (subject to tCCD). Here, we approximate
91610474Sandreas.hansson@arm.com            // this condition, and assume that if whenever a bank is already
91710474Sandreas.hansson@arm.com            // busy and a new request comes in, it can be completed with no
91810474Sandreas.hansson@arm.com            // penalty beyond waiting for the existing read to complete.
91910474Sandreas.hansson@arm.com            if (bank.freeAt > inTime) {
92010474Sandreas.hansson@arm.com                accLat += bank.freeAt - inTime;
92110037SARM gem5 Developers                bankLat += 0;
92210037SARM gem5 Developers            } else {
92310037SARM gem5 Developers               // CAS latency only
92410037SARM gem5 Developers               accLat += tCL;
92510037SARM gem5 Developers               bankLat += tCL;
92610037SARM gem5 Developers            }
92710037SARM gem5 Developers
92810037SARM gem5 Developers        } else {
92910037SARM gem5 Developers            // Row-buffer miss, need to close existing row
93010037SARM gem5 Developers            // once tRAS has expired, then open the new one,
93110037SARM gem5 Developers            // then add cas latency.
93210037SARM gem5 Developers            Tick freeTime = std::max(bank.tRASDoneAt, bank.freeAt);
93310037SARM gem5 Developers
93410037SARM gem5 Developers            if (freeTime > inTime)
93510037SARM gem5 Developers               accLat += freeTime - inTime;
93610037SARM gem5 Developers
93710037SARM gem5 Developers            // If the there is no open row (open adaptive), then there
93810324SCurtis.Dunham@arm.com            // is no precharge delay, otherwise go with tRP
93910037SARM gem5 Developers            Tick precharge_delay = bank.openRow == -1 ? 0 : tRP;
94010037SARM gem5 Developers
94111395Sandreas.sandberg@arm.com            //The bank is free, and you may be able to activate
94211395Sandreas.sandberg@arm.com            potentialActTick = inTime + accLat + precharge_delay;
94310037SARM gem5 Developers            if (potentialActTick < bank.actAllowedAt)
94410037SARM gem5 Developers                accLat += bank.actAllowedAt - potentialActTick;
94510037SARM gem5 Developers
94610037SARM gem5 Developers            accLat += precharge_delay + tRCD + tCL;
94710037SARM gem5 Developers            bankLat += precharge_delay + tRCD + tCL;
94810037SARM gem5 Developers        }
94910037SARM gem5 Developers    } else if (pageMgmt == Enums::close) {
95010037SARM gem5 Developers        // With a close page policy, no notion of
95110037SARM gem5 Developers        // bank.tRASDoneAt
95210037SARM gem5 Developers        if (bank.freeAt > inTime)
95310037SARM gem5 Developers            accLat += bank.freeAt - inTime;
95410037SARM gem5 Developers
95510037SARM gem5 Developers        //The bank is free, and you may be able to activate
95610836Sandreas.hansson@arm.com        potentialActTick = inTime + accLat;
95710037SARM gem5 Developers        if (potentialActTick < bank.actAllowedAt)
95810836Sandreas.hansson@arm.com            accLat += bank.actAllowedAt - potentialActTick;
95910037SARM gem5 Developers
96010037SARM gem5 Developers        // page already closed, simply open the row, and
96111181Snathananel.premillieu@arm.com        // add cas latency
96211181Snathananel.premillieu@arm.com        accLat += tRCD + tCL;
96311181Snathananel.premillieu@arm.com        bankLat += tRCD + tCL;
96411181Snathananel.premillieu@arm.com    } else
96510037SARM gem5 Developers        panic("No page management policy chosen\n");
96610037SARM gem5 Developers
96710324SCurtis.Dunham@arm.com    DPRINTF(DRAM, "Returning < %lld, %lld > from estimateLatency()\n",
96810037SARM gem5 Developers            bankLat, accLat);
9697439Sdam.sunwoo@arm.com
97010037SARM gem5 Developers    return make_pair(bankLat, accLat);
97110037SARM gem5 Developers}
97210037SARM gem5 Developers
97310037SARM gem5 Developersvoid
97410037SARM gem5 DevelopersSimpleDRAM::processNextReqEvent()
97510037SARM gem5 Developers{
97610037SARM gem5 Developers    scheduleNextReq();
97710037SARM gem5 Developers}
97810037SARM gem5 Developers
97910037SARM gem5 Developersvoid
98010037SARM gem5 DevelopersSimpleDRAM::recordActivate(Tick act_tick, uint8_t rank, uint8_t bank)
98110037SARM gem5 Developers{
98210037SARM gem5 Developers    assert(0 <= rank && rank < ranksPerChannel);
98310037SARM gem5 Developers    assert(actTicks[rank].size() == activationLimit);
98410037SARM gem5 Developers
98510037SARM gem5 Developers    DPRINTF(DRAM, "Activate at tick %d\n", act_tick);
98610037SARM gem5 Developers
98710037SARM gem5 Developers    // Tracking accesses after all banks are precharged.
98810717Sandreas.hansson@arm.com    // startTickPrechargeAll: is the tick when all the banks were again
98910621SCurtis.Dunham@arm.com    // precharged. The difference between act_tick and startTickPrechargeAll
9909180Sandreas.hansson@arm.com    // gives the time for which DRAM doesn't get any accesses after refreshing
99110037SARM gem5 Developers    // or after a page is closed in closed-page or open-adaptive-page policy.
99210037SARM gem5 Developers    if ((numBanksActive == 0) && (act_tick > startTickPrechargeAll)) {
99310037SARM gem5 Developers        prechargeAllTime += act_tick - startTickPrechargeAll;
99410037SARM gem5 Developers    }
9957439Sdam.sunwoo@arm.com
99611579SDylan.Johnson@ARM.com    // No need to update number of active banks for closed-page policy as only 1
99711575SDylan.Johnson@ARM.com    // bank will be activated at any given point, which will be instatntly
99811575SDylan.Johnson@ARM.com    // precharged
99911575SDylan.Johnson@ARM.com    if (pageMgmt == Enums::open || pageMgmt == Enums::open_adaptive)
10007439Sdam.sunwoo@arm.com        ++numBanksActive;
10017404SAli.Saidi@ARM.com
10027404SAli.Saidi@ARM.com    // start by enforcing tRRD
10037439Sdam.sunwoo@arm.com    for(int i = 0; i < banksPerRank; i++) {
10047404SAli.Saidi@ARM.com        // next activate must not happen before tRRD
10057404SAli.Saidi@ARM.com        banks[rank][i].actAllowedAt = act_tick + tRRD;
10067404SAli.Saidi@ARM.com    }
10077439Sdam.sunwoo@arm.com    // tRC should be added to activation tick of the bank currently accessed,
10087439Sdam.sunwoo@arm.com    // where tRC = tRAS + tRP, this is just for a check as actAllowedAt for same
10097404SAli.Saidi@ARM.com    // bank is already captured by bank.freeAt and bank.tRASDoneAt
10107439Sdam.sunwoo@arm.com    banks[rank][bank].actAllowedAt = act_tick + tRAS + tRP;
10117439Sdam.sunwoo@arm.com
10127436Sdam.sunwoo@arm.com    // next, we deal with tXAW, if the activation limit is disabled
10137436Sdam.sunwoo@arm.com    // then we are done
10147582SAli.Saidi@arm.com    if (actTicks[rank].empty())
101510037SARM gem5 Developers        return;
10167439Sdam.sunwoo@arm.com
10177404SAli.Saidi@ARM.com    // sanity check
10187436Sdam.sunwoo@arm.com    if (actTicks[rank].back() && (act_tick - actTicks[rank].back()) < tXAW) {
10197404SAli.Saidi@ARM.com        // @todo For now, stick with a warning
102010037SARM gem5 Developers        warn("Got %d activates in window %d (%d - %d) which is smaller "
10217436Sdam.sunwoo@arm.com             "than %d\n", activationLimit, act_tick - actTicks[rank].back(),
10227436Sdam.sunwoo@arm.com             act_tick, actTicks[rank].back(), tXAW);
10237436Sdam.sunwoo@arm.com    }
10247404SAli.Saidi@ARM.com
10257436Sdam.sunwoo@arm.com    // shift the times used for the book keeping, the last element
10267436Sdam.sunwoo@arm.com    // (highest index) is the oldest one and hence the lowest value
102710037SARM gem5 Developers    actTicks[rank].pop_back();
10287436Sdam.sunwoo@arm.com
10297436Sdam.sunwoo@arm.com    // record an new activation (in the future)
10307436Sdam.sunwoo@arm.com    actTicks[rank].push_front(act_tick);
10317436Sdam.sunwoo@arm.com
10327436Sdam.sunwoo@arm.com    // cannot activate more than X times in time window tXAW, push the
103310037SARM gem5 Developers    // next one (the X + 1'st activate) to be tXAW away from the
10347436Sdam.sunwoo@arm.com    // oldest in our window of X
10357436Sdam.sunwoo@arm.com    if (actTicks[rank].back() && (act_tick - actTicks[rank].back()) < tXAW) {
10367436Sdam.sunwoo@arm.com        DPRINTF(DRAM, "Enforcing tXAW with X = %d, next activate no earlier "
10377436Sdam.sunwoo@arm.com                "than %d\n", activationLimit, actTicks[rank].back() + tXAW);
10387436Sdam.sunwoo@arm.com            for(int j = 0; j < banksPerRank; j++)
103910037SARM gem5 Developers                // next activate must not happen before end of window
10407436Sdam.sunwoo@arm.com                banks[rank][j].actAllowedAt = actTicks[rank].back() + tXAW;
10417436Sdam.sunwoo@arm.com    }
10427436Sdam.sunwoo@arm.com}
10437436Sdam.sunwoo@arm.com
10447436Sdam.sunwoo@arm.comvoid
10457436Sdam.sunwoo@arm.comSimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
104610037SARM gem5 Developers{
10477436Sdam.sunwoo@arm.com
10487436Sdam.sunwoo@arm.com    DPRINTF(DRAM, "Timing access to addr %lld, rank/bank/row %d %d %d\n",
10497436Sdam.sunwoo@arm.com            dram_pkt->addr, dram_pkt->rank, dram_pkt->bank, dram_pkt->row);
10507436Sdam.sunwoo@arm.com
10517436Sdam.sunwoo@arm.com    // estimate the bank and access latency
10527439Sdam.sunwoo@arm.com    pair<Tick, Tick> lat = estimateLatency(dram_pkt, curTick());
10537436Sdam.sunwoo@arm.com    Tick bankLat = lat.first;
10547436Sdam.sunwoo@arm.com    Tick accessLat = lat.second;
10557439Sdam.sunwoo@arm.com    Tick actTick;
10567436Sdam.sunwoo@arm.com
10577436Sdam.sunwoo@arm.com    // This request was woken up at this time based on a prior call
105810037SARM gem5 Developers    // to estimateLatency(). However, between then and now, both the
10597436Sdam.sunwoo@arm.com    // accessLatency and/or busBusyUntil may have changed. We need
10607436Sdam.sunwoo@arm.com    // to correct for that.
10617436Sdam.sunwoo@arm.com
10627436Sdam.sunwoo@arm.com    Tick addDelay = (curTick() + accessLat < busBusyUntil) ?
10637436Sdam.sunwoo@arm.com        busBusyUntil - (curTick() + accessLat) : 0;
10647436Sdam.sunwoo@arm.com
106510037SARM gem5 Developers    Bank& bank = dram_pkt->bankRef;
10667436Sdam.sunwoo@arm.com
10677436Sdam.sunwoo@arm.com    // Update bank state
10687436Sdam.sunwoo@arm.com    if (pageMgmt == Enums::open || pageMgmt == Enums::open_adaptive) {
10697436Sdam.sunwoo@arm.com        bank.freeAt = curTick() + addDelay + accessLat;
10707436Sdam.sunwoo@arm.com
10717439Sdam.sunwoo@arm.com        // If you activated a new row do to this access, the next access
10727436Sdam.sunwoo@arm.com        // will have to respect tRAS for this bank.
10737436Sdam.sunwoo@arm.com        if (!rowHitFlag) {
107410037SARM gem5 Developers            // any waiting for banks account for in freeAt
10757436Sdam.sunwoo@arm.com            actTick = bank.freeAt - tCL - tRCD;
10767404SAli.Saidi@ARM.com            bank.tRASDoneAt = actTick + tRAS;
10777404SAli.Saidi@ARM.com            recordActivate(actTick, dram_pkt->rank, dram_pkt->bank);
10787436Sdam.sunwoo@arm.com
10797436Sdam.sunwoo@arm.com            // if we closed an open row as a result of this access,
10807404SAli.Saidi@ARM.com            // then sample the number of bytes accessed before
10817436Sdam.sunwoo@arm.com            // resetting it
10827436Sdam.sunwoo@arm.com            if (bank.openRow != -1)
10837404SAli.Saidi@ARM.com                bytesPerActivate.sample(bank.bytesAccessed);
10847404SAli.Saidi@ARM.com
10857438SAli.Saidi@ARM.com            // update the open row
108610037SARM gem5 Developers            bank.openRow = dram_pkt->row;
108710037SARM gem5 Developers
108810037SARM gem5 Developers            // start counting anew, this covers both the case when we
108910037SARM gem5 Developers            // auto-precharged, and when this access is forced to
10907436Sdam.sunwoo@arm.com            // precharge
10917582SAli.Saidi@arm.com            bank.bytesAccessed = 0;
10927404SAli.Saidi@ARM.com            bank.rowAccesses = 0;
10937404SAli.Saidi@ARM.com        }
10947436Sdam.sunwoo@arm.com
10957436Sdam.sunwoo@arm.com        // increment the bytes accessed and the accesses per row
10967436Sdam.sunwoo@arm.com        bank.bytesAccessed += burstSize;
109710037SARM gem5 Developers        ++bank.rowAccesses;
10987404SAli.Saidi@ARM.com
10997404SAli.Saidi@ARM.com        // if we reached the max, then issue with an auto-precharge
11007436Sdam.sunwoo@arm.com        bool auto_precharge = bank.rowAccesses == maxAccessesPerRow;
11017436Sdam.sunwoo@arm.com
11027436Sdam.sunwoo@arm.com        // if we did not hit the limit, we might still want to
110310037SARM gem5 Developers        // auto-precharge
11047404SAli.Saidi@ARM.com        if (!auto_precharge && pageMgmt == Enums::open_adaptive) {
11057404SAli.Saidi@ARM.com            // a twist on the open page policy is to not blindly keep the
11067436Sdam.sunwoo@arm.com            // page open, but close it if there are no row hits, and there
11077436Sdam.sunwoo@arm.com            // are bank conflicts in the queue
11087436Sdam.sunwoo@arm.com            bool got_more_hits = false;
110910037SARM gem5 Developers            bool got_bank_conflict = false;
11107404SAli.Saidi@ARM.com
11117404SAli.Saidi@ARM.com            // either look at the read queue or write queue
11127436Sdam.sunwoo@arm.com            const deque<DRAMPacket*>& queue = dram_pkt->isRead ? readQueue :
11137436Sdam.sunwoo@arm.com                writeQueue;
11147436Sdam.sunwoo@arm.com            auto p = queue.begin();
111510037SARM gem5 Developers            // make sure we are not considering the packet that we are
11167404SAli.Saidi@ARM.com            // currently dealing with (which is the head of the queue)
11177404SAli.Saidi@ARM.com            ++p;
11187436Sdam.sunwoo@arm.com
11197436Sdam.sunwoo@arm.com            // keep on looking until we have found both or reached
11207436Sdam.sunwoo@arm.com            // the end
112110037SARM gem5 Developers            while (!(got_more_hits && got_bank_conflict) &&
11227404SAli.Saidi@ARM.com                   p != queue.end()) {
11237404SAli.Saidi@ARM.com                bool same_rank_bank = (dram_pkt->rank == (*p)->rank) &&
11247436Sdam.sunwoo@arm.com                    (dram_pkt->bank == (*p)->bank);
11257436Sdam.sunwoo@arm.com                bool same_row = dram_pkt->row == (*p)->row;
11267436Sdam.sunwoo@arm.com                got_more_hits |= same_rank_bank && same_row;
112710037SARM gem5 Developers                got_bank_conflict |= same_rank_bank && !same_row;
11287404SAli.Saidi@ARM.com                ++p;
11297404SAli.Saidi@ARM.com            }
11307404SAli.Saidi@ARM.com
11317404SAli.Saidi@ARM.com            // auto pre-charge if we have not got any more hits, and
11327436Sdam.sunwoo@arm.com            // have a bank conflict
11337436Sdam.sunwoo@arm.com            auto_precharge = !got_more_hits && got_bank_conflict;
11347436Sdam.sunwoo@arm.com        }
113510037SARM gem5 Developers
11367404SAli.Saidi@ARM.com        // if this access should use auto-precharge, then we are
11377404SAli.Saidi@ARM.com        // closing the row
11387436Sdam.sunwoo@arm.com        if (auto_precharge) {
11397436Sdam.sunwoo@arm.com            bank.openRow = -1;
11407436Sdam.sunwoo@arm.com            bank.freeAt = std::max(bank.freeAt, bank.tRASDoneAt) + tRP;
11417436Sdam.sunwoo@arm.com            --numBanksActive;
114210037SARM gem5 Developers            if (numBanksActive == 0) {
11437436Sdam.sunwoo@arm.com                startTickPrechargeAll = std::max(startTickPrechargeAll,
11447436Sdam.sunwoo@arm.com                                                 bank.freeAt);
11457436Sdam.sunwoo@arm.com                DPRINTF(DRAM, "All banks precharged at tick: %ld\n",
11467436Sdam.sunwoo@arm.com                        startTickPrechargeAll);
11477436Sdam.sunwoo@arm.com            }
11487436Sdam.sunwoo@arm.com
11497436Sdam.sunwoo@arm.com            // sample the bytes per activate here since we are closing
11507436Sdam.sunwoo@arm.com            // the page
115110037SARM gem5 Developers            bytesPerActivate.sample(bank.bytesAccessed);
11527436Sdam.sunwoo@arm.com
11537436Sdam.sunwoo@arm.com            DPRINTF(DRAM, "Auto-precharged bank: %d\n", dram_pkt->bankId);
11547436Sdam.sunwoo@arm.com        }
11557436Sdam.sunwoo@arm.com
11567436Sdam.sunwoo@arm.com        DPRINTF(DRAM, "doDRAMAccess::bank.freeAt is %lld\n", bank.freeAt);
11577436Sdam.sunwoo@arm.com    } else if (pageMgmt == Enums::close) {
11587436Sdam.sunwoo@arm.com        actTick = curTick() + addDelay + accessLat - tRCD - tCL;
11597436Sdam.sunwoo@arm.com        recordActivate(actTick, dram_pkt->rank, dram_pkt->bank);
11607436Sdam.sunwoo@arm.com
11617436Sdam.sunwoo@arm.com        // If the DRAM has a very quick tRAS, bank can be made free
11627436Sdam.sunwoo@arm.com        // after consecutive tCL,tRCD,tRP times. In general, however,
116310037SARM gem5 Developers        // an additional wait is required to respect tRAS.
11647436Sdam.sunwoo@arm.com        bank.freeAt = std::max(actTick + tRAS + tRP,
11657436Sdam.sunwoo@arm.com                actTick + tRCD + tCL + tRP);
11667436Sdam.sunwoo@arm.com        DPRINTF(DRAM, "doDRAMAccess::bank.freeAt is %lld\n", bank.freeAt);
11677436Sdam.sunwoo@arm.com        bytesPerActivate.sample(burstSize);
11687436Sdam.sunwoo@arm.com        startTickPrechargeAll = std::max(startTickPrechargeAll, bank.freeAt);
11697436Sdam.sunwoo@arm.com    } else
11707436Sdam.sunwoo@arm.com        panic("No page management policy chosen\n");
11717436Sdam.sunwoo@arm.com
11727436Sdam.sunwoo@arm.com    // Update request parameters
117310037SARM gem5 Developers    dram_pkt->readyTime = curTick() + addDelay + accessLat + tBURST;
11747436Sdam.sunwoo@arm.com
11757436Sdam.sunwoo@arm.com
11767436Sdam.sunwoo@arm.com    DPRINTF(DRAM, "Req %lld: curtick is %lld accessLat is %d " \
11777436Sdam.sunwoo@arm.com                  "readytime is %lld busbusyuntil is %lld. " \
11787436Sdam.sunwoo@arm.com                  "Scheduling at readyTime\n", dram_pkt->addr,
11797436Sdam.sunwoo@arm.com                   curTick(), accessLat, dram_pkt->readyTime, busBusyUntil);
11807436Sdam.sunwoo@arm.com
11817436Sdam.sunwoo@arm.com    // Make sure requests are not overlapping on the databus
11827436Sdam.sunwoo@arm.com    assert (dram_pkt->readyTime - busBusyUntil >= tBURST);
11837436Sdam.sunwoo@arm.com
11847436Sdam.sunwoo@arm.com    // Update bus state
11857436Sdam.sunwoo@arm.com    busBusyUntil = dram_pkt->readyTime;
11867436Sdam.sunwoo@arm.com
11877436Sdam.sunwoo@arm.com    DPRINTF(DRAM,"Access time is %lld\n",
11887436Sdam.sunwoo@arm.com            dram_pkt->readyTime - dram_pkt->entryTime);
11897436Sdam.sunwoo@arm.com
11907436Sdam.sunwoo@arm.com    // Update the minimum timing between the requests
11917436Sdam.sunwoo@arm.com    newTime = (busBusyUntil > tRP + tRCD + tCL) ?
11927436Sdam.sunwoo@arm.com        std::max(busBusyUntil - (tRP + tRCD + tCL), curTick()) : curTick();
11937436Sdam.sunwoo@arm.com
11947436Sdam.sunwoo@arm.com    // Update the access related stats
11957436Sdam.sunwoo@arm.com    if (dram_pkt->isRead) {
11967436Sdam.sunwoo@arm.com        if (rowHitFlag)
11977436Sdam.sunwoo@arm.com            readRowHits++;
11987436Sdam.sunwoo@arm.com        bytesReadDRAM += burstSize;
11997436Sdam.sunwoo@arm.com        perBankRdBursts[dram_pkt->bankId]++;
12007436Sdam.sunwoo@arm.com    } else {
12017436Sdam.sunwoo@arm.com        if (rowHitFlag)
12027436Sdam.sunwoo@arm.com            writeRowHits++;
12037436Sdam.sunwoo@arm.com        bytesWritten += burstSize;
12047436Sdam.sunwoo@arm.com        perBankWrBursts[dram_pkt->bankId]++;
12057436Sdam.sunwoo@arm.com
12067404SAli.Saidi@ARM.com        // At this point, commonality between reads and writes ends.
120710367SAndrew.Bardsley@arm.com        // For writes, we are done since we long ago responded to the
120810367SAndrew.Bardsley@arm.com        // requestor.
12097439Sdam.sunwoo@arm.com        return;
121010037SARM gem5 Developers    }
121110037SARM gem5 Developers
12127436Sdam.sunwoo@arm.com    // Update latency stats
121310037SARM gem5 Developers    totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime;
121410037SARM gem5 Developers    totBankLat += bankLat;
121510037SARM gem5 Developers    totBusLat += tBURST;
121610037SARM gem5 Developers    totQLat += dram_pkt->readyTime - dram_pkt->entryTime - bankLat - tBURST;
121710037SARM gem5 Developers
12187436Sdam.sunwoo@arm.com
121910037SARM gem5 Developers    // At this point we're done dealing with the request
122010037SARM gem5 Developers    // It will be moved to a separate response queue with a
122110037SARM gem5 Developers    // correct readyTime, and eventually be sent back at that
122210037SARM gem5 Developers    //time
122310037SARM gem5 Developers    moveToRespQ();
122410037SARM gem5 Developers
122510037SARM gem5 Developers    // Schedule the next read event
122610037SARM gem5 Developers    if (!nextReqEvent.scheduled() && !stopReads){
12277436Sdam.sunwoo@arm.com        schedule(nextReqEvent, newTime);
122810037SARM gem5 Developers    } else {
122910037SARM gem5 Developers        if (newTime < nextReqEvent.when())
123010037SARM gem5 Developers            reschedule(nextReqEvent, newTime);
123110037SARM gem5 Developers    }
123210037SARM gem5 Developers}
123310037SARM gem5 Developers
123410037SARM gem5 Developersvoid
123510037SARM gem5 DevelopersSimpleDRAM::moveToRespQ()
123610037SARM gem5 Developers{
123710037SARM gem5 Developers    // Remove from read queue
123810037SARM gem5 Developers    DRAMPacket* dram_pkt = readQueue.front();
123910037SARM gem5 Developers    readQueue.pop_front();
124010037SARM gem5 Developers
124110037SARM gem5 Developers    // sanity check
124210037SARM gem5 Developers    assert(dram_pkt->size <= burstSize);
124310037SARM gem5 Developers
124410037SARM gem5 Developers    // Insert into response queue sorted by readyTime
124510037SARM gem5 Developers    // It will be sent back to the requestor at its
124610037SARM gem5 Developers    // readyTime
124710037SARM gem5 Developers    if (respQueue.empty()) {
124810037SARM gem5 Developers        respQueue.push_front(dram_pkt);
124910421Sandreas.hansson@arm.com        assert(!respondEvent.scheduled());
125010421Sandreas.hansson@arm.com        assert(dram_pkt->readyTime >= curTick());
125110421Sandreas.hansson@arm.com        schedule(respondEvent, dram_pkt->readyTime);
125210421Sandreas.hansson@arm.com    } else {
125310037SARM gem5 Developers        bool done = false;
125410037SARM gem5 Developers        auto i = respQueue.begin();
125510037SARM gem5 Developers        while (!done && i != respQueue.end()) {
125610037SARM gem5 Developers            if ((*i)->readyTime > dram_pkt->readyTime) {
125710037SARM gem5 Developers                respQueue.insert(i, dram_pkt);
125810037SARM gem5 Developers                done = true;
125910037SARM gem5 Developers            }
126010037SARM gem5 Developers            ++i;
126110037SARM gem5 Developers        }
126210037SARM gem5 Developers
126310037SARM gem5 Developers        if (!done)
126410037SARM gem5 Developers            respQueue.push_back(dram_pkt);
126510037SARM gem5 Developers
126610037SARM gem5 Developers        assert(respondEvent.scheduled());
126710037SARM gem5 Developers
126810037SARM gem5 Developers        if (respQueue.front()->readyTime < respondEvent.when()) {
126910037SARM gem5 Developers            assert(respQueue.front()->readyTime >= curTick());
127010037SARM gem5 Developers            reschedule(respondEvent, respQueue.front()->readyTime);
127110037SARM gem5 Developers        }
127210037SARM gem5 Developers    }
127310037SARM gem5 Developers}
127410037SARM gem5 Developers
127510037SARM gem5 Developersvoid
127610037SARM gem5 DevelopersSimpleDRAM::scheduleNextReq()
127710037SARM gem5 Developers{
127810037SARM gem5 Developers    DPRINTF(DRAM, "Reached scheduleNextReq()\n");
127910037SARM gem5 Developers
128010037SARM gem5 Developers    // Figure out which read request goes next, and move it to the
128110037SARM gem5 Developers    // front of the read queue
128210037SARM gem5 Developers    if (!chooseNextRead()) {
128310037SARM gem5 Developers        // In the case there is no read request to go next, trigger
128410037SARM gem5 Developers        // writes if we have passed the low threshold (or if we are
128510037SARM gem5 Developers        // draining)
128610037SARM gem5 Developers        if (!writeQueue.empty() && !writeEvent.scheduled() &&
128710037SARM gem5 Developers            (writeQueue.size() > writeLowThreshold || drainManager))
128810037SARM gem5 Developers            triggerWrites();
128910037SARM gem5 Developers    } else {
129010037SARM gem5 Developers        doDRAMAccess(readQueue.front());
129110037SARM gem5 Developers    }
129210037SARM gem5 Developers}
129310037SARM gem5 Developers
129410037SARM gem5 DevelopersTick
129510037SARM gem5 DevelopersSimpleDRAM::maxBankFreeAt() const
129610037SARM gem5 Developers{
129710037SARM gem5 Developers    Tick banksFree = 0;
129810037SARM gem5 Developers
129910037SARM gem5 Developers    for(int i = 0; i < ranksPerChannel; i++)
130010037SARM gem5 Developers        for(int j = 0; j < banksPerRank; j++)
130110037SARM gem5 Developers            banksFree = std::max(banks[i][j].freeAt, banksFree);
130210037SARM gem5 Developers
130310037SARM gem5 Developers    return banksFree;
130410037SARM gem5 Developers}
130510037SARM gem5 Developers
130610037SARM gem5 Developersuint64_t
130710037SARM gem5 DevelopersSimpleDRAM::minBankFreeAt(const deque<DRAMPacket*>& queue) const
130810037SARM gem5 Developers{
130910037SARM gem5 Developers    uint64_t bank_mask = 0;
131010037SARM gem5 Developers    Tick freeAt = MaxTick;
131110037SARM gem5 Developers
131210037SARM gem5 Developers    // detemrine if we have queued transactions targetting the
131310037SARM gem5 Developers    // bank in question
131410037SARM gem5 Developers    vector<bool> got_waiting(ranksPerChannel * banksPerRank, false);
131510037SARM gem5 Developers    for (auto p = queue.begin(); p != queue.end(); ++p) {
131610037SARM gem5 Developers        got_waiting[(*p)->bankId] = true;
131710037SARM gem5 Developers    }
131810037SARM gem5 Developers
131910037SARM gem5 Developers    for (int i = 0; i < ranksPerChannel; i++) {
132010037SARM gem5 Developers        for (int j = 0; j < banksPerRank; j++) {
132110037SARM gem5 Developers            // if we have waiting requests for the bank, and it is
132210037SARM gem5 Developers            // amongst the first available, update the mask
132310037SARM gem5 Developers            if (got_waiting[i * banksPerRank + j] &&
132410037SARM gem5 Developers                banks[i][j].freeAt <= freeAt) {
132510037SARM gem5 Developers                // reset bank mask if new minimum is found
132610037SARM gem5 Developers                if (banks[i][j].freeAt < freeAt)
132710037SARM gem5 Developers                    bank_mask = 0;
132810037SARM gem5 Developers                // set the bit corresponding to the available bank
132910037SARM gem5 Developers                uint8_t bit_index = i * ranksPerChannel + j;
133010037SARM gem5 Developers                replaceBits(bank_mask, bit_index, bit_index, 1);
133110037SARM gem5 Developers                freeAt = banks[i][j].freeAt;
133210037SARM gem5 Developers            }
133310037SARM gem5 Developers        }
133410037SARM gem5 Developers    }
133510037SARM gem5 Developers    return bank_mask;
133610037SARM gem5 Developers}
133710037SARM gem5 Developers
133810037SARM gem5 Developersvoid
133910037SARM gem5 DevelopersSimpleDRAM::processRefreshEvent()
134011583SDylan.Johnson@ARM.com{
134111583SDylan.Johnson@ARM.com    DPRINTF(DRAM, "Refreshing at tick %ld\n", curTick());
134210037SARM gem5 Developers
134311583SDylan.Johnson@ARM.com    Tick banksFree = std::max(curTick(), maxBankFreeAt()) + tRFC;
134411583SDylan.Johnson@ARM.com
134511583SDylan.Johnson@ARM.com    for(int i = 0; i < ranksPerChannel; i++)
134611583SDylan.Johnson@ARM.com        for(int j = 0; j < banksPerRank; j++) {
134710037SARM gem5 Developers            banks[i][j].freeAt = banksFree;
134811583SDylan.Johnson@ARM.com            banks[i][j].openRow = -1;
134911583SDylan.Johnson@ARM.com        }
135011583SDylan.Johnson@ARM.com
135111583SDylan.Johnson@ARM.com    // updating startTickPrechargeAll, isprechargeAll
135211583SDylan.Johnson@ARM.com    numBanksActive = 0;
135311583SDylan.Johnson@ARM.com    startTickPrechargeAll = banksFree;
135411583SDylan.Johnson@ARM.com
135511583SDylan.Johnson@ARM.com    schedule(refreshEvent, curTick() + tREFI);
135611583SDylan.Johnson@ARM.com}
135711583SDylan.Johnson@ARM.com
135811583SDylan.Johnson@ARM.comvoid
135911583SDylan.Johnson@ARM.comSimpleDRAM::regStats()
136011583SDylan.Johnson@ARM.com{
136111583SDylan.Johnson@ARM.com    using namespace Stats;
136211583SDylan.Johnson@ARM.com
136311583SDylan.Johnson@ARM.com    AbstractMemory::regStats();
136411583SDylan.Johnson@ARM.com
136511583SDylan.Johnson@ARM.com    readReqs
136611583SDylan.Johnson@ARM.com        .name(name() + ".readReqs")
136711583SDylan.Johnson@ARM.com        .desc("Number of read requests accepted");
136811583SDylan.Johnson@ARM.com
136911583SDylan.Johnson@ARM.com    writeReqs
137011583SDylan.Johnson@ARM.com        .name(name() + ".writeReqs")
137111583SDylan.Johnson@ARM.com        .desc("Number of write requests accepted");
137211583SDylan.Johnson@ARM.com
137311583SDylan.Johnson@ARM.com    readBursts
137411583SDylan.Johnson@ARM.com        .name(name() + ".readBursts")
137511583SDylan.Johnson@ARM.com        .desc("Number of DRAM read bursts, "
137611583SDylan.Johnson@ARM.com              "including those serviced by the write queue");
137711583SDylan.Johnson@ARM.com
137811583SDylan.Johnson@ARM.com    writeBursts
137911583SDylan.Johnson@ARM.com        .name(name() + ".writeBursts")
138011583SDylan.Johnson@ARM.com        .desc("Number of DRAM write bursts, "
138111583SDylan.Johnson@ARM.com              "including those merged in the write queue");
138211583SDylan.Johnson@ARM.com
138311583SDylan.Johnson@ARM.com    servicedByWrQ
138411583SDylan.Johnson@ARM.com        .name(name() + ".servicedByWrQ")
138511583SDylan.Johnson@ARM.com        .desc("Number of DRAM read bursts serviced by the write queue");
138611583SDylan.Johnson@ARM.com
138711583SDylan.Johnson@ARM.com    mergedWrBursts
138811583SDylan.Johnson@ARM.com        .name(name() + ".mergedWrBursts")
138911583SDylan.Johnson@ARM.com        .desc("Number of DRAM write bursts merged with an existing one");
139011583SDylan.Johnson@ARM.com
139111583SDylan.Johnson@ARM.com    neitherReadNorWrite
139211583SDylan.Johnson@ARM.com        .name(name() + ".neitherReadNorWriteReqs")
139311583SDylan.Johnson@ARM.com        .desc("Number of requests that are neither read nor write");
139411583SDylan.Johnson@ARM.com
139511583SDylan.Johnson@ARM.com    perBankRdBursts
139611583SDylan.Johnson@ARM.com        .init(banksPerRank * ranksPerChannel)
139711583SDylan.Johnson@ARM.com        .name(name() + ".perBankRdBursts")
139811583SDylan.Johnson@ARM.com        .desc("Per bank write bursts");
139911583SDylan.Johnson@ARM.com
140011583SDylan.Johnson@ARM.com    perBankWrBursts
140111583SDylan.Johnson@ARM.com        .init(banksPerRank * ranksPerChannel)
140211583SDylan.Johnson@ARM.com        .name(name() + ".perBankWrBursts")
140311583SDylan.Johnson@ARM.com        .desc("Per bank write bursts");
140411583SDylan.Johnson@ARM.com
140511583SDylan.Johnson@ARM.com    avgRdQLen
140611583SDylan.Johnson@ARM.com        .name(name() + ".avgRdQLen")
140711583SDylan.Johnson@ARM.com        .desc("Average read queue length when enqueuing")
140811583SDylan.Johnson@ARM.com        .precision(2);
140911583SDylan.Johnson@ARM.com
141011583SDylan.Johnson@ARM.com    avgWrQLen
141111583SDylan.Johnson@ARM.com        .name(name() + ".avgWrQLen")
141211583SDylan.Johnson@ARM.com        .desc("Average write queue length when enqueuing")
141311583SDylan.Johnson@ARM.com        .precision(2);
141411583SDylan.Johnson@ARM.com
141510037SARM gem5 Developers    totQLat
14167404SAli.Saidi@ARM.com        .name(name() + ".totQLat")
14177404SAli.Saidi@ARM.com        .desc("Total ticks spent queuing");
14187404SAli.Saidi@ARM.com
14197404SAli.Saidi@ARM.com    totBankLat
14207404SAli.Saidi@ARM.com        .name(name() + ".totBankLat")
142110037SARM gem5 Developers        .desc("Total ticks spent accessing banks");
142210037SARM gem5 Developers
142310037SARM gem5 Developers    totBusLat
142410037SARM gem5 Developers        .name(name() + ".totBusLat")
14257439Sdam.sunwoo@arm.com        .desc("Total ticks spent in databus transfers");
142610037SARM gem5 Developers
14277404SAli.Saidi@ARM.com    totMemAccLat
14287404SAli.Saidi@ARM.com        .name(name() + ".totMemAccLat")
14297439Sdam.sunwoo@arm.com        .desc("Total ticks spent from burst creation until serviced "
14307404SAli.Saidi@ARM.com              "by the DRAM");
14317404SAli.Saidi@ARM.com
14327946SGiacomo.Gabrielli@arm.com    avgQLat
14337439Sdam.sunwoo@arm.com        .name(name() + ".avgQLat")
14347439Sdam.sunwoo@arm.com        .desc("Average queueing delay per DRAM burst")
14357437Sdam.sunwoo@arm.com        .precision(2);
14367406SAli.Saidi@ARM.com
14377439Sdam.sunwoo@arm.com    avgQLat = totQLat / (readBursts - servicedByWrQ);
14387439Sdam.sunwoo@arm.com
143910474Sandreas.hansson@arm.com    avgBankLat
144010474Sandreas.hansson@arm.com        .name(name() + ".avgBankLat")
144110474Sandreas.hansson@arm.com        .desc("Average bank access latency per DRAM burst")
144210474Sandreas.hansson@arm.com        .precision(2);
144310474Sandreas.hansson@arm.com
14447406SAli.Saidi@ARM.com    avgBankLat = totBankLat / (readBursts - servicedByWrQ);
14457439Sdam.sunwoo@arm.com
144610474Sandreas.hansson@arm.com    avgBusLat
144710474Sandreas.hansson@arm.com        .name(name() + ".avgBusLat")
144810474Sandreas.hansson@arm.com        .desc("Average bus latency per DRAM burst")
144910474Sandreas.hansson@arm.com        .precision(2);
145010474Sandreas.hansson@arm.com
145110474Sandreas.hansson@arm.com    avgBusLat = totBusLat / (readBursts - servicedByWrQ);
14527404SAli.Saidi@ARM.com
14537404SAli.Saidi@ARM.com    avgMemAccLat
14547439Sdam.sunwoo@arm.com        .name(name() + ".avgMemAccLat")
14557436Sdam.sunwoo@arm.com        .desc("Average memory access latency per DRAM burst")
14567436Sdam.sunwoo@arm.com        .precision(2);
14577436Sdam.sunwoo@arm.com
14587436Sdam.sunwoo@arm.com    avgMemAccLat = totMemAccLat / (readBursts - servicedByWrQ);
14597436Sdam.sunwoo@arm.com
146010474Sandreas.hansson@arm.com    numRdRetry
146110474Sandreas.hansson@arm.com        .name(name() + ".numRdRetry")
146210474Sandreas.hansson@arm.com        .desc("Number of times read queue was full causing retry");
146310474Sandreas.hansson@arm.com
146410474Sandreas.hansson@arm.com    numWrRetry
146510474Sandreas.hansson@arm.com        .name(name() + ".numWrRetry")
146610474Sandreas.hansson@arm.com        .desc("Number of times write queue was full causing retry");
14677436Sdam.sunwoo@arm.com
14687439Sdam.sunwoo@arm.com    readRowHits
14697404SAli.Saidi@ARM.com        .name(name() + ".readRowHits")
14707404SAli.Saidi@ARM.com        .desc("Number of row buffer hits during reads");
147110037SARM gem5 Developers
147210037SARM gem5 Developers    writeRowHits
147310037SARM gem5 Developers        .name(name() + ".writeRowHits")
147410037SARM gem5 Developers        .desc("Number of row buffer hits during writes");
147510037SARM gem5 Developers
147610037SARM gem5 Developers    readRowHitRate
147710037SARM gem5 Developers        .name(name() + ".readRowHitRate")
147810037SARM gem5 Developers        .desc("Row buffer hit rate for reads")
147910037SARM gem5 Developers        .precision(2);
14807404SAli.Saidi@ARM.com
148110037SARM gem5 Developers    readRowHitRate = (readRowHits / (readBursts - servicedByWrQ)) * 100;
148211395Sandreas.sandberg@arm.com
148311395Sandreas.sandberg@arm.com    writeRowHitRate
14847404SAli.Saidi@ARM.com        .name(name() + ".writeRowHitRate")
148510037SARM gem5 Developers        .desc("Row buffer hit rate for writes")
148610037SARM gem5 Developers        .precision(2);
148710037SARM gem5 Developers
148810037SARM gem5 Developers    writeRowHitRate = (writeRowHits / (writeBursts - mergedWrBursts)) * 100;
148910037SARM gem5 Developers
149010037SARM gem5 Developers    readPktSize
149110037SARM gem5 Developers        .init(ceilLog2(burstSize) + 1)
149210037SARM gem5 Developers        .name(name() + ".readPktSize")
149310836Sandreas.hansson@arm.com        .desc("Read request sizes (log2)");
149410037SARM gem5 Developers
149510037SARM gem5 Developers     writePktSize
149610037SARM gem5 Developers        .init(ceilLog2(burstSize) + 1)
149710037SARM gem5 Developers        .name(name() + ".writePktSize")
149810037SARM gem5 Developers        .desc("Write request sizes (log2)");
149910037SARM gem5 Developers
150010037SARM gem5 Developers     rdQLenPdf
150110037SARM gem5 Developers        .init(readBufferSize)
150210037SARM gem5 Developers        .name(name() + ".rdQLenPdf")
150310037SARM gem5 Developers        .desc("What read queue length does an incoming req see");
150410037SARM gem5 Developers
150510037SARM gem5 Developers     wrQLenPdf
150610037SARM gem5 Developers        .init(writeBufferSize)
150710037SARM gem5 Developers        .name(name() + ".wrQLenPdf")
150810037SARM gem5 Developers        .desc("What write queue length does an incoming req see");
150910037SARM gem5 Developers
151010037SARM gem5 Developers     bytesPerActivate
151110037SARM gem5 Developers         .init(maxAccessesPerRow)
151210037SARM gem5 Developers         .name(name() + ".bytesPerActivate")
151310037SARM gem5 Developers         .desc("Bytes accessed per row activation")
151410037SARM gem5 Developers         .flags(nozero);
151510037SARM gem5 Developers
151610037SARM gem5 Developers    bytesReadDRAM
151710037SARM gem5 Developers        .name(name() + ".bytesReadDRAM")
151810037SARM gem5 Developers        .desc("Total number of bytes read from DRAM");
151910037SARM gem5 Developers
152010037SARM gem5 Developers    bytesReadWrQ
152110037SARM gem5 Developers        .name(name() + ".bytesReadWrQ")
152210037SARM gem5 Developers        .desc("Total number of bytes read from write queue");
152310037SARM gem5 Developers
152410037SARM gem5 Developers    bytesWritten
152510037SARM gem5 Developers        .name(name() + ".bytesWritten")
152610037SARM gem5 Developers        .desc("Total number of bytes written to DRAM");
152710037SARM gem5 Developers
152810037SARM gem5 Developers    bytesReadSys
152910037SARM gem5 Developers        .name(name() + ".bytesReadSys")
153010037SARM gem5 Developers        .desc("Total read bytes from the system interface side");
153110037SARM gem5 Developers
153210037SARM gem5 Developers    bytesWrittenSys
153310037SARM gem5 Developers        .name(name() + ".bytesWrittenSys")
153410037SARM gem5 Developers        .desc("Total written bytes from the system interface side");
153510037SARM gem5 Developers
153610037SARM gem5 Developers    avgRdBW
153710037SARM gem5 Developers        .name(name() + ".avgRdBW")
153810037SARM gem5 Developers        .desc("Average DRAM read bandwidth in MiByte/s")
153910037SARM gem5 Developers        .precision(2);
154010037SARM gem5 Developers
154110037SARM gem5 Developers    avgRdBW = (bytesReadDRAM / 1000000) / simSeconds;
154210037SARM gem5 Developers
154310037SARM gem5 Developers    avgWrBW
154410037SARM gem5 Developers        .name(name() + ".avgWrBW")
154510037SARM gem5 Developers        .desc("Average achieved write bandwidth in MiByte/s")
154610037SARM gem5 Developers        .precision(2);
15477439Sdam.sunwoo@arm.com
15487439Sdam.sunwoo@arm.com    avgWrBW = (bytesWritten / 1000000) / simSeconds;
15497439Sdam.sunwoo@arm.com
15507437Sdam.sunwoo@arm.com    avgRdBWSys
15517404SAli.Saidi@ARM.com        .name(name() + ".avgRdBWSys")
155210037SARM gem5 Developers        .desc("Average system read bandwidth in MiByte/s")
155310037SARM gem5 Developers        .precision(2);
155410037SARM gem5 Developers
155510037SARM gem5 Developers    avgRdBWSys = (bytesReadSys / 1000000) / simSeconds;
155610474Sandreas.hansson@arm.com
155710037SARM gem5 Developers    avgWrBWSys
155810037SARM gem5 Developers        .name(name() + ".avgWrBWSys")
155910037SARM gem5 Developers        .desc("Average system write bandwidth in MiByte/s")
156010037SARM gem5 Developers        .precision(2);
156110037SARM gem5 Developers
156210474Sandreas.hansson@arm.com    avgWrBWSys = (bytesWrittenSys / 1000000) / simSeconds;
156310037SARM gem5 Developers
156410037SARM gem5 Developers    peakBW
156510037SARM gem5 Developers        .name(name() + ".peakBW")
156610037SARM gem5 Developers        .desc("Theoretical peak bandwidth in MiByte/s")
156710037SARM gem5 Developers        .precision(2);
156810037SARM gem5 Developers
15697404SAli.Saidi@ARM.com    peakBW = (SimClock::Frequency / tBURST) * burstSize / 1000000;
157010037SARM gem5 Developers
157110037SARM gem5 Developers    busUtil
157210037SARM gem5 Developers        .name(name() + ".busUtil")
157310037SARM gem5 Developers        .desc("Data bus utilization in percentage")
157410037SARM gem5 Developers        .precision(2);
157510037SARM gem5 Developers
157610037SARM gem5 Developers    busUtil = (avgRdBW + avgWrBW) / peakBW * 100;
157710037SARM gem5 Developers
157810037SARM gem5 Developers    totGap
157910037SARM gem5 Developers        .name(name() + ".totGap")
158010037SARM gem5 Developers        .desc("Total gap between requests");
158110037SARM gem5 Developers
158210037SARM gem5 Developers    avgGap
158310037SARM gem5 Developers        .name(name() + ".avgGap")
158410037SARM gem5 Developers        .desc("Average gap between requests")
158510037SARM gem5 Developers        .precision(2);
158610037SARM gem5 Developers
158710037SARM gem5 Developers    avgGap = totGap / (readReqs + writeReqs);
158810037SARM gem5 Developers
158910037SARM gem5 Developers    // Stats for DRAM Power calculation based on Micron datasheet
159010037SARM gem5 Developers    busUtilRead
159110037SARM gem5 Developers        .name(name() + ".busUtilRead")
159210474Sandreas.hansson@arm.com        .desc("Data bus utilization in percentage for reads")
159310037SARM gem5 Developers        .precision(2);
159410037SARM gem5 Developers
159510037SARM gem5 Developers    busUtilRead = avgRdBW / peakBW * 100;
159610037SARM gem5 Developers
159710037SARM gem5 Developers    busUtilWrite
159810037SARM gem5 Developers        .name(name() + ".busUtilWrite")
159910474Sandreas.hansson@arm.com        .desc("Data bus utilization in percentage for writes")
160010037SARM gem5 Developers        .precision(2);
160110037SARM gem5 Developers
160210037SARM gem5 Developers    busUtilWrite = avgWrBW / peakBW * 100;
160310037SARM gem5 Developers
160410037SARM gem5 Developers    pageHitRate
160510037SARM gem5 Developers        .name(name() + ".pageHitRate")
160610037SARM gem5 Developers        .desc("Row buffer hit rate, read and write combined")
160710037SARM gem5 Developers        .precision(2);
160810037SARM gem5 Developers
160910037SARM gem5 Developers    pageHitRate = (writeRowHits + readRowHits) /
161010037SARM gem5 Developers        (writeBursts - mergedWrBursts + readBursts - servicedByWrQ) * 100;
161110037SARM gem5 Developers
161210037SARM gem5 Developers    prechargeAllPercent
161310037SARM gem5 Developers        .name(name() + ".prechargeAllPercent")
161410037SARM gem5 Developers        .desc("Percentage of time for which DRAM has all the banks in "
161510037SARM gem5 Developers              "precharge state")
161610037SARM gem5 Developers        .precision(2);
161710037SARM gem5 Developers
161810037SARM gem5 Developers    prechargeAllPercent = prechargeAllTime / simTicks * 100;
161910037SARM gem5 Developers}
162010037SARM gem5 Developers
162110037SARM gem5 Developersvoid
162210037SARM gem5 DevelopersSimpleDRAM::recvFunctional(PacketPtr pkt)
162310037SARM gem5 Developers{
16247404SAli.Saidi@ARM.com    // rely on the abstract memory
162510037SARM gem5 Developers    functionalAccess(pkt);
162610037SARM gem5 Developers}
162710037SARM gem5 Developers
16287439Sdam.sunwoo@arm.comBaseSlavePort&
162910037SARM gem5 DevelopersSimpleDRAM::getSlavePort(const string &if_name, PortID idx)
163010037SARM gem5 Developers{
163110037SARM gem5 Developers    if (if_name != "port") {
163210037SARM gem5 Developers        return MemObject::getSlavePort(if_name, idx);
163310037SARM gem5 Developers    } else {
163410037SARM gem5 Developers        return port;
163510037SARM gem5 Developers    }
163610037SARM gem5 Developers}
163710037SARM gem5 Developers
163810037SARM gem5 Developersunsigned int
163910037SARM gem5 DevelopersSimpleDRAM::drain(DrainManager *dm)
164010037SARM gem5 Developers{
164110474Sandreas.hansson@arm.com    unsigned int count = port.drain(dm);
164210037SARM gem5 Developers
164310037SARM gem5 Developers    // if there is anything in any of our internal queues, keep track
164410037SARM gem5 Developers    // of that as well
164510037SARM gem5 Developers    if (!(writeQueue.empty() && readQueue.empty() &&
164610037SARM gem5 Developers          respQueue.empty())) {
164710037SARM gem5 Developers        DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d,"
164810474Sandreas.hansson@arm.com                " resp: %d\n", writeQueue.size(), readQueue.size(),
164910037SARM gem5 Developers                respQueue.size());
165010037SARM gem5 Developers        ++count;
165110037SARM gem5 Developers        drainManager = dm;
165210037SARM gem5 Developers        // the only part that is not drained automatically over time
165310037SARM gem5 Developers        // is the write queue, thus trigger writes if there are any
165410037SARM gem5 Developers        // waiting and no reads waiting, otherwise wait until the
165510037SARM gem5 Developers        // reads are done
16567437Sdam.sunwoo@arm.com        if (readQueue.empty() && !writeQueue.empty() &&
16577404SAli.Saidi@ARM.com            !writeEvent.scheduled())
165810037SARM gem5 Developers            triggerWrites();
165911395Sandreas.sandberg@arm.com    }
166011395Sandreas.sandberg@arm.com
166111395Sandreas.sandberg@arm.com    if (count)
16627404SAli.Saidi@ARM.com        setDrainState(Drainable::Draining);
166310037SARM gem5 Developers    else
166410037SARM gem5 Developers        setDrainState(Drainable::Drained);
166510037SARM gem5 Developers    return count;
166610037SARM gem5 Developers}
166710037SARM gem5 Developers
166810037SARM gem5 DevelopersSimpleDRAM::MemoryPort::MemoryPort(const std::string& name, SimpleDRAM& _memory)
166910037SARM gem5 Developers    : QueuedSlavePort(name, &_memory, queue), queue(_memory, *this),
167010037SARM gem5 Developers      memory(_memory)
167110836Sandreas.hansson@arm.com{ }
167210037SARM gem5 Developers
167310037SARM gem5 DevelopersAddrRangeList
167410037SARM gem5 DevelopersSimpleDRAM::MemoryPort::getAddrRanges() const
167510037SARM gem5 Developers{
167610037SARM gem5 Developers    AddrRangeList ranges;
167710037SARM gem5 Developers    ranges.push_back(memory.getAddrRange());
167810037SARM gem5 Developers    return ranges;
167910037SARM gem5 Developers}
168010037SARM gem5 Developers
168110037SARM gem5 Developersvoid
168210037SARM gem5 DevelopersSimpleDRAM::MemoryPort::recvFunctional(PacketPtr pkt)
168310037SARM gem5 Developers{
168410037SARM gem5 Developers    pkt->pushLabel(memory.name());
168510037SARM gem5 Developers
168610037SARM gem5 Developers    if (!queue.checkFunctional(pkt)) {
168710037SARM gem5 Developers        // Default implementation of SimpleTimingPort::recvFunctional()
168810037SARM gem5 Developers        // calls recvAtomic() and throws away the latency; we can save a
168910037SARM gem5 Developers        // little here by just not calculating the latency.
169010037SARM gem5 Developers        memory.recvFunctional(pkt);
169110037SARM gem5 Developers    }
169210037SARM gem5 Developers
169310037SARM gem5 Developers    pkt->popLabel();
169410037SARM gem5 Developers}
169510037SARM gem5 Developers
169610037SARM gem5 DevelopersTick
169710037SARM gem5 DevelopersSimpleDRAM::MemoryPort::recvAtomic(PacketPtr pkt)
169810037SARM gem5 Developers{
169910037SARM gem5 Developers    return memory.recvAtomic(pkt);
170010037SARM gem5 Developers}
17017404SAli.Saidi@ARM.com
17027404SAli.Saidi@ARM.combool
17037404SAli.Saidi@ARM.comSimpleDRAM::MemoryPort::recvTimingReq(PacketPtr pkt)
17047404SAli.Saidi@ARM.com{
17057404SAli.Saidi@ARM.com    // pass it to the memory controller
17067404SAli.Saidi@ARM.com    return memory.recvTimingReq(pkt);
17077404SAli.Saidi@ARM.com}
17087404SAli.Saidi@ARM.com
17097404SAli.Saidi@ARM.comSimpleDRAM*
17107404SAli.Saidi@ARM.comSimpleDRAMParams::create()
171110037SARM gem5 Developers{
171210037SARM gem5 Developers    return new SimpleDRAM(this);
171310037SARM gem5 Developers}
171410037SARM gem5 Developers