dram_ctrl.cc revision 9832
1/*
2 * Copyright (c) 2010-2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2013 Amin Farmahini-Farahani
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Andreas Hansson
41 *          Ani Udipi
42 */
43
44#include "base/trace.hh"
45#include "debug/Drain.hh"
46#include "debug/DRAM.hh"
47#include "debug/DRAMWR.hh"
48#include "mem/simple_dram.hh"
49#include "sim/system.hh"
50
51using namespace std;
52
53SimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
54    AbstractMemory(p),
55    port(name() + ".port", *this),
56    retryRdReq(false), retryWrReq(false),
57    rowHitFlag(false), stopReads(false), actTicks(p->activation_limit, 0),
58    writeEvent(this), respondEvent(this),
59    refreshEvent(this), nextReqEvent(this), drainManager(NULL),
60    deviceBusWidth(p->device_bus_width), burstLength(p->burst_length),
61    deviceRowBufferSize(p->device_rowbuffer_size),
62    devicesPerRank(p->devices_per_rank),
63    burstSize((devicesPerRank * burstLength * deviceBusWidth) / 8),
64    rowBufferSize(devicesPerRank * deviceRowBufferSize),
65    ranksPerChannel(p->ranks_per_channel),
66    banksPerRank(p->banks_per_rank), channels(p->channels), rowsPerBank(0),
67    readBufferSize(p->read_buffer_size),
68    writeBufferSize(p->write_buffer_size),
69    writeThresholdPerc(p->write_thresh_perc),
70    tWTR(p->tWTR), tBURST(p->tBURST),
71    tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP),
72    tRFC(p->tRFC), tREFI(p->tREFI),
73    tXAW(p->tXAW), activationLimit(p->activation_limit),
74    memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping),
75    pageMgmt(p->page_policy),
76    frontendLatency(p->static_frontend_latency),
77    backendLatency(p->static_backend_latency),
78    busBusyUntil(0), writeStartTime(0),
79    prevArrival(0), numReqs(0)
80{
81    // create the bank states based on the dimensions of the ranks and
82    // banks
83    banks.resize(ranksPerChannel);
84    for (size_t c = 0; c < ranksPerChannel; ++c) {
85        banks[c].resize(banksPerRank);
86    }
87
88    // round the write threshold percent to a whole number of entries
89    // in the buffer
90    writeThreshold = writeBufferSize * writeThresholdPerc / 100.0;
91}
92
93void
94SimpleDRAM::init()
95{
96    if (!port.isConnected()) {
97        fatal("SimpleDRAM %s is unconnected!\n", name());
98    } else {
99        port.sendRangeChange();
100    }
101
102    // we could deal with plenty options here, but for now do a quick
103    // sanity check
104    DPRINTF(DRAM, "Burst size %d bytes\n", burstSize);
105
106    // determine the rows per bank by looking at the total capacity
107    uint64_t capacity = ULL(1) << ceilLog2(AbstractMemory::size());
108
109    DPRINTF(DRAM, "Memory capacity %lld (%lld) bytes\n", capacity,
110            AbstractMemory::size());
111
112    columnsPerRowBuffer = rowBufferSize / burstSize;
113
114    DPRINTF(DRAM, "Row buffer size %d bytes with %d columns per row buffer\n",
115            rowBufferSize, columnsPerRowBuffer);
116
117    rowsPerBank = capacity / (rowBufferSize * banksPerRank * ranksPerChannel);
118
119    if (range.interleaved()) {
120        if (channels != range.stripes())
121            panic("%s has %d interleaved address stripes but %d channel(s)\n",
122                  name(), range.stripes(), channels);
123
124        if (addrMapping == Enums::RaBaChCo) {
125            if (rowBufferSize != range.granularity()) {
126                panic("Interleaving of %s doesn't match RaBaChCo address map\n",
127                      name());
128            }
129        } else if (addrMapping == Enums::RaBaCoCh) {
130            if (burstSize != range.granularity()) {
131                panic("Interleaving of %s doesn't match RaBaCoCh address map\n",
132                      name());
133            }
134        } else if (addrMapping == Enums::CoRaBaCh) {
135            if (burstSize != range.granularity())
136                panic("Interleaving of %s doesn't match CoRaBaCh address map\n",
137                      name());
138        }
139    }
140}
141
142void
143SimpleDRAM::startup()
144{
145    // print the configuration of the controller
146    printParams();
147
148    // kick off the refresh
149    schedule(refreshEvent, curTick() + tREFI);
150}
151
152Tick
153SimpleDRAM::recvAtomic(PacketPtr pkt)
154{
155    DPRINTF(DRAM, "recvAtomic: %s 0x%x\n", pkt->cmdString(), pkt->getAddr());
156
157    // do the actual memory access and turn the packet into a response
158    access(pkt);
159
160    Tick latency = 0;
161    if (!pkt->memInhibitAsserted() && pkt->hasData()) {
162        // this value is not supposed to be accurate, just enough to
163        // keep things going, mimic a closed page
164        latency = tRP + tRCD + tCL;
165    }
166    return latency;
167}
168
169bool
170SimpleDRAM::readQueueFull(unsigned int neededEntries) const
171{
172    DPRINTF(DRAM, "Read queue limit %d, current size %d, entries needed %d\n",
173            readBufferSize, readQueue.size() + respQueue.size(),
174            neededEntries);
175
176    return
177        (readQueue.size() + respQueue.size() + neededEntries) > readBufferSize;
178}
179
180bool
181SimpleDRAM::writeQueueFull(unsigned int neededEntries) const
182{
183    DPRINTF(DRAM, "Write queue limit %d, current size %d, entries needed %d\n",
184            writeBufferSize, writeQueue.size(), neededEntries);
185    return (writeQueue.size() + neededEntries) > writeBufferSize;
186}
187
188SimpleDRAM::DRAMPacket*
189SimpleDRAM::decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned size)
190{
191    // decode the address based on the address mapping scheme, with
192    // Ra, Co, Ba and Ch denoting rank, column, bank and channel,
193    // respectively
194    uint8_t rank;
195    uint16_t bank;
196    uint16_t row;
197
198    // truncate the address to the access granularity
199    Addr addr = dramPktAddr / burstSize;
200
201    // we have removed the lowest order address bits that denote the
202    // position within the column
203    if (addrMapping == Enums::RaBaChCo) {
204        // the lowest order bits denote the column to ensure that
205        // sequential cache lines occupy the same row
206        addr = addr / columnsPerRowBuffer;
207
208        // take out the channel part of the address
209        addr = addr / channels;
210
211        // after the channel bits, get the bank bits to interleave
212        // over the banks
213        bank = addr % banksPerRank;
214        addr = addr / banksPerRank;
215
216        // after the bank, we get the rank bits which thus interleaves
217        // over the ranks
218        rank = addr % ranksPerChannel;
219        addr = addr / ranksPerChannel;
220
221        // lastly, get the row bits
222        row = addr % rowsPerBank;
223        addr = addr / rowsPerBank;
224    } else if (addrMapping == Enums::RaBaCoCh) {
225        // take out the channel part of the address
226        addr = addr / channels;
227
228        // next, the column
229        addr = addr / columnsPerRowBuffer;
230
231        // after the column bits, we get the bank bits to interleave
232        // over the banks
233        bank = addr % banksPerRank;
234        addr = addr / banksPerRank;
235
236        // after the bank, we get the rank bits which thus interleaves
237        // over the ranks
238        rank = addr % ranksPerChannel;
239        addr = addr / ranksPerChannel;
240
241        // lastly, get the row bits
242        row = addr % rowsPerBank;
243        addr = addr / rowsPerBank;
244    } else if (addrMapping == Enums::CoRaBaCh) {
245        // optimise for closed page mode and utilise maximum
246        // parallelism of the DRAM (at the cost of power)
247
248        // take out the channel part of the address, not that this has
249        // to match with how accesses are interleaved between the
250        // controllers in the address mapping
251        addr = addr / channels;
252
253        // start with the bank bits, as this provides the maximum
254        // opportunity for parallelism between requests
255        bank = addr % banksPerRank;
256        addr = addr / banksPerRank;
257
258        // next get the rank bits
259        rank = addr % ranksPerChannel;
260        addr = addr / ranksPerChannel;
261
262        // next the column bits which we do not need to keep track of
263        // and simply skip past
264        addr = addr / columnsPerRowBuffer;
265
266        // lastly, get the row bits
267        row = addr % rowsPerBank;
268        addr = addr / rowsPerBank;
269    } else
270        panic("Unknown address mapping policy chosen!");
271
272    assert(rank < ranksPerChannel);
273    assert(bank < banksPerRank);
274    assert(row < rowsPerBank);
275
276    DPRINTF(DRAM, "Address: %lld Rank %d Bank %d Row %d\n",
277            dramPktAddr, rank, bank, row);
278
279    // create the corresponding DRAM packet with the entry time and
280    // ready time set to the current tick, the latter will be updated
281    // later
282    return new DRAMPacket(pkt, rank, bank, row, dramPktAddr, size,
283                          banks[rank][bank]);
284}
285
286void
287SimpleDRAM::addToReadQueue(PacketPtr pkt, unsigned int pktCount)
288{
289    // only add to the read queue here. whenever the request is
290    // eventually done, set the readyTime, and call schedule()
291    assert(!pkt->isWrite());
292
293    assert(pktCount != 0);
294
295    // if the request size is larger than burst size, the pkt is split into
296    // multiple DRAM packets
297    // Note if the pkt starting address is not aligened to burst size, the
298    // address of first DRAM packet is kept unaliged. Subsequent DRAM packets
299    // are aligned to burst size boundaries. This is to ensure we accurately
300    // check read packets against packets in write queue.
301    Addr addr = pkt->getAddr();
302    unsigned pktsServicedByWrQ = 0;
303    BurstHelper* burst_helper = NULL;
304    for (int cnt = 0; cnt < pktCount; ++cnt) {
305        unsigned size = std::min((addr | (burstSize - 1)) + 1,
306                        pkt->getAddr() + pkt->getSize()) - addr;
307        readPktSize[ceilLog2(size)]++;
308        readBursts++;
309
310        // First check write buffer to see if the data is already at
311        // the controller
312        bool foundInWrQ = false;
313        list<DRAMPacket*>::const_iterator i;
314        for (i = writeQueue.begin(); i != writeQueue.end(); ++i) {
315            // check if the read is subsumed in the write entry we are
316            // looking at
317            if ((*i)->addr <= addr &&
318                (addr + size) <= ((*i)->addr + (*i)->size)) {
319                foundInWrQ = true;
320                servicedByWrQ++;
321                pktsServicedByWrQ++;
322                DPRINTF(DRAM, "Read to addr %lld with size %d serviced by "
323                        "write queue\n", addr, size);
324                bytesRead += burstSize;
325                bytesConsumedRd += size;
326                break;
327            }
328        }
329
330        // If not found in the write q, make a DRAM packet and
331        // push it onto the read queue
332        if (!foundInWrQ) {
333
334            // Make the burst helper for split packets
335            if (pktCount > 1 && burst_helper == NULL) {
336                DPRINTF(DRAM, "Read to addr %lld translates to %d "
337                        "dram requests\n", pkt->getAddr(), pktCount);
338                burst_helper = new BurstHelper(pktCount);
339            }
340
341            DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size);
342            dram_pkt->burstHelper = burst_helper;
343
344            assert(!readQueueFull(1));
345            rdQLenPdf[readQueue.size() + respQueue.size()]++;
346
347            DPRINTF(DRAM, "Adding to read queue\n");
348
349            readQueue.push_back(dram_pkt);
350
351            // Update stats
352            uint32_t bank_id = banksPerRank * dram_pkt->rank + dram_pkt->bank;
353            assert(bank_id < ranksPerChannel * banksPerRank);
354            perBankRdReqs[bank_id]++;
355
356            avgRdQLen = readQueue.size() + respQueue.size();
357        }
358
359        // Starting address of next dram pkt (aligend to burstSize boundary)
360        addr = (addr | (burstSize - 1)) + 1;
361    }
362
363    // If all packets are serviced by write queue, we send the repsonse back
364    if (pktsServicedByWrQ == pktCount) {
365        accessAndRespond(pkt, frontendLatency);
366        return;
367    }
368
369    // Update how many split packets are serviced by write queue
370    if (burst_helper != NULL)
371        burst_helper->burstsServiced = pktsServicedByWrQ;
372
373    // If we are not already scheduled to get the read request out of
374    // the queue, do so now
375    if (!nextReqEvent.scheduled() && !stopReads) {
376        DPRINTF(DRAM, "Request scheduled immediately\n");
377        schedule(nextReqEvent, curTick());
378    }
379}
380
381void
382SimpleDRAM::processWriteEvent()
383{
384    assert(!writeQueue.empty());
385    uint32_t numWritesThisTime = 0;
386
387    DPRINTF(DRAMWR, "Beginning DRAM Writes\n");
388    Tick temp1 M5_VAR_USED = std::max(curTick(), busBusyUntil);
389    Tick temp2 M5_VAR_USED = std::max(curTick(), maxBankFreeAt());
390
391    // @todo: are there any dangers with the untimed while loop?
392    while (!writeQueue.empty()) {
393        if (numWritesThisTime > writeThreshold) {
394            DPRINTF(DRAMWR, "Hit write threshold %d\n", writeThreshold);
395            break;
396        }
397
398        chooseNextWrite();
399        DRAMPacket* dram_pkt = writeQueue.front();
400
401        // sanity check
402        assert(dram_pkt->size <= burstSize);
403
404        // What's the earliest the request can be put on the bus
405        Tick schedTime = std::max(curTick(), busBusyUntil);
406
407        DPRINTF(DRAMWR, "Asking for latency estimate at %lld\n",
408                schedTime + tBURST);
409
410        pair<Tick, Tick> lat = estimateLatency(dram_pkt, schedTime + tBURST);
411        Tick accessLat = lat.second;
412
413        // look at the rowHitFlag set by estimateLatency
414        if (rowHitFlag)
415            writeRowHits++;
416
417        Bank& bank = dram_pkt->bank_ref;
418
419        if (pageMgmt == Enums::open) {
420            bank.openRow = dram_pkt->row;
421            bank.freeAt = schedTime + tBURST + std::max(accessLat, tCL);
422            busBusyUntil = bank.freeAt - tCL;
423            bank.bytesAccessed += burstSize;
424
425            if (!rowHitFlag) {
426                bank.tRASDoneAt = bank.freeAt + tRP;
427                recordActivate(bank.freeAt - tCL - tRCD);
428                busBusyUntil = bank.freeAt - tCL - tRCD;
429
430                // sample the number of bytes accessed and reset it as
431                // we are now closing this row
432                bytesPerActivate.sample(bank.bytesAccessed);
433                bank.bytesAccessed = 0;
434            }
435        } else if (pageMgmt == Enums::close) {
436            bank.freeAt = schedTime + tBURST + accessLat + tRP + tRP;
437            // Work backwards from bank.freeAt to determine activate time
438            recordActivate(bank.freeAt - tRP - tRP - tCL - tRCD);
439            busBusyUntil = bank.freeAt - tRP - tRP - tCL - tRCD;
440            DPRINTF(DRAMWR, "processWriteEvent::bank.freeAt for "
441                    "banks_id %d is %lld\n",
442                    dram_pkt->rank * banksPerRank + dram_pkt->bank,
443                    bank.freeAt);
444            bytesPerActivate.sample(burstSize);
445        } else
446            panic("Unknown page management policy chosen\n");
447
448        DPRINTF(DRAMWR, "Done writing to address %lld\n", dram_pkt->addr);
449
450        DPRINTF(DRAMWR, "schedtime is %lld, tBURST is %lld, "
451                "busbusyuntil is %lld\n",
452                schedTime, tBURST, busBusyUntil);
453
454        writeQueue.pop_front();
455        delete dram_pkt;
456
457        numWritesThisTime++;
458    }
459
460    DPRINTF(DRAMWR, "Completed %d writes, bus busy for %lld ticks,"\
461            "banks busy for %lld ticks\n", numWritesThisTime,
462            busBusyUntil - temp1, maxBankFreeAt() - temp2);
463
464    // Update stats
465    avgWrQLen = writeQueue.size();
466
467    // turn the bus back around for reads again
468    busBusyUntil += tWTR;
469    stopReads = false;
470
471    if (retryWrReq) {
472        retryWrReq = false;
473        port.sendRetry();
474    }
475
476    // if there is nothing left in any queue, signal a drain
477    if (writeQueue.empty() && readQueue.empty() &&
478        respQueue.empty () && drainManager) {
479        drainManager->signalDrainDone();
480        drainManager = NULL;
481    }
482
483    // Once you're done emptying the write queue, check if there's
484    // anything in the read queue, and call schedule if required. The
485    // retry above could already have caused it to be scheduled, so
486    // first check
487    if (!nextReqEvent.scheduled())
488        schedule(nextReqEvent, busBusyUntil);
489}
490
491void
492SimpleDRAM::triggerWrites()
493{
494    DPRINTF(DRAM, "Writes triggered at %lld\n", curTick());
495    // Flag variable to stop any more read scheduling
496    stopReads = true;
497
498    writeStartTime = std::max(busBusyUntil, curTick()) + tWTR;
499
500    DPRINTF(DRAM, "Writes scheduled at %lld\n", writeStartTime);
501
502    assert(writeStartTime >= curTick());
503    assert(!writeEvent.scheduled());
504    schedule(writeEvent, writeStartTime);
505}
506
507void
508SimpleDRAM::addToWriteQueue(PacketPtr pkt, unsigned int pktCount)
509{
510    // only add to the write queue here. whenever the request is
511    // eventually done, set the readyTime, and call schedule()
512    assert(pkt->isWrite());
513
514    // if the request size is larger than burst size, the pkt is split into
515    // multiple DRAM packets
516    Addr addr = pkt->getAddr();
517    for (int cnt = 0; cnt < pktCount; ++cnt) {
518        unsigned size = std::min((addr | (burstSize - 1)) + 1,
519                        pkt->getAddr() + pkt->getSize()) - addr;
520        writePktSize[ceilLog2(size)]++;
521        writeBursts++;
522
523        // see if we can merge with an existing item in the write
524        // queue and keep track of whether we have merged or not, as
525        // there is only ever one item to merge with
526        bool merged = false;
527        auto w = writeQueue.begin();
528
529        while(!merged && w != writeQueue.end()) {
530            // either of the two could be first, if they are the same
531            // it does not matter which way we go
532            if ((*w)->addr >= addr) {
533                if ((addr + size) >= ((*w)->addr + (*w)->size)) {
534                    // check if the existing one is completely
535                    // subsumed in the new one
536                    DPRINTF(DRAM, "Merging write covering existing burst\n");
537                    merged = true;
538                    // update both the address and the size
539                    (*w)->addr = addr;
540                    (*w)->size = size;
541                } else if ((addr + size) >= (*w)->addr &&
542                           ((*w)->addr + (*w)->size - addr) <= burstSize) {
543                    // the new one is just before or partially
544                    // overlapping with the existing one, and together
545                    // they fit within a burst
546                    DPRINTF(DRAM, "Merging write before existing burst\n");
547                    merged = true;
548                    // the existing queue item needs to be adjusted with
549                    // respect to both address and size
550                    (*w)->addr = addr;
551                    (*w)->size = (*w)->addr + (*w)->size - addr;
552                }
553            } else {
554                if (((*w)->addr + (*w)->size) >= (addr + size)) {
555                    // check if the new one is completely subsumed in the
556                    // existing one
557                    DPRINTF(DRAM, "Merging write into existing burst\n");
558                    merged = true;
559                    // no adjustments necessary
560                } else if (((*w)->addr + (*w)->size) >= addr &&
561                           (addr + size - (*w)->addr) <= burstSize) {
562                    // the existing one is just before or partially
563                    // overlapping with the new one, and together
564                    // they fit within a burst
565                    DPRINTF(DRAM, "Merging write after existing burst\n");
566                    merged = true;
567                    // the address is right, and only the size has
568                    // to be adjusted
569                    (*w)->size = addr + size - (*w)->addr;
570                }
571            }
572            ++w;
573        }
574
575        // if the item was not merged we need to create a new write
576        // and enqueue it
577        if (!merged) {
578            DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size);
579
580            assert(writeQueue.size() < writeBufferSize);
581            wrQLenPdf[writeQueue.size()]++;
582
583            DPRINTF(DRAM, "Adding to write queue\n");
584
585            writeQueue.push_back(dram_pkt);
586
587            // Update stats
588            uint32_t bank_id = banksPerRank * dram_pkt->rank + dram_pkt->bank;
589            assert(bank_id < ranksPerChannel * banksPerRank);
590            perBankWrReqs[bank_id]++;
591
592            avgWrQLen = writeQueue.size();
593        }
594
595        bytesConsumedWr += size;
596        bytesWritten += burstSize;
597
598        // Starting address of next dram pkt (aligend to burstSize boundary)
599        addr = (addr | (burstSize - 1)) + 1;
600    }
601
602    // we do not wait for the writes to be send to the actual memory,
603    // but instead take responsibility for the consistency here and
604    // snoop the write queue for any upcoming reads
605    // @todo, if a pkt size is larger than burst size, we might need a
606    // different front end latency
607    accessAndRespond(pkt, frontendLatency);
608
609    // If your write buffer is starting to fill up, drain it!
610    if (writeQueue.size() > writeThreshold && !stopReads){
611        triggerWrites();
612    }
613}
614
615void
616SimpleDRAM::printParams() const
617{
618    // Sanity check print of important parameters
619    DPRINTF(DRAM,
620            "Memory controller %s physical organization\n"      \
621            "Number of devices per rank   %d\n"                 \
622            "Device bus width (in bits)   %d\n"                 \
623            "DRAM data bus burst          %d\n"                 \
624            "Row buffer size              %d\n"                 \
625            "Columns per row buffer       %d\n"                 \
626            "Rows    per bank             %d\n"                 \
627            "Banks   per rank             %d\n"                 \
628            "Ranks   per channel          %d\n"                 \
629            "Total mem capacity           %u\n",
630            name(), devicesPerRank, deviceBusWidth, burstSize, rowBufferSize,
631            columnsPerRowBuffer, rowsPerBank, banksPerRank, ranksPerChannel,
632            rowBufferSize * rowsPerBank * banksPerRank * ranksPerChannel);
633
634    string scheduler =  memSchedPolicy == Enums::fcfs ? "FCFS" : "FR-FCFS";
635    string address_mapping = addrMapping == Enums::RaBaChCo ? "RaBaChCo" :
636        (addrMapping == Enums::RaBaCoCh ? "RaBaCoCh" : "CoRaBaCh");
637    string page_policy = pageMgmt == Enums::open ? "OPEN" : "CLOSE";
638
639    DPRINTF(DRAM,
640            "Memory controller %s characteristics\n"    \
641            "Read buffer size     %d\n"                 \
642            "Write buffer size    %d\n"                 \
643            "Write buffer thresh  %d\n"                 \
644            "Scheduler            %s\n"                 \
645            "Address mapping      %s\n"                 \
646            "Page policy          %s\n",
647            name(), readBufferSize, writeBufferSize, writeThreshold,
648            scheduler, address_mapping, page_policy);
649
650    DPRINTF(DRAM, "Memory controller %s timing specs\n" \
651            "tRCD      %d ticks\n"                        \
652            "tCL       %d ticks\n"                        \
653            "tRP       %d ticks\n"                        \
654            "tBURST    %d ticks\n"                        \
655            "tRFC      %d ticks\n"                        \
656            "tREFI     %d ticks\n"                        \
657            "tWTR      %d ticks\n"                        \
658            "tXAW (%d) %d ticks\n",
659            name(), tRCD, tCL, tRP, tBURST, tRFC, tREFI, tWTR,
660            activationLimit, tXAW);
661}
662
663void
664SimpleDRAM::printQs() const {
665
666    list<DRAMPacket*>::const_iterator i;
667
668    DPRINTF(DRAM, "===READ QUEUE===\n\n");
669    for (i = readQueue.begin() ;  i != readQueue.end() ; ++i) {
670        DPRINTF(DRAM, "Read %lu\n", (*i)->addr);
671    }
672    DPRINTF(DRAM, "\n===RESP QUEUE===\n\n");
673    for (i = respQueue.begin() ;  i != respQueue.end() ; ++i) {
674        DPRINTF(DRAM, "Response %lu\n", (*i)->addr);
675    }
676    DPRINTF(DRAM, "\n===WRITE QUEUE===\n\n");
677    for (i = writeQueue.begin() ;  i != writeQueue.end() ; ++i) {
678        DPRINTF(DRAM, "Write %lu\n", (*i)->addr);
679    }
680}
681
682bool
683SimpleDRAM::recvTimingReq(PacketPtr pkt)
684{
685    /// @todo temporary hack to deal with memory corruption issues until
686    /// 4-phase transactions are complete
687    for (int x = 0; x < pendingDelete.size(); x++)
688        delete pendingDelete[x];
689    pendingDelete.clear();
690
691    // This is where we enter from the outside world
692    DPRINTF(DRAM, "recvTimingReq: request %s addr %lld size %d\n",
693            pkt->cmdString(), pkt->getAddr(), pkt->getSize());
694
695    // simply drop inhibited packets for now
696    if (pkt->memInhibitAsserted()) {
697        DPRINTF(DRAM,"Inhibited packet -- Dropping it now\n");
698        pendingDelete.push_back(pkt);
699        return true;
700    }
701
702   // Every million accesses, print the state of the queues
703   if (numReqs % 1000000 == 0)
704       printQs();
705
706    // Calc avg gap between requests
707    if (prevArrival != 0) {
708        totGap += curTick() - prevArrival;
709    }
710    prevArrival = curTick();
711
712
713    // Find out how many dram packets a pkt translates to
714    // If the burst size is equal or larger than the pkt size, then a pkt
715    // translates to only one dram packet. Otherwise, a pkt translates to
716    // multiple dram packets
717    unsigned size = pkt->getSize();
718    unsigned offset = pkt->getAddr() & (burstSize - 1);
719    unsigned int dram_pkt_count = divCeil(offset + size, burstSize);
720
721    // check local buffers and do not accept if full
722    if (pkt->isRead()) {
723        assert(size != 0);
724        if (readQueueFull(dram_pkt_count)) {
725            DPRINTF(DRAM, "Read queue full, not accepting\n");
726            // remember that we have to retry this port
727            retryRdReq = true;
728            numRdRetry++;
729            return false;
730        } else {
731            addToReadQueue(pkt, dram_pkt_count);
732            readReqs++;
733            numReqs++;
734        }
735    } else if (pkt->isWrite()) {
736        assert(size != 0);
737        if (writeQueueFull(dram_pkt_count)) {
738            DPRINTF(DRAM, "Write queue full, not accepting\n");
739            // remember that we have to retry this port
740            retryWrReq = true;
741            numWrRetry++;
742            return false;
743        } else {
744            addToWriteQueue(pkt, dram_pkt_count);
745            writeReqs++;
746            numReqs++;
747        }
748    } else {
749        DPRINTF(DRAM,"Neither read nor write, ignore timing\n");
750        neitherReadNorWrite++;
751        accessAndRespond(pkt, 1);
752    }
753
754    retryRdReq = false;
755    retryWrReq = false;
756    return true;
757}
758
759void
760SimpleDRAM::processRespondEvent()
761{
762    DPRINTF(DRAM,
763            "processRespondEvent(): Some req has reached its readyTime\n");
764
765    DRAMPacket* dram_pkt = respQueue.front();
766
767    // Actually responds to the requestor
768    bytesConsumedRd += dram_pkt->size;
769    bytesRead += burstSize;
770    if (dram_pkt->burstHelper) {
771        // it is a split packet
772        dram_pkt->burstHelper->burstsServiced++;
773        if (dram_pkt->burstHelper->burstsServiced ==
774                                  dram_pkt->burstHelper->burstCount) {
775            // we have now serviced all children packets of a system packet
776            // so we can now respond to the requester
777            // @todo we probably want to have a different front end and back
778            // end latency for split packets
779            accessAndRespond(dram_pkt->pkt, frontendLatency + backendLatency);
780            delete dram_pkt->burstHelper;
781            dram_pkt->burstHelper = NULL;
782        }
783    } else {
784        // it is not a split packet
785        accessAndRespond(dram_pkt->pkt, frontendLatency + backendLatency);
786    }
787
788    delete respQueue.front();
789    respQueue.pop_front();
790
791    // Update stats
792    avgRdQLen = readQueue.size() + respQueue.size();
793
794    if (!respQueue.empty()) {
795        assert(respQueue.front()->readyTime >= curTick());
796        assert(!respondEvent.scheduled());
797        schedule(respondEvent, respQueue.front()->readyTime);
798    } else {
799        // if there is nothing left in any queue, signal a drain
800        if (writeQueue.empty() && readQueue.empty() &&
801            drainManager) {
802            drainManager->signalDrainDone();
803            drainManager = NULL;
804        }
805    }
806
807    // We have made a location in the queue available at this point,
808    // so if there is a read that was forced to wait, retry now
809    if (retryRdReq) {
810        retryRdReq = false;
811        port.sendRetry();
812    }
813}
814
815void
816SimpleDRAM::chooseNextWrite()
817{
818    // This method does the arbitration between write requests. The
819    // chosen packet is simply moved to the head of the write
820    // queue. The other methods know that this is the place to
821    // look. For example, with FCFS, this method does nothing
822    assert(!writeQueue.empty());
823
824    if (writeQueue.size() == 1) {
825        DPRINTF(DRAMWR, "Single write request, nothing to do\n");
826        return;
827    }
828
829    if (memSchedPolicy == Enums::fcfs) {
830        // Do nothing, since the correct request is already head
831    } else if (memSchedPolicy == Enums::frfcfs) {
832        list<DRAMPacket*>::iterator i = writeQueue.begin();
833        bool foundRowHit = false;
834        while (!foundRowHit && i != writeQueue.end()) {
835            DRAMPacket* dram_pkt = *i;
836            const Bank& bank = dram_pkt->bank_ref;
837            if (bank.openRow == dram_pkt->row) { //FR part
838                DPRINTF(DRAMWR, "Write row buffer hit\n");
839                writeQueue.erase(i);
840                writeQueue.push_front(dram_pkt);
841                foundRowHit = true;
842            } else { //FCFS part
843                ;
844            }
845            ++i;
846        }
847    } else
848        panic("No scheduling policy chosen\n");
849
850    DPRINTF(DRAMWR, "Selected next write request\n");
851}
852
853bool
854SimpleDRAM::chooseNextRead()
855{
856    // This method does the arbitration between read requests. The
857    // chosen packet is simply moved to the head of the queue. The
858    // other methods know that this is the place to look. For example,
859    // with FCFS, this method does nothing
860    if (readQueue.empty()) {
861        DPRINTF(DRAM, "No read request to select\n");
862        return false;
863    }
864
865    // If there is only one request then there is nothing left to do
866    if (readQueue.size() == 1)
867        return true;
868
869    if (memSchedPolicy == Enums::fcfs) {
870        // Do nothing, since the request to serve is already the first
871        // one in the read queue
872    } else if (memSchedPolicy == Enums::frfcfs) {
873        for (list<DRAMPacket*>::iterator i = readQueue.begin();
874             i != readQueue.end() ; ++i) {
875            DRAMPacket* dram_pkt = *i;
876            const Bank& bank = dram_pkt->bank_ref;
877            // Check if it is a row hit
878            if (bank.openRow == dram_pkt->row) { //FR part
879                DPRINTF(DRAM, "Row buffer hit\n");
880                readQueue.erase(i);
881                readQueue.push_front(dram_pkt);
882                break;
883            } else { //FCFS part
884                ;
885            }
886        }
887    } else
888        panic("No scheduling policy chosen!\n");
889
890    DPRINTF(DRAM, "Selected next read request\n");
891    return true;
892}
893
894void
895SimpleDRAM::accessAndRespond(PacketPtr pkt, Tick static_latency)
896{
897    DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr());
898
899    bool needsResponse = pkt->needsResponse();
900    // do the actual memory access which also turns the packet into a
901    // response
902    access(pkt);
903
904    // turn packet around to go back to requester if response expected
905    if (needsResponse) {
906        // access already turned the packet into a response
907        assert(pkt->isResponse());
908
909        // @todo someone should pay for this
910        pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
911
912        // queue the packet in the response queue to be sent out after
913        // the static latency has passed
914        port.schedTimingResp(pkt, curTick() + static_latency);
915    } else {
916        // @todo the packet is going to be deleted, and the DRAMPacket
917        // is still having a pointer to it
918        pendingDelete.push_back(pkt);
919    }
920
921    DPRINTF(DRAM, "Done\n");
922
923    return;
924}
925
926pair<Tick, Tick>
927SimpleDRAM::estimateLatency(DRAMPacket* dram_pkt, Tick inTime)
928{
929    // If a request reaches a bank at tick 'inTime', how much time
930    // *after* that does it take to finish the request, depending
931    // on bank status and page open policy. Note that this method
932    // considers only the time taken for the actual read or write
933    // to complete, NOT any additional time thereafter for tRAS or
934    // tRP.
935    Tick accLat = 0;
936    Tick bankLat = 0;
937    rowHitFlag = false;
938
939    const Bank& bank = dram_pkt->bank_ref;
940    if (pageMgmt == Enums::open) { // open-page policy
941        if (bank.openRow == dram_pkt->row) {
942            // When we have a row-buffer hit,
943            // we don't care about tRAS having expired or not,
944            // but do care about bank being free for access
945            rowHitFlag = true;
946
947            if (bank.freeAt < inTime) {
948               // CAS latency only
949               accLat += tCL;
950               bankLat += tCL;
951            } else {
952                accLat += 0;
953                bankLat += 0;
954            }
955
956        } else {
957            // Row-buffer miss, need to close existing row
958            // once tRAS has expired, then open the new one,
959            // then add cas latency.
960            Tick freeTime = std::max(bank.tRASDoneAt, bank.freeAt);
961
962            if (freeTime > inTime)
963               accLat += freeTime - inTime;
964
965            accLat += tRP + tRCD + tCL;
966            bankLat += tRP + tRCD + tCL;
967        }
968    } else if (pageMgmt == Enums::close) {
969        // With a close page policy, no notion of
970        // bank.tRASDoneAt
971        if (bank.freeAt > inTime)
972            accLat += bank.freeAt - inTime;
973
974        // page already closed, simply open the row, and
975        // add cas latency
976        accLat += tRCD + tCL;
977        bankLat += tRCD + tCL;
978    } else
979        panic("No page management policy chosen\n");
980
981    DPRINTF(DRAM, "Returning < %lld, %lld > from estimateLatency()\n",
982            bankLat, accLat);
983
984    return make_pair(bankLat, accLat);
985}
986
987void
988SimpleDRAM::processNextReqEvent()
989{
990    scheduleNextReq();
991}
992
993void
994SimpleDRAM::recordActivate(Tick act_tick)
995{
996    assert(actTicks.size() == activationLimit);
997
998    DPRINTF(DRAM, "Activate at tick %d\n", act_tick);
999
1000    // if the activation limit is disabled then we are done
1001    if (actTicks.empty())
1002        return;
1003
1004    // sanity check
1005    if (actTicks.back() && (act_tick - actTicks.back()) < tXAW) {
1006        // @todo For now, stick with a warning
1007        warn("Got %d activates in window %d (%d - %d) which is smaller "
1008             "than %d\n", activationLimit, act_tick - actTicks.back(),
1009             act_tick, actTicks.back(), tXAW);
1010    }
1011
1012    // shift the times used for the book keeping, the last element
1013    // (highest index) is the oldest one and hence the lowest value
1014    actTicks.pop_back();
1015
1016    // record an new activation (in the future)
1017    actTicks.push_front(act_tick);
1018
1019    // cannot activate more than X times in time window tXAW, push the
1020    // next one (the X + 1'st activate) to be tXAW away from the
1021    // oldest in our window of X
1022    if (actTicks.back() && (act_tick - actTicks.back()) < tXAW) {
1023        DPRINTF(DRAM, "Enforcing tXAW with X = %d, next activate no earlier "
1024                "than %d\n", activationLimit, actTicks.back() + tXAW);
1025        for(int i = 0; i < ranksPerChannel; i++)
1026            for(int j = 0; j < banksPerRank; j++)
1027                // next activate must not happen before end of window
1028                banks[i][j].freeAt = std::max(banks[i][j].freeAt,
1029                                              actTicks.back() + tXAW);
1030    }
1031}
1032
1033void
1034SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
1035{
1036
1037    DPRINTF(DRAM, "Timing access to addr %lld, rank/bank/row %d %d %d\n",
1038            dram_pkt->addr, dram_pkt->rank, dram_pkt->bank, dram_pkt->row);
1039
1040    // estimate the bank and access latency
1041    pair<Tick, Tick> lat = estimateLatency(dram_pkt, curTick());
1042    Tick bankLat = lat.first;
1043    Tick accessLat = lat.second;
1044
1045    // This request was woken up at this time based on a prior call
1046    // to estimateLatency(). However, between then and now, both the
1047    // accessLatency and/or busBusyUntil may have changed. We need
1048    // to correct for that.
1049
1050    Tick addDelay = (curTick() + accessLat < busBusyUntil) ?
1051        busBusyUntil - (curTick() + accessLat) : 0;
1052
1053    Bank& bank = dram_pkt->bank_ref;
1054
1055    // Update bank state
1056    if (pageMgmt == Enums::open) {
1057        bank.openRow = dram_pkt->row;
1058        bank.freeAt = curTick() + addDelay + accessLat;
1059        bank.bytesAccessed += burstSize;
1060
1061        // If you activated a new row do to this access, the next access
1062        // will have to respect tRAS for this bank. Assume tRAS ~= 3 * tRP.
1063        // Also need to account for t_XAW
1064        if (!rowHitFlag) {
1065            bank.tRASDoneAt = bank.freeAt + tRP;
1066            recordActivate(bank.freeAt - tCL - tRCD); //since this is open page,
1067                                                      //no tRP by default
1068            // sample the number of bytes accessed and reset it as
1069            // we are now closing this row
1070            bytesPerActivate.sample(bank.bytesAccessed);
1071            bank.bytesAccessed = 0;
1072        }
1073    } else if (pageMgmt == Enums::close) { // accounting for tRAS also
1074        // assuming that tRAS ~= 3 * tRP, and tRC ~= 4 * tRP, as is common
1075        // (refer Jacob/Ng/Wang and Micron datasheets)
1076        bank.freeAt = curTick() + addDelay + accessLat + tRP + tRP;
1077        recordActivate(bank.freeAt - tRP - tRP - tCL - tRCD); //essentially (freeAt - tRC)
1078        DPRINTF(DRAM,"doDRAMAccess::bank.freeAt is %lld\n",bank.freeAt);
1079        bytesPerActivate.sample(burstSize);
1080    } else
1081        panic("No page management policy chosen\n");
1082
1083    // Update request parameters
1084    dram_pkt->readyTime = curTick() + addDelay + accessLat + tBURST;
1085
1086
1087    DPRINTF(DRAM, "Req %lld: curtick is %lld accessLat is %d " \
1088                  "readytime is %lld busbusyuntil is %lld. " \
1089                  "Scheduling at readyTime\n", dram_pkt->addr,
1090                   curTick(), accessLat, dram_pkt->readyTime, busBusyUntil);
1091
1092    // Make sure requests are not overlapping on the databus
1093    assert (dram_pkt->readyTime - busBusyUntil >= tBURST);
1094
1095    // Update bus state
1096    busBusyUntil = dram_pkt->readyTime;
1097
1098    DPRINTF(DRAM,"Access time is %lld\n",
1099            dram_pkt->readyTime - dram_pkt->entryTime);
1100
1101    // Update stats
1102    totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime;
1103    totBankLat += bankLat;
1104    totBusLat += tBURST;
1105    totQLat += dram_pkt->readyTime - dram_pkt->entryTime - bankLat - tBURST;
1106
1107    if (rowHitFlag)
1108        readRowHits++;
1109
1110    // At this point we're done dealing with the request
1111    // It will be moved to a separate response queue with a
1112    // correct readyTime, and eventually be sent back at that
1113    //time
1114    moveToRespQ();
1115
1116    // The absolute soonest you have to start thinking about the
1117    // next request is the longest access time that can occur before
1118    // busBusyUntil. Assuming you need to meet tRAS, then precharge,
1119    // open a new row, and access, it is ~4*tRCD.
1120
1121
1122    Tick newTime = (busBusyUntil > 4 * tRCD) ?
1123                   std::max(busBusyUntil - 4 * tRCD, curTick()) :
1124                   curTick();
1125
1126    if (!nextReqEvent.scheduled() && !stopReads){
1127        schedule(nextReqEvent, newTime);
1128    } else {
1129        if (newTime < nextReqEvent.when())
1130            reschedule(nextReqEvent, newTime);
1131    }
1132
1133
1134}
1135
1136void
1137SimpleDRAM::moveToRespQ()
1138{
1139    // Remove from read queue
1140    DRAMPacket* dram_pkt = readQueue.front();
1141    readQueue.pop_front();
1142
1143    // sanity check
1144    assert(dram_pkt->size <= burstSize);
1145
1146    // Insert into response queue sorted by readyTime
1147    // It will be sent back to the requestor at its
1148    // readyTime
1149    if (respQueue.empty()) {
1150        respQueue.push_front(dram_pkt);
1151        assert(!respondEvent.scheduled());
1152        assert(dram_pkt->readyTime >= curTick());
1153        schedule(respondEvent, dram_pkt->readyTime);
1154    } else {
1155        bool done = false;
1156        list<DRAMPacket*>::iterator i = respQueue.begin();
1157        while (!done && i != respQueue.end()) {
1158            if ((*i)->readyTime > dram_pkt->readyTime) {
1159                respQueue.insert(i, dram_pkt);
1160                done = true;
1161            }
1162            ++i;
1163        }
1164
1165        if (!done)
1166            respQueue.push_back(dram_pkt);
1167
1168        assert(respondEvent.scheduled());
1169
1170        if (respQueue.front()->readyTime < respondEvent.when()) {
1171            assert(respQueue.front()->readyTime >= curTick());
1172            reschedule(respondEvent, respQueue.front()->readyTime);
1173        }
1174    }
1175}
1176
1177void
1178SimpleDRAM::scheduleNextReq()
1179{
1180    DPRINTF(DRAM, "Reached scheduleNextReq()\n");
1181
1182    // Figure out which read request goes next, and move it to the
1183    // front of the read queue
1184    if (!chooseNextRead()) {
1185        // In the case there is no read request to go next, see if we
1186        // are asked to drain, and if so trigger writes, this also
1187        // ensures that if we hit the write limit we will do this
1188        // multiple times until we are completely drained
1189        if (drainManager && !writeQueue.empty() && !writeEvent.scheduled())
1190            triggerWrites();
1191    } else {
1192        doDRAMAccess(readQueue.front());
1193    }
1194}
1195
1196Tick
1197SimpleDRAM::maxBankFreeAt() const
1198{
1199    Tick banksFree = 0;
1200
1201    for(int i = 0; i < ranksPerChannel; i++)
1202        for(int j = 0; j < banksPerRank; j++)
1203            banksFree = std::max(banks[i][j].freeAt, banksFree);
1204
1205    return banksFree;
1206}
1207
1208void
1209SimpleDRAM::processRefreshEvent()
1210{
1211    DPRINTF(DRAM, "Refreshing at tick %ld\n", curTick());
1212
1213    Tick banksFree = std::max(curTick(), maxBankFreeAt()) + tRFC;
1214
1215    for(int i = 0; i < ranksPerChannel; i++)
1216        for(int j = 0; j < banksPerRank; j++)
1217            banks[i][j].freeAt = banksFree;
1218
1219    schedule(refreshEvent, curTick() + tREFI);
1220}
1221
1222void
1223SimpleDRAM::regStats()
1224{
1225    using namespace Stats;
1226
1227    AbstractMemory::regStats();
1228
1229    readReqs
1230        .name(name() + ".readReqs")
1231        .desc("Total number of read requests accepted by DRAM controller");
1232
1233    writeReqs
1234        .name(name() + ".writeReqs")
1235        .desc("Total number of write requests accepted by DRAM controller");
1236
1237    readBursts
1238        .name(name() + ".readBursts")
1239        .desc("Total number of DRAM read bursts. "
1240              "Each DRAM read request translates to either one or multiple "
1241              "DRAM read bursts");
1242
1243    writeBursts
1244        .name(name() + ".writeBursts")
1245        .desc("Total number of DRAM write bursts. "
1246              "Each DRAM write request translates to either one or multiple "
1247              "DRAM write bursts");
1248
1249    servicedByWrQ
1250        .name(name() + ".servicedByWrQ")
1251        .desc("Number of DRAM read bursts serviced by write Q");
1252
1253    neitherReadNorWrite
1254        .name(name() + ".neitherReadNorWrite")
1255        .desc("Reqs where no action is needed");
1256
1257    perBankRdReqs
1258        .init(banksPerRank * ranksPerChannel)
1259        .name(name() + ".perBankRdReqs")
1260        .desc("Track reads on a per bank basis");
1261
1262    perBankWrReqs
1263        .init(banksPerRank * ranksPerChannel)
1264        .name(name() + ".perBankWrReqs")
1265        .desc("Track writes on a per bank basis");
1266
1267    avgRdQLen
1268        .name(name() + ".avgRdQLen")
1269        .desc("Average read queue length over time")
1270        .precision(2);
1271
1272    avgWrQLen
1273        .name(name() + ".avgWrQLen")
1274        .desc("Average write queue length over time")
1275        .precision(2);
1276
1277    totQLat
1278        .name(name() + ".totQLat")
1279        .desc("Total cycles spent in queuing delays");
1280
1281    totBankLat
1282        .name(name() + ".totBankLat")
1283        .desc("Total cycles spent in bank access");
1284
1285    totBusLat
1286        .name(name() + ".totBusLat")
1287        .desc("Total cycles spent in databus access");
1288
1289    totMemAccLat
1290        .name(name() + ".totMemAccLat")
1291        .desc("Sum of mem lat for all requests");
1292
1293    avgQLat
1294        .name(name() + ".avgQLat")
1295        .desc("Average queueing delay per request")
1296        .precision(2);
1297
1298    avgQLat = totQLat / (readBursts - servicedByWrQ);
1299
1300    avgBankLat
1301        .name(name() + ".avgBankLat")
1302        .desc("Average bank access latency per request")
1303        .precision(2);
1304
1305    avgBankLat = totBankLat / (readBursts - servicedByWrQ);
1306
1307    avgBusLat
1308        .name(name() + ".avgBusLat")
1309        .desc("Average bus latency per request")
1310        .precision(2);
1311
1312    avgBusLat = totBusLat / (readBursts - servicedByWrQ);
1313
1314    avgMemAccLat
1315        .name(name() + ".avgMemAccLat")
1316        .desc("Average memory access latency")
1317        .precision(2);
1318
1319    avgMemAccLat = totMemAccLat / (readBursts - servicedByWrQ);
1320
1321    numRdRetry
1322        .name(name() + ".numRdRetry")
1323        .desc("Number of times rd buffer was full causing retry");
1324
1325    numWrRetry
1326        .name(name() + ".numWrRetry")
1327        .desc("Number of times wr buffer was full causing retry");
1328
1329    readRowHits
1330        .name(name() + ".readRowHits")
1331        .desc("Number of row buffer hits during reads");
1332
1333    writeRowHits
1334        .name(name() + ".writeRowHits")
1335        .desc("Number of row buffer hits during writes");
1336
1337    readRowHitRate
1338        .name(name() + ".readRowHitRate")
1339        .desc("Row buffer hit rate for reads")
1340        .precision(2);
1341
1342    readRowHitRate = (readRowHits / (readBursts - servicedByWrQ)) * 100;
1343
1344    writeRowHitRate
1345        .name(name() + ".writeRowHitRate")
1346        .desc("Row buffer hit rate for writes")
1347        .precision(2);
1348
1349    writeRowHitRate = (writeRowHits / writeBursts) * 100;
1350
1351    readPktSize
1352        .init(ceilLog2(burstSize) + 1)
1353        .name(name() + ".readPktSize")
1354        .desc("Categorize read packet sizes");
1355
1356     writePktSize
1357        .init(ceilLog2(burstSize) + 1)
1358        .name(name() + ".writePktSize")
1359        .desc("Categorize write packet sizes");
1360
1361     rdQLenPdf
1362        .init(readBufferSize)
1363        .name(name() + ".rdQLenPdf")
1364        .desc("What read queue length does an incoming req see");
1365
1366     wrQLenPdf
1367        .init(writeBufferSize)
1368        .name(name() + ".wrQLenPdf")
1369        .desc("What write queue length does an incoming req see");
1370
1371     bytesPerActivate
1372         .init(rowBufferSize)
1373         .name(name() + ".bytesPerActivate")
1374         .desc("Bytes accessed per row activation")
1375         .flags(nozero);
1376
1377    bytesRead
1378        .name(name() + ".bytesRead")
1379        .desc("Total number of bytes read from memory");
1380
1381    bytesWritten
1382        .name(name() + ".bytesWritten")
1383        .desc("Total number of bytes written to memory");
1384
1385    bytesConsumedRd
1386        .name(name() + ".bytesConsumedRd")
1387        .desc("bytesRead derated as per pkt->getSize()");
1388
1389    bytesConsumedWr
1390        .name(name() + ".bytesConsumedWr")
1391        .desc("bytesWritten derated as per pkt->getSize()");
1392
1393    avgRdBW
1394        .name(name() + ".avgRdBW")
1395        .desc("Average achieved read bandwidth in MB/s")
1396        .precision(2);
1397
1398    avgRdBW = (bytesRead / 1000000) / simSeconds;
1399
1400    avgWrBW
1401        .name(name() + ".avgWrBW")
1402        .desc("Average achieved write bandwidth in MB/s")
1403        .precision(2);
1404
1405    avgWrBW = (bytesWritten / 1000000) / simSeconds;
1406
1407    avgConsumedRdBW
1408        .name(name() + ".avgConsumedRdBW")
1409        .desc("Average consumed read bandwidth in MB/s")
1410        .precision(2);
1411
1412    avgConsumedRdBW = (bytesConsumedRd / 1000000) / simSeconds;
1413
1414    avgConsumedWrBW
1415        .name(name() + ".avgConsumedWrBW")
1416        .desc("Average consumed write bandwidth in MB/s")
1417        .precision(2);
1418
1419    avgConsumedWrBW = (bytesConsumedWr / 1000000) / simSeconds;
1420
1421    peakBW
1422        .name(name() + ".peakBW")
1423        .desc("Theoretical peak bandwidth in MB/s")
1424        .precision(2);
1425
1426    peakBW = (SimClock::Frequency / tBURST) * burstSize / 1000000;
1427
1428    busUtil
1429        .name(name() + ".busUtil")
1430        .desc("Data bus utilization in percentage")
1431        .precision(2);
1432
1433    busUtil = (avgRdBW + avgWrBW) / peakBW * 100;
1434
1435    totGap
1436        .name(name() + ".totGap")
1437        .desc("Total gap between requests");
1438
1439    avgGap
1440        .name(name() + ".avgGap")
1441        .desc("Average gap between requests")
1442        .precision(2);
1443
1444    avgGap = totGap / (readReqs + writeReqs);
1445}
1446
1447void
1448SimpleDRAM::recvFunctional(PacketPtr pkt)
1449{
1450    // rely on the abstract memory
1451    functionalAccess(pkt);
1452}
1453
1454BaseSlavePort&
1455SimpleDRAM::getSlavePort(const string &if_name, PortID idx)
1456{
1457    if (if_name != "port") {
1458        return MemObject::getSlavePort(if_name, idx);
1459    } else {
1460        return port;
1461    }
1462}
1463
1464unsigned int
1465SimpleDRAM::drain(DrainManager *dm)
1466{
1467    unsigned int count = port.drain(dm);
1468
1469    // if there is anything in any of our internal queues, keep track
1470    // of that as well
1471    if (!(writeQueue.empty() && readQueue.empty() &&
1472          respQueue.empty())) {
1473        DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d,"
1474                " resp: %d\n", writeQueue.size(), readQueue.size(),
1475                respQueue.size());
1476        ++count;
1477        drainManager = dm;
1478        // the only part that is not drained automatically over time
1479        // is the write queue, thus trigger writes if there are any
1480        // waiting and no reads waiting, otherwise wait until the
1481        // reads are done
1482        if (readQueue.empty() && !writeQueue.empty() &&
1483            !writeEvent.scheduled())
1484            triggerWrites();
1485    }
1486
1487    if (count)
1488        setDrainState(Drainable::Draining);
1489    else
1490        setDrainState(Drainable::Drained);
1491    return count;
1492}
1493
1494SimpleDRAM::MemoryPort::MemoryPort(const std::string& name, SimpleDRAM& _memory)
1495    : QueuedSlavePort(name, &_memory, queue), queue(_memory, *this),
1496      memory(_memory)
1497{ }
1498
1499AddrRangeList
1500SimpleDRAM::MemoryPort::getAddrRanges() const
1501{
1502    AddrRangeList ranges;
1503    ranges.push_back(memory.getAddrRange());
1504    return ranges;
1505}
1506
1507void
1508SimpleDRAM::MemoryPort::recvFunctional(PacketPtr pkt)
1509{
1510    pkt->pushLabel(memory.name());
1511
1512    if (!queue.checkFunctional(pkt)) {
1513        // Default implementation of SimpleTimingPort::recvFunctional()
1514        // calls recvAtomic() and throws away the latency; we can save a
1515        // little here by just not calculating the latency.
1516        memory.recvFunctional(pkt);
1517    }
1518
1519    pkt->popLabel();
1520}
1521
1522Tick
1523SimpleDRAM::MemoryPort::recvAtomic(PacketPtr pkt)
1524{
1525    return memory.recvAtomic(pkt);
1526}
1527
1528bool
1529SimpleDRAM::MemoryPort::recvTimingReq(PacketPtr pkt)
1530{
1531    // pass it to the memory controller
1532    return memory.recvTimingReq(pkt);
1533}
1534
1535SimpleDRAM*
1536SimpleDRAMParams::create()
1537{
1538    return new SimpleDRAM(this);
1539}
1540