dram_ctrl.cc revision 9488
16157Snate@binkert.org/*
26157Snate@binkert.org * Copyright (c) 2010-2012 ARM Limited
36157Snate@binkert.org * All rights reserved
46157Snate@binkert.org *
56157Snate@binkert.org * The license below extends only to copyright in the software and shall
66157Snate@binkert.org * not be construed as granting a license to any other intellectual
76157Snate@binkert.org * property including but not limited to intellectual property relating
86157Snate@binkert.org * to a hardware implementation of the functionality of the software
96157Snate@binkert.org * licensed hereunder.  You may use the software subject to the license
106157Snate@binkert.org * terms below provided that you ensure that this notice is replicated
116157Snate@binkert.org * unmodified and in its entirety in all distributions of the software,
126157Snate@binkert.org * modified or unmodified, in source code or in binary form.
136157Snate@binkert.org *
146157Snate@binkert.org * Redistribution and use in source and binary forms, with or without
156157Snate@binkert.org * modification, are permitted provided that the following conditions are
166157Snate@binkert.org * met: redistributions of source code must retain the above copyright
176157Snate@binkert.org * notice, this list of conditions and the following disclaimer;
186157Snate@binkert.org * redistributions in binary form must reproduce the above copyright
196157Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
206157Snate@binkert.org * documentation and/or other materials provided with the distribution;
216157Snate@binkert.org * neither the name of the copyright holders nor the names of its
226157Snate@binkert.org * contributors may be used to endorse or promote products derived from
236157Snate@binkert.org * this software without specific prior written permission.
246157Snate@binkert.org *
256157Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
266157Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
276157Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
286157Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
296157Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
306157Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
316157Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
326157Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
338492Snilay@cs.wisc.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
346168Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
356168Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
368439Snilay@cs.wisc.edu *
376876Ssteve.reinhardt@amd.com * Authors: Andreas Hansson
388439Snilay@cs.wisc.edu *          Ani Udipi
396876Ssteve.reinhardt@amd.com */
408191SLisa.Hsu@amd.com
416876Ssteve.reinhardt@amd.com#include "base/trace.hh"
429102SNuwan.Jayasena@amd.com#include "debug/Drain.hh"
436876Ssteve.reinhardt@amd.com#include "debug/DRAM.hh"
446286Snate@binkert.org#include "debug/DRAMWR.hh"
456157Snate@binkert.org#include "mem/simple_dram.hh"
467025SBrad.Beckmann@amd.com#include "sim/stat_control.hh"
476782SBrad.Beckmann@amd.com
486157Snate@binkert.orgusing namespace std;
498191SLisa.Hsu@amd.com
509102SNuwan.Jayasena@amd.comSimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
516157Snate@binkert.org    AbstractMemory(p),
526797SBrad.Beckmann@amd.com    port(name() + ".port", *this),
536286Snate@binkert.org    retryRdReq(false), retryWrReq(false),
548706Sandreas.hansson@arm.com    rowHitFlag(false), stopReads(false), actTicks(p->activation_limit, 0),
558641Snate@binkert.org    writeEvent(this), respondEvent(this),
566157Snate@binkert.org    refreshEvent(this), nextReqEvent(this), drainManager(NULL),
576157Snate@binkert.org    bytesPerCacheLine(0),
589105SBrad.Beckmann@amd.com    linesPerRowBuffer(p->lines_per_rowbuffer),
59    ranksPerChannel(p->ranks_per_channel),
60    banksPerRank(p->banks_per_rank), rowsPerBank(0),
61    readBufferSize(p->read_buffer_size),
62    writeBufferSize(p->write_buffer_size),
63    writeThresholdPerc(p->write_thresh_perc),
64    tWTR(p->tWTR), tBURST(p->tBURST),
65    tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP),
66    tRFC(p->tRFC), tREFI(p->tREFI),
67    tXAW(p->tXAW), activationLimit(p->activation_limit),
68    memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping),
69    pageMgmt(p->page_policy),
70    busBusyUntil(0), prevdramaccess(0), writeStartTime(0),
71    prevArrival(0), numReqs(0)
72{
73    // create the bank states based on the dimensions of the ranks and
74    // banks
75    banks.resize(ranksPerChannel);
76    for (size_t c = 0; c < ranksPerChannel; ++c) {
77        banks[c].resize(banksPerRank);
78    }
79
80    // round the write threshold percent to a whole number of entries
81    // in the buffer
82    writeThreshold = writeBufferSize * writeThresholdPerc / 100.0;
83}
84
85void
86SimpleDRAM::init()
87{
88    if (!port.isConnected()) {
89        fatal("SimpleDRAM %s is unconnected!\n", name());
90    } else {
91        port.sendRangeChange();
92    }
93
94    // get the cache line size from the connected port
95    bytesPerCacheLine = port.peerBlockSize();
96
97    // we could deal with plenty options here, but for now do a quick
98    // sanity check
99    if (bytesPerCacheLine != 64 && bytesPerCacheLine != 32)
100        panic("Unexpected cache line size %d", bytesPerCacheLine);
101
102    // determine the rows per bank by looking at the total capacity
103    uint64_t capacity = AbstractMemory::size();
104    uint64_t i = 1;
105    while (i < 64 && capacity > ((1 << i))) {
106        ++i;
107    }
108
109    // rounded up to nearest power of two
110    DPRINTF(DRAM, "i is %lld\n", i);
111    capacity = 1 << i;
112
113    DPRINTF(DRAM, "Memory capacity %lld (%lld) bytes\n", capacity,
114            AbstractMemory::size());
115    rowsPerBank = capacity / (bytesPerCacheLine * linesPerRowBuffer *
116                              banksPerRank * ranksPerChannel);
117
118}
119
120void
121SimpleDRAM::startup()
122{
123    // print the configuration of the controller
124    printParams();
125
126    // kick off the refresh
127    schedule(&refreshEvent, curTick() + tREFI);
128}
129
130
131Tick
132SimpleDRAM::recvAtomic(PacketPtr pkt)
133{
134    DPRINTF(DRAM, "recvAtomic: %s 0x%x\n", pkt->cmdString(), pkt->getAddr());
135
136    // do the actual memory access and turn the packet into a response
137    access(pkt);
138
139    Tick latency = 0;
140    if (!pkt->memInhibitAsserted() && pkt->hasData()) {
141        // this value is not supposed to be accurate, just enough to
142        // keep things going, mimic a closed page
143        latency = tRP + tRCD + tCL;
144    }
145    return latency;
146}
147
148bool
149SimpleDRAM::readQueueFull() const
150{
151    DPRINTF(DRAM, "Read queue limit %d current size %d\n",
152            readBufferSize, dramReadQueue.size() + dramRespQueue.size());
153
154    return (dramReadQueue.size() + dramRespQueue.size()) == readBufferSize;
155}
156
157bool
158SimpleDRAM::writeQueueFull() const
159{
160    DPRINTF(DRAM, "Write queue limit %d current size %d\n",
161            writeBufferSize, dramWriteQueue.size());
162    return dramWriteQueue.size() == writeBufferSize;
163}
164
165
166SimpleDRAM::DRAMPacket*
167SimpleDRAM::decodeAddr(PacketPtr pkt)
168{
169    uint8_t rank;
170    uint16_t bank;
171    uint16_t row;
172
173    Addr addr = pkt->getAddr();
174    Addr temp = addr;
175
176    // truncate the address to the access granularity
177    addr = addr / bytesPerCacheLine;
178
179    if (addrMapping == Enums::openmap) {
180        addr = addr / linesPerRowBuffer;
181
182        bank = addr % banksPerRank;
183        addr = addr / banksPerRank;
184
185        rank = addr % ranksPerChannel;
186        addr = addr / ranksPerChannel;
187
188        row = addr % rowsPerBank;
189        addr = addr / rowsPerBank;
190    } else if (addrMapping == Enums::closemap) {
191        bank = addr % banksPerRank;
192        addr = addr / banksPerRank;
193
194        rank = addr % ranksPerChannel;
195        addr = addr / ranksPerChannel;
196
197        addr = addr / linesPerRowBuffer;
198
199        row = addr % rowsPerBank;
200        addr = addr / rowsPerBank;
201    } else
202        panic("Unknown address mapping policy chosen!");
203
204    assert(rank < ranksPerChannel);
205    assert(bank < banksPerRank);
206    assert(row < rowsPerBank);
207
208    DPRINTF(DRAM, "Address: %lld Rank %d Bank %d Row %d\n",
209            temp, rank, bank, row);
210
211    // create the corresponding DRAM packet with the entry time and
212    // ready time set to the current tick, they will be updated later
213    DRAMPacket* dram_pkt = new DRAMPacket(pkt, rank, bank, row, temp,
214                                          banks[rank][bank]);
215
216    return dram_pkt;
217}
218
219void
220SimpleDRAM::addToReadQueue(PacketPtr pkt)
221{
222    // only add to the read queue here. whenever the request is
223    // eventually done, set the readyTime, and call schedule()
224    assert(!pkt->isWrite());
225
226    // First check write buffer to see if the data is already at
227    // the controller
228    std::list<DRAMPacket*>::const_iterator i;
229    Addr addr = pkt->getAddr();
230
231    // @todo: add size check
232    for (i = dramWriteQueue.begin();  i != dramWriteQueue.end(); ++i) {
233        if ((*i)->addr == addr){
234            servicedByWrQ++;
235            DPRINTF(DRAM,"Serviced by write Q\n");
236            bytesRead += bytesPerCacheLine;
237            bytesConsumedRd += pkt->getSize();
238            accessAndRespond(pkt);
239            return;
240        }
241    }
242
243    DRAMPacket* dram_pkt = decodeAddr(pkt);
244
245    assert(dramReadQueue.size() + dramRespQueue.size() < readBufferSize);
246    rdQLenPdf[dramReadQueue.size() + dramRespQueue.size()]++;
247
248    DPRINTF(DRAM, "Adding to read queue\n");
249
250    dramReadQueue.push_back(dram_pkt);
251
252    // Update stats
253    uint32_t bank_id = banksPerRank * dram_pkt->rank + dram_pkt->bank;
254    assert(bank_id < ranksPerChannel * banksPerRank);
255    perBankRdReqs[bank_id]++;
256
257    avgRdQLen = dramReadQueue.size() + dramRespQueue.size();
258
259    // Special case where no arbitration is required between requests
260    if (!nextReqEvent.scheduled() && !stopReads) {
261        DPRINTF(DRAM, "Request %lld - need to schedule immediately");
262        schedule(&nextReqEvent, curTick() + 1);
263    }
264}
265
266void
267SimpleDRAM::processWriteEvent()
268{
269    assert(!dramWriteQueue.empty());
270    uint32_t numWritesThisTime = 0;
271
272    DPRINTF(DRAMWR, "Beginning DRAM Writes\n");
273    Tick temp1 M5_VAR_USED = std::max(curTick(), busBusyUntil);
274    Tick temp2 M5_VAR_USED = std::max(curTick(), maxBankFreeAt());
275
276    // @todo: are there any dangers with the untimed while loop?
277    while (!dramWriteQueue.empty()) {
278        if (numWritesThisTime > writeThreshold)
279            break;
280
281        chooseNextWrite();
282        DRAMPacket* dram_pkt = dramWriteQueue.front();
283        // What's the earlier the request can be put on the bus
284        Tick schedTime = std::max(curTick(), busBusyUntil);
285
286        DPRINTF(DRAMWR, "Asking for latency estimate at %lld\n",
287                schedTime + tBURST);
288
289        pair<Tick, Tick> lat = estimateLatency(dram_pkt, schedTime + tBURST);
290        Tick accessLat = lat.second;
291
292        // look at the rowHitFlag set by estimateLatency
293
294        // @todo: Race condition here where another packet gives rise
295        // to another call to estimateLatency in the meanwhile?
296        if (rowHitFlag)
297            writeRowHits++;
298
299        Bank& bank = dram_pkt->bank_ref;
300
301        if (pageMgmt == Enums::open) {
302            bank.openRow = dram_pkt->row;
303            bank.freeAt = schedTime + tBURST + std::max(accessLat, tCL);
304            busBusyUntil = bank.freeAt - tCL;
305
306            if (!rowHitFlag) {
307                bank.tRASDoneAt = bank.freeAt + tRP;
308                recordActivate(bank.freeAt - tCL - tRCD);
309                busBusyUntil = bank.freeAt - tCL - tRCD;
310            }
311        } else if (pageMgmt == Enums::close) {
312            bank.freeAt = schedTime + tBURST + accessLat + tRP + tRP;
313            // Work backwards from bank.freeAt to determine activate time
314            recordActivate(bank.freeAt - tRP - tRP - tCL - tRCD);
315            busBusyUntil = bank.freeAt - tRP - tRP - tCL - tRCD;
316            DPRINTF(DRAMWR, "processWriteEvent::bank.freeAt for "
317                    "banks_id %d is %lld\n",
318                    dram_pkt->rank * banksPerRank + dram_pkt->bank,
319                    bank.freeAt);
320        } else
321            panic("Unknown page management policy chosen\n");
322
323        DPRINTF(DRAMWR,"Done writing to address %lld\n",dram_pkt->addr);
324
325        DPRINTF(DRAMWR,"schedtime is %lld, tBURST is %lld, "
326                "busbusyuntil is %lld\n",
327                schedTime, tBURST, busBusyUntil);
328
329        dramWriteQueue.pop_front();
330        delete dram_pkt;
331
332        numWritesThisTime++;
333    }
334
335    DPRINTF(DRAMWR, "Completed %d writes, bus busy for %lld ticks,"\
336            "banks busy for %lld ticks\n", numWritesThisTime,
337            busBusyUntil - temp1, maxBankFreeAt() - temp2);
338
339    // Update stats
340    avgWrQLen = dramWriteQueue.size();
341
342    // turn the bus back around for reads again
343    busBusyUntil += tWTR;
344    stopReads = false;
345
346    if (retryWrReq) {
347        retryWrReq = false;
348        port.sendRetry();
349    }
350
351    // if there is nothing left in any queue, signal a drain
352    if (dramWriteQueue.empty() && dramReadQueue.empty() &&
353        dramRespQueue.empty () && drainManager) {
354        drainManager->signalDrainDone();
355        drainManager = NULL;
356    }
357
358    // Once you're done emptying the write queue, check if there's
359    // anything in the read queue, and call schedule if required
360    schedule(&nextReqEvent, busBusyUntil);
361}
362
363void
364SimpleDRAM::triggerWrites()
365{
366    DPRINTF(DRAM, "Writes triggered at %lld\n", curTick());
367    // Flag variable to stop any more read scheduling
368    stopReads = true;
369
370    writeStartTime = std::max(busBusyUntil, curTick()) + tWTR;
371
372    DPRINTF(DRAM, "Writes scheduled at %lld\n", writeStartTime);
373
374    assert(writeStartTime >= curTick());
375    assert(!writeEvent.scheduled());
376    schedule(&writeEvent, writeStartTime);
377}
378
379void
380SimpleDRAM::addToWriteQueue(PacketPtr pkt)
381{
382    // only add to the write queue here. whenever the request is
383    // eventually done, set the readyTime, and call schedule()
384    assert(pkt->isWrite());
385
386    DRAMPacket* dram_pkt = decodeAddr(pkt);
387
388    assert(dramWriteQueue.size() < writeBufferSize);
389    wrQLenPdf[dramWriteQueue.size()]++;
390
391    DPRINTF(DRAM, "Adding to write queue\n");
392
393    dramWriteQueue.push_back(dram_pkt);
394
395    // Update stats
396    uint32_t bank_id = banksPerRank * dram_pkt->rank + dram_pkt->bank;
397    assert(bank_id < ranksPerChannel * banksPerRank);
398    perBankWrReqs[bank_id]++;
399
400    avgWrQLen = dramWriteQueue.size();
401
402    // we do not wait for the writes to be send to the actual memory,
403    // but instead take responsibility for the consistency here and
404    // snoop the write queue for any upcoming reads
405
406    bytesConsumedWr += pkt->getSize();
407    bytesWritten += bytesPerCacheLine;
408    accessAndRespond(pkt);
409
410    // If your write buffer is starting to fill up, drain it!
411    if (dramWriteQueue.size() > writeThreshold  && !stopReads){
412        triggerWrites();
413    }
414}
415
416void
417SimpleDRAM::printParams() const
418{
419    // Sanity check print of important parameters
420    DPRINTF(DRAM,
421            "Memory controller %s physical organization\n"      \
422            "Bytes per cacheline  %d\n"                         \
423            "Lines per row buffer %d\n"                         \
424            "Rows  per bank       %d\n"                         \
425            "Banks per rank       %d\n"                         \
426            "Ranks per channel    %d\n"                         \
427            "Total mem capacity   %u\n",
428            name(), bytesPerCacheLine ,linesPerRowBuffer, rowsPerBank,
429            banksPerRank, ranksPerChannel, bytesPerCacheLine *
430            linesPerRowBuffer * rowsPerBank * banksPerRank * ranksPerChannel);
431
432    string scheduler =  memSchedPolicy == Enums::fcfs ? "FCFS" : "FR-FCFS";
433    string address_mapping = addrMapping == Enums::openmap ? "OPENMAP" :
434        "CLOSEMAP";
435    string page_policy = pageMgmt == Enums::open ? "OPEN" : "CLOSE";
436
437    DPRINTF(DRAM,
438            "Memory controller %s characteristics\n"    \
439            "Read buffer size     %d\n"                 \
440            "Write buffer size    %d\n"                 \
441            "Write buffer thresh  %d\n"                 \
442            "Scheduler            %s\n"                 \
443            "Address mapping      %s\n"                 \
444            "Page policy          %s\n",
445            name(), readBufferSize, writeBufferSize, writeThreshold,
446            scheduler, address_mapping, page_policy);
447
448    DPRINTF(DRAM, "Memory controller %s timing specs\n" \
449            "tRCD    %d ticks\n"                        \
450            "tCL     %d ticks\n"                        \
451            "tRP     %d ticks\n"                        \
452            "tBURST  %d ticks\n"                        \
453            "tRFC    %d ticks\n"                        \
454            "tREFI   %d ticks\n"                        \
455            "tWTR    %d ticks\n",
456            name(), tRCD, tCL, tRP, tBURST, tRFC, tREFI, tWTR);
457}
458
459void
460SimpleDRAM::printQs() const {
461
462    list<DRAMPacket*>::const_iterator i;
463
464    DPRINTF(DRAM, "===READ QUEUE===\n\n");
465    for (i = dramReadQueue.begin() ;  i != dramReadQueue.end() ; ++i) {
466        DPRINTF(DRAM, "Read %lu\n", (*i)->addr);
467    }
468    DPRINTF(DRAM, "\n===RESP QUEUE===\n\n");
469    for (i = dramRespQueue.begin() ;  i != dramRespQueue.end() ; ++i) {
470        DPRINTF(DRAM, "Response %lu\n", (*i)->addr);
471    }
472    DPRINTF(DRAM, "\n===WRITE QUEUE===\n\n");
473    for (i = dramWriteQueue.begin() ;  i != dramWriteQueue.end() ; ++i) {
474        DPRINTF(DRAM, "Write %lu\n", (*i)->addr);
475    }
476}
477
478bool
479SimpleDRAM::recvTimingReq(PacketPtr pkt)
480{
481    /// @todo temporary hack to deal with memory corruption issues until
482    /// 4-phase transactions are complete
483    for (int x = 0; x < pendingDelete.size(); x++)
484        delete pendingDelete[x];
485    pendingDelete.clear();
486
487
488    // This is where we enter from the outside world
489    DPRINTF(DRAM, "Inside recvTimingReq: request %s addr %lld size %d\n",
490            pkt->cmdString(),pkt->getAddr(), pkt->getSize());
491
492   int index;
493
494   if (pkt->getSize() == bytesPerCacheLine)
495       cpuReqs++;
496
497   if (numReqs % 1000000 == 0)
498       printQs();
499
500    // Calc avg gap between requests
501    if (prevArrival != 0) {
502        totGap += curTick() - prevArrival;
503    }
504    prevArrival = curTick();
505
506    // simply drop inhibited packets for now
507    if (pkt->memInhibitAsserted()) {
508        DPRINTF(DRAM,"Inhibited packet -- Dropping it now\n");
509        pendingDelete.push_back(pkt);
510        return true;
511    }
512
513    unsigned size = pkt->getSize();
514    if (size > bytesPerCacheLine)
515        panic("Request size %d is greater than cache line size %d",
516              size, bytesPerCacheLine);
517
518    if (size == 0)
519        index = log2(bytesPerCacheLine) + 1;
520    else
521        index = log2(size);
522
523    if (size != 0 && (1 << index) != size)
524        index = log2(bytesPerCacheLine) + 2;
525
526    // @todo: Do we really want to do all this before the packet is
527    // actually accepted?
528
529    /* Index 0 - Size 1 byte
530       Index 1 - Size 2 bytes
531       Index 2 - Size 4 bytes
532         .
533         .
534       Index 6 - Size 64 bytes
535       Index 7 - Size 0 bytes
536       Index 8 - Non-power-of-2 size */
537
538    if (pkt->isRead())
539        readPktSize[index]++;
540    else if (pkt->isWrite())
541        writePktSize[index]++;
542    else
543        neitherPktSize[index]++;
544
545    // check local buffers and do not accept if full
546    if (pkt->isRead()) {
547        if (readQueueFull()) {
548            DPRINTF(DRAM,"Read queue full, not accepting\n");
549            // remember that we have to retry this port
550            retryRdReq = true;
551            numRdRetry++;
552            return false;
553        } else {
554            addToReadQueue(pkt);
555            readReqs++;
556            numReqs++;
557        }
558    } else if (pkt->isWrite()) {
559        if (writeQueueFull()) {
560            DPRINTF(DRAM,"Write queue full, not accepting\n");
561            // remember that we have to retry this port
562            retryWrReq = true;
563            numWrRetry++;
564            return false;
565        } else {
566            addToWriteQueue(pkt);
567            writeReqs++;
568            numReqs++;
569        }
570    } else {
571        DPRINTF(DRAM,"Neither read nor write, ignore timing\n");
572        neitherReadNorWrite++;
573        accessAndRespond(pkt);
574    }
575
576
577    retryRdReq = false;
578    retryWrReq = false;
579    return true;
580}
581
582void
583SimpleDRAM::processRespondEvent()
584{
585    DPRINTF(DRAM,
586            "processRespondEvent(): Some req has reached its readyTime\n");
587
588     PacketPtr pkt = dramRespQueue.front()->pkt;
589
590     // Actually responds to the requestor
591     bytesConsumedRd += pkt->getSize();
592     bytesRead += bytesPerCacheLine;
593     accessAndRespond(pkt);
594
595     DRAMPacket* dram_pkt = dramRespQueue.front();
596     dramRespQueue.pop_front();
597     delete dram_pkt;
598
599     // Update stats
600     avgRdQLen = dramReadQueue.size() + dramRespQueue.size();
601
602     if (!dramRespQueue.empty()){
603         assert(dramRespQueue.front()->readyTime >= curTick());
604         assert(!respondEvent.scheduled());
605         schedule(&respondEvent, dramRespQueue.front()->readyTime);
606     } else {
607         // if there is nothing left in any queue, signal a drain
608         if (dramWriteQueue.empty() && dramReadQueue.empty() &&
609             drainManager) {
610             drainManager->signalDrainDone();
611             drainManager = NULL;
612         }
613     }
614}
615
616void
617SimpleDRAM::chooseNextWrite()
618{
619    // This method does the arbitration between requests. The chosen
620    // packet is simply moved to the head of the queue. The other
621    // methods know that this is the place to look. For example, with
622    // FCFS, this method does nothing
623    assert(!dramWriteQueue.empty());
624
625    if (dramWriteQueue.size() == 1) {
626        DPRINTF(DRAMWR, "chooseNextWrite(): Single element, nothing to do\n");
627        return;
628    }
629
630    if (memSchedPolicy == Enums::fcfs) {
631
632        // Do nothing, since the correct request is already head
633
634    } else if (memSchedPolicy == Enums::frfcfs) {
635
636        list<DRAMPacket*>::iterator i = dramWriteQueue.begin();
637        bool foundRowHit = false;
638        while (!foundRowHit && i != dramWriteQueue.end()) {
639            DRAMPacket* dram_pkt = *i;
640            const Bank& bank = dram_pkt->bank_ref;
641            if (bank.openRow == dram_pkt->row) { //FR part
642                DPRINTF(DRAMWR,"Row buffer hit\n");
643                dramWriteQueue.erase(i);
644                dramWriteQueue.push_front(dram_pkt);
645                foundRowHit = true;
646            } else { //FCFS part
647                ;
648            }
649            ++i;
650        }
651
652    } else
653        panic("No scheduling policy chosen\n");
654
655    DPRINTF(DRAMWR, "chooseNextWrite(): Something chosen\n");
656}
657
658bool
659SimpleDRAM::chooseNextReq()
660{
661    // This method does the arbitration between requests.
662    // The chosen packet is simply moved to the head of the
663    // queue. The other methods know that this is the place
664    // to look. For example, with FCFS, this method does nothing
665    list<DRAMPacket*>::iterator i;
666    DRAMPacket* dram_pkt;
667
668    if (dramReadQueue.empty()){
669        DPRINTF(DRAM, "chooseNextReq(): Returning False\n");
670        return false;
671    }
672
673    if (dramReadQueue.size() == 1)
674        return true;
675
676    if (memSchedPolicy == Enums::fcfs) {
677
678        // Do nothing, since the correct request is already head
679
680    } else if (memSchedPolicy == Enums::frfcfs) {
681
682        for (i = dramReadQueue.begin() ; i != dramReadQueue.end() ; ++i) {
683            dram_pkt = *i;
684            const Bank& bank = dram_pkt->bank_ref;
685            if (bank.openRow == dram_pkt->row) { //FR part
686                DPRINTF(DRAM, "Row buffer hit\n");
687                dramReadQueue.erase(i);
688                dramReadQueue.push_front(dram_pkt);
689                break;
690            } else { //FCFS part
691                ;
692            }
693
694        }
695
696    } else
697        panic("No scheduling policy chosen!\n");
698
699
700    DPRINTF(DRAM,"chooseNextReq(): Chosen something, returning True\n");
701    return true;
702}
703
704void
705SimpleDRAM::accessAndRespond(PacketPtr pkt)
706{
707    DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr());
708
709    bool needsResponse = pkt->needsResponse();
710    // do the actual memory access which also turns the packet into a
711    // response
712    access(pkt);
713
714    // turn packet around to go back to requester if response expected
715    if (needsResponse) {
716        // access already turned the packet into a response
717        assert(pkt->isResponse());
718
719        // queue the packet in the response queue to be sent out the
720        // next tick
721        port.schedTimingResp(pkt, curTick() + 1);
722    } else {
723    }
724
725    DPRINTF(DRAM, "Done\n");
726
727    return;
728}
729
730pair<Tick, Tick>
731SimpleDRAM::estimateLatency(DRAMPacket* dram_pkt, Tick inTime)
732{
733    // If a request reaches a bank at tick 'inTime', how much time
734    // *after* that does it take to finish the request, depending
735    // on bank status and page open policy. Note that this method
736    // considers only the time taken for the actual read or write
737    // to complete, NOT any additional time thereafter for tRAS or
738    // tRP.
739    Tick accLat = 0;
740    Tick bankLat = 0;
741    rowHitFlag = false;
742
743    const Bank& bank = dram_pkt->bank_ref;
744    if (pageMgmt == Enums::open) { // open-page policy
745        if (bank.openRow == dram_pkt->row) {
746            // When we have a row-buffer hit,
747            // we don't care about tRAS having expired or not,
748            // but do care about bank being free for access
749            rowHitFlag = true;
750
751            if (bank.freeAt < inTime) {
752               // CAS latency only
753               accLat += tCL;
754               bankLat += tCL;
755            } else {
756                accLat += 0;
757                bankLat += 0;
758            }
759
760        } else {
761            // Row-buffer miss, need to close existing row
762            // once tRAS has expired, then open the new one,
763            // then add cas latency.
764            Tick freeTime = std::max(bank.tRASDoneAt, bank.freeAt);
765
766            if (freeTime > inTime)
767               accLat += freeTime - inTime;
768
769            accLat += tRP + tRCD + tCL;
770            bankLat += tRP + tRCD + tCL;
771        }
772    } else if (pageMgmt == Enums::close) {
773
774        // With a close page policy, no notion of
775        // bank.tRASDoneAt
776        if (bank.freeAt > inTime)
777            accLat += bank.freeAt - inTime;
778
779        // page already closed, simply open the row, and
780        // add cas latency
781        accLat += tRCD + tCL;
782        bankLat += tRCD + tCL;
783    } else
784        panic("No page management policy chosen\n");
785
786    DPRINTF(DRAM, "Returning < %lld, %lld > from estimateLatency()\n",
787            bankLat, accLat);
788
789    return make_pair(bankLat, accLat);
790}
791
792void
793SimpleDRAM::processNextReqEvent()
794{
795    scheduleNextReq();
796}
797
798void
799SimpleDRAM::recordActivate(Tick act_tick)
800{
801    assert(actTicks.size() == activationLimit);
802
803    DPRINTF(DRAM, "Activate at tick %d\n", act_tick);
804
805    // sanity check
806    if (actTicks.back() && (act_tick - actTicks.back()) < tXAW) {
807        panic("Got %d activates in window %d (%d - %d) which is smaller "
808              "than %d\n", activationLimit, act_tick - actTicks.back(),
809              act_tick, actTicks.back(), tXAW);
810    }
811
812    // shift the times used for the book keeping, the last element
813    // (highest index) is the oldest one and hence the lowest value
814    actTicks.pop_back();
815
816    // record an new activation (in the future)
817    actTicks.push_front(act_tick);
818
819    // cannot activate more than X times in time window tXAW, push the
820    // next one (the X + 1'st activate) to be tXAW away from the
821    // oldest in our window of X
822    if (actTicks.back() && (act_tick - actTicks.back()) < tXAW) {
823        DPRINTF(DRAM, "Enforcing tXAW with X = %d, next activate no earlier "
824                "than %d\n", activationLimit, actTicks.back() + tXAW);
825        for(int i = 0; i < ranksPerChannel; i++)
826            for(int j = 0; j < banksPerRank; j++)
827                // next activate must not happen before end of window
828                banks[i][j].freeAt = std::max(banks[i][j].freeAt,
829                                              actTicks.back() + tXAW);
830    }
831}
832
833void
834SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
835{
836
837    DPRINTF(DRAM, "Timing access to addr %lld, rank/bank/row %d %d %d\n",
838            dram_pkt->addr, dram_pkt->rank, dram_pkt->bank, dram_pkt->row);
839
840    assert(curTick() >= prevdramaccess);
841    prevdramaccess = curTick();
842
843    // estimate the bank and access latency
844    pair<Tick, Tick> lat = estimateLatency(dram_pkt, curTick());
845    Tick bankLat = lat.first;
846    Tick accessLat = lat.second;
847
848    // This request was woken up at this time based on a prior call
849    // to estimateLatency(). However, between then and now, both the
850    // accessLatency and/or busBusyUntil may have changed. We need
851    // to correct for that.
852
853    Tick addDelay = (curTick() + accessLat < busBusyUntil) ?
854        busBusyUntil - (curTick() + accessLat) : 0;
855
856    Bank& bank = dram_pkt->bank_ref;
857
858    // Update bank state
859    if (pageMgmt == Enums::open) {
860        bank.openRow = dram_pkt->row;
861        bank.freeAt = curTick() + addDelay + accessLat;
862        // If you activated a new row do to this access, the next access
863        // will have to respect tRAS for this bank. Assume tRAS ~= 3 * tRP.
864        // Also need to account for t_XAW
865        if (!rowHitFlag) {
866            bank.tRASDoneAt = bank.freeAt + tRP;
867            recordActivate(bank.freeAt - tCL - tRCD); //since this is open page,
868                                                      //no tRP by default
869        }
870    } else if (pageMgmt == Enums::close) { // accounting for tRAS also
871        // assuming that tRAS ~= 3 * tRP, and tRC ~= 4 * tRP, as is common
872        // (refer Jacob/Ng/Wang and Micron datasheets)
873        bank.freeAt = curTick() + addDelay + accessLat + tRP + tRP;
874        recordActivate(bank.freeAt - tRP - tRP - tCL - tRCD); //essentially (freeAt - tRC)
875        DPRINTF(DRAM,"doDRAMAccess::bank.freeAt is %lld\n",bank.freeAt);
876    } else
877        panic("No page management policy chosen\n");
878
879    // Update request parameters
880    dram_pkt->readyTime = curTick() + addDelay + accessLat + tBURST;
881
882
883    DPRINTF(DRAM, "Req %lld: curtick is %lld accessLat is %d " \
884                  "readytime is %lld busbusyuntil is %lld. " \
885                  "Scheduling at readyTime\n", dram_pkt->addr,
886                   curTick(), accessLat, dram_pkt->readyTime, busBusyUntil);
887
888    // Make sure requests are not overlapping on the databus
889    assert (dram_pkt->readyTime - busBusyUntil >= tBURST);
890
891    // Update bus state
892    busBusyUntil = dram_pkt->readyTime;
893
894    DPRINTF(DRAM,"Access time is %lld\n",
895            dram_pkt->readyTime - dram_pkt->entryTime);
896
897    // Update stats
898    totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime;
899    totBankLat += bankLat;
900    totBusLat += tBURST;
901    totQLat += dram_pkt->readyTime - dram_pkt->entryTime - bankLat - tBURST;
902
903    if (rowHitFlag)
904        readRowHits++;
905
906    // At this point we're done dealing with the request
907    // It will be moved to a separate response queue with a
908    // correct readyTime, and eventually be sent back at that
909    //time
910    moveToRespQ();
911
912    // The absolute soonest you have to start thinking about the
913    // next request is the longest access time that can occur before
914    // busBusyUntil. Assuming you need to meet tRAS, then precharge,
915    // open a new row, and access, it is ~4*tRCD.
916
917
918    Tick newTime = (busBusyUntil > 4 * tRCD) ?
919                   std::max(busBusyUntil - 4 * tRCD, curTick()) :
920                   curTick();
921
922    if (!nextReqEvent.scheduled() && !stopReads){
923        schedule(&nextReqEvent, newTime);
924    } else {
925        if (newTime < nextReqEvent.when())
926            reschedule(&nextReqEvent, newTime);
927    }
928
929
930}
931
932void
933SimpleDRAM::moveToRespQ()
934{
935    // Remove from read queue
936    DRAMPacket* dram_pkt = dramReadQueue.front();
937    dramReadQueue.pop_front();
938
939    // Insert into response queue sorted by readyTime
940    // It will be sent back to the requestor at its
941    // readyTime
942    if (dramRespQueue.empty()) {
943        dramRespQueue.push_front(dram_pkt);
944        assert(!respondEvent.scheduled());
945        assert(dram_pkt->readyTime >= curTick());
946        schedule(&respondEvent, dram_pkt->readyTime);
947    } else {
948        bool done = false;
949        std::list<DRAMPacket*>::iterator i = dramRespQueue.begin();
950        while (!done && i != dramRespQueue.end()) {
951            if ((*i)->readyTime > dram_pkt->readyTime) {
952                dramRespQueue.insert(i, dram_pkt);
953                done = true;
954            }
955            ++i;
956        }
957
958        if (!done)
959            dramRespQueue.push_back(dram_pkt);
960
961        assert(respondEvent.scheduled());
962
963        if (dramRespQueue.front()->readyTime < respondEvent.when()) {
964            assert(dramRespQueue.front()->readyTime >= curTick());
965            reschedule(&respondEvent, dramRespQueue.front()->readyTime);
966        }
967    }
968
969    if (retryRdReq) {
970         retryRdReq = false;
971         port.sendRetry();
972     }
973}
974
975void
976SimpleDRAM::scheduleNextReq()
977{
978    DPRINTF(DRAM, "Reached scheduleNextReq()\n");
979
980    // Figure out which request goes next, and move it to front()
981    if (!chooseNextReq()) {
982        // In the case there is no read request to go next, see if we
983        // are asked to drain, and if so trigger writes, this also
984        // ensures that if we hit the write limit we will do this
985        // multiple times until we are completely drained
986        if (drainManager && !dramWriteQueue.empty() && !writeEvent.scheduled())
987            triggerWrites();
988    } else {
989        doDRAMAccess(dramReadQueue.front());
990    }
991}
992
993Tick
994SimpleDRAM::maxBankFreeAt() const
995{
996    Tick banksFree = 0;
997
998    for(int i = 0; i < ranksPerChannel; i++)
999        for(int j = 0; j < banksPerRank; j++)
1000            banksFree = std::max(banks[i][j].freeAt, banksFree);
1001
1002    return banksFree;
1003}
1004
1005void
1006SimpleDRAM::processRefreshEvent()
1007{
1008    DPRINTF(DRAM, "Refreshing at tick %ld\n", curTick());
1009
1010    Tick banksFree = std::max(curTick(), maxBankFreeAt()) + tRFC;
1011
1012    for(int i = 0; i < ranksPerChannel; i++)
1013        for(int j = 0; j < banksPerRank; j++)
1014            banks[i][j].freeAt = banksFree;
1015
1016    schedule(&refreshEvent, curTick() + tREFI);
1017}
1018
1019void
1020SimpleDRAM::regStats()
1021{
1022    using namespace Stats;
1023
1024    AbstractMemory::regStats();
1025
1026    readReqs
1027        .name(name() + ".readReqs")
1028        .desc("Total number of read requests seen");
1029
1030    writeReqs
1031        .name(name() + ".writeReqs")
1032        .desc("Total number of write requests seen");
1033
1034    servicedByWrQ
1035        .name(name() + ".servicedByWrQ")
1036        .desc("Number of read reqs serviced by write Q");
1037
1038    cpuReqs
1039        .name(name() + ".cpureqs")
1040        .desc("Reqs generatd by CPU via cache - shady");
1041
1042    neitherReadNorWrite
1043        .name(name() + ".neitherReadNorWrite")
1044        .desc("Reqs where no action is needed");
1045
1046    perBankRdReqs
1047        .init(banksPerRank * ranksPerChannel)
1048        .name(name() + ".perBankRdReqs")
1049        .desc("Track reads on a per bank basis");
1050
1051    perBankWrReqs
1052        .init(banksPerRank * ranksPerChannel)
1053        .name(name() + ".perBankWrReqs")
1054        .desc("Track writes on a per bank basis");
1055
1056    avgRdQLen
1057        .name(name() + ".avgRdQLen")
1058        .desc("Average read queue length over time")
1059        .precision(2);
1060
1061    avgWrQLen
1062        .name(name() + ".avgWrQLen")
1063        .desc("Average write queue length over time")
1064        .precision(2);
1065
1066    totQLat
1067        .name(name() + ".totQLat")
1068        .desc("Total cycles spent in queuing delays");
1069
1070    totBankLat
1071        .name(name() + ".totBankLat")
1072        .desc("Total cycles spent in bank access");
1073
1074    totBusLat
1075        .name(name() + ".totBusLat")
1076        .desc("Total cycles spent in databus access");
1077
1078    totMemAccLat
1079        .name(name() + ".totMemAccLat")
1080        .desc("Sum of mem lat for all requests");
1081
1082    avgQLat
1083        .name(name() + ".avgQLat")
1084        .desc("Average queueing delay per request")
1085        .precision(2);
1086
1087    avgQLat = totQLat / (readReqs - servicedByWrQ);
1088
1089    avgBankLat
1090        .name(name() + ".avgBankLat")
1091        .desc("Average bank access latency per request")
1092        .precision(2);
1093
1094    avgBankLat = totBankLat / (readReqs - servicedByWrQ);
1095
1096    avgBusLat
1097        .name(name() + ".avgBusLat")
1098        .desc("Average bus latency per request")
1099        .precision(2);
1100
1101    avgBusLat = totBusLat / (readReqs - servicedByWrQ);
1102
1103    avgMemAccLat
1104        .name(name() + ".avgMemAccLat")
1105        .desc("Average memory access latency")
1106        .precision(2);
1107
1108    avgMemAccLat = totMemAccLat / (readReqs - servicedByWrQ);
1109
1110    numRdRetry
1111        .name(name() + ".numRdRetry")
1112        .desc("Number of times rd buffer was full causing retry");
1113
1114    numWrRetry
1115        .name(name() + ".numWrRetry")
1116        .desc("Number of times wr buffer was full causing retry");
1117
1118    readRowHits
1119        .name(name() + ".readRowHits")
1120        .desc("Number of row buffer hits during reads");
1121
1122    writeRowHits
1123        .name(name() + ".writeRowHits")
1124        .desc("Number of row buffer hits during writes");
1125
1126    readRowHitRate
1127        .name(name() + ".readRowHitRate")
1128        .desc("Row buffer hit rate for reads")
1129        .precision(2);
1130
1131    readRowHitRate = (readRowHits / (readReqs - servicedByWrQ)) * 100;
1132
1133    writeRowHitRate
1134        .name(name() + ".writeRowHitRate")
1135        .desc("Row buffer hit rate for writes")
1136        .precision(2);
1137
1138    writeRowHitRate = (writeRowHits / writeReqs) * 100;
1139
1140    readPktSize
1141        .init(log2(bytesPerCacheLine)+3)
1142        .name(name() + ".readPktSize")
1143        .desc("Categorize read packet sizes");
1144
1145     writePktSize
1146        .init(log2(bytesPerCacheLine)+3)
1147        .name(name() + ".writePktSize")
1148        .desc("categorize write packet sizes");
1149
1150     neitherPktSize
1151        .init(log2(bytesPerCacheLine)+3)
1152        .name(name() + ".neitherpktsize")
1153        .desc("categorize neither packet sizes");
1154
1155     rdQLenPdf
1156        .init(readBufferSize + 1)
1157        .name(name() + ".rdQLenPdf")
1158        .desc("What read queue length does an incoming req see");
1159
1160     wrQLenPdf
1161        .init(writeBufferSize + 1)
1162        .name(name() + ".wrQLenPdf")
1163        .desc("What write queue length does an incoming req see");
1164
1165
1166    bytesRead
1167        .name(name() + ".bytesRead")
1168        .desc("Total number of bytes read from memory");
1169
1170    bytesWritten
1171        .name(name() + ".bytesWritten")
1172        .desc("Total number of bytes written to memory");
1173
1174    bytesConsumedRd
1175        .name(name() + ".bytesConsumedRd")
1176        .desc("bytesRead derated as per pkt->getSize()");
1177
1178    bytesConsumedWr
1179        .name(name() + ".bytesConsumedWr")
1180        .desc("bytesWritten derated as per pkt->getSize()");
1181
1182    avgRdBW
1183        .name(name() + ".avgRdBW")
1184        .desc("Average achieved read bandwidth in MB/s")
1185        .precision(2);
1186
1187    avgRdBW = (bytesRead / 1000000) / simSeconds;
1188
1189    avgWrBW
1190        .name(name() + ".avgWrBW")
1191        .desc("Average achieved write bandwidth in MB/s")
1192        .precision(2);
1193
1194    avgWrBW = (bytesWritten / 1000000) / simSeconds;
1195
1196    avgConsumedRdBW
1197        .name(name() + ".avgConsumedRdBW")
1198        .desc("Average consumed read bandwidth in MB/s")
1199        .precision(2);
1200
1201    avgConsumedRdBW = (bytesConsumedRd / 1000000) / simSeconds;
1202
1203    avgConsumedWrBW
1204        .name(name() + ".avgConsumedWrBW")
1205        .desc("Average consumed write bandwidth in MB/s")
1206        .precision(2);
1207
1208    avgConsumedWrBW = (bytesConsumedWr / 1000000) / simSeconds;
1209
1210    peakBW
1211        .name(name() + ".peakBW")
1212        .desc("Theoretical peak bandwidth in MB/s")
1213        .precision(2);
1214
1215    peakBW = (SimClock::Frequency / tBURST) * bytesPerCacheLine / 1000000;
1216
1217    busUtil
1218        .name(name() + ".busUtil")
1219        .desc("Data bus utilization in percentage")
1220        .precision(2);
1221
1222    busUtil = (avgRdBW + avgWrBW) / peakBW * 100;
1223
1224    totGap
1225        .name(name() + ".totGap")
1226        .desc("Total gap between requests");
1227
1228    avgGap
1229        .name(name() + ".avgGap")
1230        .desc("Average gap between requests")
1231        .precision(2);
1232
1233    avgGap = totGap / (readReqs + writeReqs);
1234}
1235
1236void
1237SimpleDRAM::recvFunctional(PacketPtr pkt)
1238{
1239    // rely on the abstract memory
1240    functionalAccess(pkt);
1241}
1242
1243BaseSlavePort&
1244SimpleDRAM::getSlavePort(const string &if_name, PortID idx)
1245{
1246    if (if_name != "port") {
1247        return MemObject::getSlavePort(if_name, idx);
1248    } else {
1249        return port;
1250    }
1251}
1252
1253unsigned int
1254SimpleDRAM::drain(DrainManager *dm)
1255{
1256    unsigned int count = port.drain(dm);
1257
1258    // if there is anything in any of our internal queues, keep track
1259    // of that as well
1260    if (!(dramWriteQueue.empty() && dramReadQueue.empty() &&
1261          dramRespQueue.empty())) {
1262        DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d,"
1263                " resp: %d\n", dramWriteQueue.size(), dramReadQueue.size(),
1264                dramRespQueue.size());
1265        ++count;
1266        drainManager = dm;
1267        // the only part that is not drained automatically over time
1268        // is the write queue, thus trigger writes if there are any
1269        // waiting and no reads waiting, otherwise wait until the
1270        // reads are done
1271        if (dramReadQueue.empty() && !dramWriteQueue.empty() &&
1272            !writeEvent.scheduled())
1273            triggerWrites();
1274    }
1275
1276    if (count)
1277        setDrainState(Drainable::Draining);
1278    else
1279        setDrainState(Drainable::Drained);
1280    return count;
1281}
1282
1283SimpleDRAM::MemoryPort::MemoryPort(const std::string& name, SimpleDRAM& _memory)
1284    : QueuedSlavePort(name, &_memory, queue), queue(_memory, *this),
1285      memory(_memory)
1286{ }
1287
1288AddrRangeList
1289SimpleDRAM::MemoryPort::getAddrRanges() const
1290{
1291    AddrRangeList ranges;
1292    ranges.push_back(memory.getAddrRange());
1293    return ranges;
1294}
1295
1296void
1297SimpleDRAM::MemoryPort::recvFunctional(PacketPtr pkt)
1298{
1299    pkt->pushLabel(memory.name());
1300
1301    if (!queue.checkFunctional(pkt)) {
1302        // Default implementation of SimpleTimingPort::recvFunctional()
1303        // calls recvAtomic() and throws away the latency; we can save a
1304        // little here by just not calculating the latency.
1305        memory.recvFunctional(pkt);
1306    }
1307
1308    pkt->popLabel();
1309}
1310
1311Tick
1312SimpleDRAM::MemoryPort::recvAtomic(PacketPtr pkt)
1313{
1314    return memory.recvAtomic(pkt);
1315}
1316
1317bool
1318SimpleDRAM::MemoryPort::recvTimingReq(PacketPtr pkt)
1319{
1320    // pass it to the memory controller
1321    return memory.recvTimingReq(pkt);
1322}
1323
1324SimpleDRAM*
1325SimpleDRAMParams::create()
1326{
1327    return new SimpleDRAM(this);
1328}
1329