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