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