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