2 * Copyright (c) 2010-2012 ARM Limited
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.
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.
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.
37 * Authors: Andreas Hansson
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"
49 SimpleDRAM::SimpleDRAM(const SimpleDRAMParams
* 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
),
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)
72 // create the bank states based on the dimensions of the ranks and
74 banks
.resize(ranksPerChannel
);
75 for (size_t c
= 0; c
< ranksPerChannel
; ++c
) {
76 banks
[c
].resize(banksPerRank
);
79 // round the write threshold percent to a whole number of entries
81 writeThreshold
= writeBufferSize
* writeThresholdPerc
/ 100.0;
87 if (!port
.isConnected()) {
88 fatal("SimpleDRAM %s is unconnected!\n", name());
90 port
.sendRangeChange();
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();
97 // we could deal with plenty options here, but for now do a quick
99 if (bytesPerCacheLine
!= 64 && bytesPerCacheLine
!= 32)
100 panic("Unexpected burst size %d", bytesPerCacheLine
);
102 // determine the rows per bank by looking at the total capacity
103 uint64_t capacity
= ULL(1) << ceilLog2(AbstractMemory::size());
105 DPRINTF(DRAM
, "Memory capacity %lld (%lld) bytes\n", capacity
,
106 AbstractMemory::size());
107 rowsPerBank
= capacity
/ (bytesPerCacheLine
* linesPerRowBuffer
*
108 banksPerRank
* ranksPerChannel
);
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
);
115 if (addrMapping
== Enums::openmap
) {
116 if (bytesPerCacheLine
* linesPerRowBuffer
!=
117 range
.granularity()) {
118 panic("Interleaving of %s doesn't match open address map\n",
121 } else if (addrMapping
== Enums::closemap
) {
122 if (bytesPerCacheLine
!= range
.granularity())
123 panic("Interleaving of %s doesn't match closed address map\n",
130 SimpleDRAM::startup()
132 // print the configuration of the controller
135 // kick off the refresh
136 schedule(refreshEvent
, curTick() + tREFI
);
140 SimpleDRAM::recvAtomic(PacketPtr pkt
)
142 DPRINTF(DRAM
, "recvAtomic: %s 0x%x\n", pkt
->cmdString(), pkt
->getAddr());
144 // do the actual memory access and turn the packet into a response
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
;
157 SimpleDRAM::readQueueFull() const
159 DPRINTF(DRAM
, "Read queue limit %d current size %d\n",
160 readBufferSize
, readQueue
.size() + respQueue
.size());
162 return (readQueue
.size() + respQueue
.size()) == readBufferSize
;
166 SimpleDRAM::writeQueueFull() const
168 DPRINTF(DRAM
, "Write queue limit %d current size %d\n",
169 writeBufferSize
, writeQueue
.size());
170 return writeQueue
.size() == writeBufferSize
;
173 SimpleDRAM::DRAMPacket
*
174 SimpleDRAM::decodeAddr(PacketPtr pkt
)
176 // decode the address based on the address mapping scheme
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)
185 Addr addr
= pkt
->getAddr();
187 // truncate the address to the access granularity
188 addr
= addr
/ bytesPerCacheLine
;
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
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
;
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
;
204 // after the column bits, we get the bank bits to interleave
206 bank
= addr
% banksPerRank
;
207 addr
= addr
/ banksPerRank
;
209 // after the bank, we get the rank bits which thus interleaves
211 rank
= addr
% ranksPerChannel
;
212 addr
= addr
/ ranksPerChannel
;
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)
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
;
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
;
231 // next get the rank bits
232 rank
= addr
% ranksPerChannel
;
233 addr
= addr
/ ranksPerChannel
;
235 // next the column bits which we do not need to keep track of
236 // and simply skip past
237 addr
= addr
/ linesPerRowBuffer
;
239 // lastly, get the row bits
240 row
= addr
% rowsPerBank
;
241 addr
= addr
/ rowsPerBank
;
243 panic("Unknown address mapping policy chosen!");
245 assert(rank
< ranksPerChannel
);
246 assert(bank
< banksPerRank
);
247 assert(row
< rowsPerBank
);
249 DPRINTF(DRAM
, "Address: %lld Rank %d Bank %d Row %d\n",
250 pkt
->getAddr(), rank
, bank
, row
);
252 // create the corresponding DRAM packet with the entry time and
253 // ready time set to the current tick, the latter will be updated
255 return new DRAMPacket(pkt
, rank
, bank
, row
, pkt
->getAddr(),
260 SimpleDRAM::addToReadQueue(PacketPtr pkt
)
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());
266 // First check write buffer to see if the data is already at
268 list
<DRAMPacket
*>::const_iterator i
;
269 Addr addr
= pkt
->getAddr();
271 // @todo: add size check
272 for (i
= writeQueue
.begin(); i
!= writeQueue
.end(); ++i
) {
273 if ((*i
)->addr
== addr
){
275 DPRINTF(DRAM
, "Read to %lld serviced by write queue\n", addr
);
276 bytesRead
+= bytesPerCacheLine
;
277 bytesConsumedRd
+= pkt
->getSize();
278 accessAndRespond(pkt
);
283 DRAMPacket
* dram_pkt
= decodeAddr(pkt
);
285 assert(readQueue
.size() + respQueue
.size() < readBufferSize
);
286 rdQLenPdf
[readQueue
.size() + respQueue
.size()]++;
288 DPRINTF(DRAM
, "Adding to read queue\n");
290 readQueue
.push_back(dram_pkt
);
293 uint32_t bank_id
= banksPerRank
* dram_pkt
->rank
+ dram_pkt
->bank
;
294 assert(bank_id
< ranksPerChannel
* banksPerRank
);
295 perBankRdReqs
[bank_id
]++;
297 avgRdQLen
= readQueue
.size() + respQueue
.size();
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());
308 SimpleDRAM::processWriteEvent()
310 assert(!writeQueue
.empty());
311 uint32_t numWritesThisTime
= 0;
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());
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
);
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
);
329 DPRINTF(DRAMWR
, "Asking for latency estimate at %lld\n",
332 pair
<Tick
, Tick
> lat
= estimateLatency(dram_pkt
, schedTime
+ tBURST
);
333 Tick accessLat
= lat
.second
;
335 // look at the rowHitFlag set by estimateLatency
339 Bank
& bank
= dram_pkt
->bank_ref
;
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
;
347 bank
.tRASDoneAt
= bank
.freeAt
+ tRP
;
348 recordActivate(bank
.freeAt
- tCL
- tRCD
);
349 busBusyUntil
= bank
.freeAt
- tCL
- tRCD
;
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
,
361 panic("Unknown page management policy chosen\n");
363 DPRINTF(DRAMWR
, "Done writing to address %lld\n", dram_pkt
->addr
);
365 DPRINTF(DRAMWR
, "schedtime is %lld, tBURST is %lld, "
366 "busbusyuntil is %lld\n",
367 schedTime
, tBURST
, busBusyUntil
);
369 writeQueue
.pop_front();
375 DPRINTF(DRAMWR
, "Completed %d writes, bus busy for %lld ticks,"\
376 "banks busy for %lld ticks\n", numWritesThisTime
,
377 busBusyUntil
- temp1
, maxBankFreeAt() - temp2
);
380 avgWrQLen
= writeQueue
.size();
382 // turn the bus back around for reads again
383 busBusyUntil
+= tWTR
;
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();
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
402 if (!nextReqEvent
.scheduled())
403 schedule(nextReqEvent
, busBusyUntil
);
407 SimpleDRAM::triggerWrites()
409 DPRINTF(DRAM
, "Writes triggered at %lld\n", curTick());
410 // Flag variable to stop any more read scheduling
413 writeStartTime
= std::max(busBusyUntil
, curTick()) + tWTR
;
415 DPRINTF(DRAM
, "Writes scheduled at %lld\n", writeStartTime
);
417 assert(writeStartTime
>= curTick());
418 assert(!writeEvent
.scheduled());
419 schedule(writeEvent
, writeStartTime
);
423 SimpleDRAM::addToWriteQueue(PacketPtr pkt
)
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());
429 DRAMPacket
* dram_pkt
= decodeAddr(pkt
);
431 assert(writeQueue
.size() < writeBufferSize
);
432 wrQLenPdf
[writeQueue
.size()]++;
434 DPRINTF(DRAM
, "Adding to write queue\n");
436 writeQueue
.push_back(dram_pkt
);
439 uint32_t bank_id
= banksPerRank
* dram_pkt
->rank
+ dram_pkt
->bank
;
440 assert(bank_id
< ranksPerChannel
* banksPerRank
);
441 perBankWrReqs
[bank_id
]++;
443 avgWrQLen
= writeQueue
.size();
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
449 bytesConsumedWr
+= pkt
->getSize();
450 bytesWritten
+= bytesPerCacheLine
;
451 accessAndRespond(pkt
);
453 // If your write buffer is starting to fill up, drain it!
454 if (writeQueue
.size() > writeThreshold
&& !stopReads
){
460 SimpleDRAM::printParams() const
462 // Sanity check print of important parameters
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
);
475 string scheduler
= memSchedPolicy
== Enums::fcfs
? "FCFS" : "FR-FCFS";
476 string address_mapping
= addrMapping
== Enums::openmap
? "OPENMAP" :
478 string page_policy
= pageMgmt
== Enums::open
? "OPEN" : "CLOSE";
481 "Memory controller %s characteristics\n" \
482 "Read buffer size %d\n" \
483 "Write buffer size %d\n" \
484 "Write buffer thresh %d\n" \
486 "Address mapping %s\n" \
488 name(), readBufferSize
, writeBufferSize
, writeThreshold
,
489 scheduler
, address_mapping
, page_policy
);
491 DPRINTF(DRAM
, "Memory controller %s timing specs\n" \
495 "tBURST %d ticks\n" \
499 "tXAW (%d) %d ticks\n",
500 name(), tRCD
, tCL
, tRP
, tBURST
, tRFC
, tREFI
, tWTR
,
501 activationLimit
, tXAW
);
505 SimpleDRAM::printQs() const {
507 list
<DRAMPacket
*>::const_iterator i
;
509 DPRINTF(DRAM
, "===READ QUEUE===\n\n");
510 for (i
= readQueue
.begin() ; i
!= readQueue
.end() ; ++i
) {
511 DPRINTF(DRAM
, "Read %lu\n", (*i
)->addr
);
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
);
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
);
524 SimpleDRAM::recvTimingReq(PacketPtr pkt
)
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();
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());
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
);
543 if (pkt
->getSize() == bytesPerCacheLine
)
546 // Every million accesses, print the state of the queues
547 if (numReqs
% 1000000 == 0)
550 // Calc avg gap between requests
551 if (prevArrival
!= 0) {
552 totGap
+= curTick() - prevArrival
;
554 prevArrival
= curTick();
556 unsigned size
= pkt
->getSize();
557 if (size
> bytesPerCacheLine
)
558 panic("Request size %d is greater than burst size %d",
559 size
, bytesPerCacheLine
);
561 // check local buffers and do not accept if full
564 if (readQueueFull()) {
565 DPRINTF(DRAM
, "Read queue full, not accepting\n");
566 // remember that we have to retry this port
571 readPktSize
[ceilLog2(size
)]++;
576 } else if (pkt
->isWrite()) {
578 if (writeQueueFull()) {
579 DPRINTF(DRAM
, "Write queue full, not accepting\n");
580 // remember that we have to retry this port
585 writePktSize
[ceilLog2(size
)]++;
586 addToWriteQueue(pkt
);
591 DPRINTF(DRAM
,"Neither read nor write, ignore timing\n");
592 neitherReadNorWrite
++;
593 accessAndRespond(pkt
);
602 SimpleDRAM::processRespondEvent()
605 "processRespondEvent(): Some req has reached its readyTime\n");
607 PacketPtr pkt
= respQueue
.front()->pkt
;
609 // Actually responds to the requestor
610 bytesConsumedRd
+= pkt
->getSize();
611 bytesRead
+= bytesPerCacheLine
;
612 accessAndRespond(pkt
);
614 delete respQueue
.front();
615 respQueue
.pop_front();
618 avgRdQLen
= readQueue
.size() + respQueue
.size();
620 if (!respQueue
.empty()) {
621 assert(respQueue
.front()->readyTime
>= curTick());
622 assert(!respondEvent
.scheduled());
623 schedule(respondEvent
, respQueue
.front()->readyTime
);
625 // if there is nothing left in any queue, signal a drain
626 if (writeQueue
.empty() && readQueue
.empty() &&
628 drainManager
->signalDrainDone();
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
642 SimpleDRAM::chooseNextWrite()
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());
650 if (writeQueue
.size() == 1) {
651 DPRINTF(DRAMWR
, "Single write request, nothing to do\n");
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");
666 writeQueue
.push_front(dram_pkt
);
674 panic("No scheduling policy chosen\n");
676 DPRINTF(DRAMWR
, "Selected next write request\n");
680 SimpleDRAM::chooseNextRead()
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");
691 // If there is only one request then there is nothing left to do
692 if (readQueue
.size() == 1)
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");
707 readQueue
.push_front(dram_pkt
);
714 panic("No scheduling policy chosen!\n");
716 DPRINTF(DRAM
, "Selected next read request\n");
721 SimpleDRAM::accessAndRespond(PacketPtr pkt
)
723 DPRINTF(DRAM
, "Responding to Address %lld.. ",pkt
->getAddr());
725 bool needsResponse
= pkt
->needsResponse();
726 // do the actual memory access which also turns the packet into a
730 // turn packet around to go back to requester if response expected
732 // access already turned the packet into a response
733 assert(pkt
->isResponse());
735 // @todo someone should pay for this
736 pkt
->busFirstWordDelay
= pkt
->busLastWordDelay
= 0;
738 // queue the packet in the response queue to be sent out the
740 port
.schedTimingResp(pkt
, curTick() + 1);
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
);
747 DPRINTF(DRAM
, "Done\n");
753 SimpleDRAM::estimateLatency(DRAMPacket
* dram_pkt
, Tick inTime
)
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
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
773 if (bank
.freeAt
< inTime
) {
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
);
788 if (freeTime
> inTime
)
789 accLat
+= freeTime
- inTime
;
791 accLat
+= tRP
+ tRCD
+ tCL
;
792 bankLat
+= tRP
+ tRCD
+ tCL
;
794 } else if (pageMgmt
== Enums::close
) {
795 // With a close page policy, no notion of
797 if (bank
.freeAt
> inTime
)
798 accLat
+= bank
.freeAt
- inTime
;
800 // page already closed, simply open the row, and
802 accLat
+= tRCD
+ tCL
;
803 bankLat
+= tRCD
+ tCL
;
805 panic("No page management policy chosen\n");
807 DPRINTF(DRAM
, "Returning < %lld, %lld > from estimateLatency()\n",
810 return make_pair(bankLat
, accLat
);
814 SimpleDRAM::processNextReqEvent()
820 SimpleDRAM::recordActivate(Tick act_tick
)
822 assert(actTicks
.size() == activationLimit
);
824 DPRINTF(DRAM
, "Activate at tick %d\n", act_tick
);
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
);
833 // shift the times used for the book keeping, the last element
834 // (highest index) is the oldest one and hence the lowest value
837 // record an new activation (in the future)
838 actTicks
.push_front(act_tick
);
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
);
855 SimpleDRAM::doDRAMAccess(DRAMPacket
* dram_pkt
)
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
);
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
;
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.
871 Tick addDelay
= (curTick() + accessLat
< busBusyUntil
) ?
872 busBusyUntil
- (curTick() + accessLat
) : 0;
874 Bank
& bank
= dram_pkt
->bank_ref
;
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
884 bank
.tRASDoneAt
= bank
.freeAt
+ tRP
;
885 recordActivate(bank
.freeAt
- tCL
- tRCD
); //since this is open page,
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
);
895 panic("No page management policy chosen\n");
897 // Update request parameters
898 dram_pkt
->readyTime
= curTick() + addDelay
+ accessLat
+ tBURST
;
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
);
906 // Make sure requests are not overlapping on the databus
907 assert (dram_pkt
->readyTime
- busBusyUntil
>= tBURST
);
910 busBusyUntil
= dram_pkt
->readyTime
;
912 DPRINTF(DRAM
,"Access time is %lld\n",
913 dram_pkt
->readyTime
- dram_pkt
->entryTime
);
916 totMemAccLat
+= dram_pkt
->readyTime
- dram_pkt
->entryTime
;
917 totBankLat
+= bankLat
;
919 totQLat
+= dram_pkt
->readyTime
- dram_pkt
->entryTime
- bankLat
- tBURST
;
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
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.
936 Tick newTime
= (busBusyUntil
> 4 * tRCD
) ?
937 std::max(busBusyUntil
- 4 * tRCD
, curTick()) :
940 if (!nextReqEvent
.scheduled() && !stopReads
){
941 schedule(nextReqEvent
, newTime
);
943 if (newTime
< nextReqEvent
.when())
944 reschedule(nextReqEvent
, newTime
);
951 SimpleDRAM::moveToRespQ()
953 // Remove from read queue
954 DRAMPacket
* dram_pkt
= readQueue
.front();
955 readQueue
.pop_front();
957 // Insert into response queue sorted by readyTime
958 // It will be sent back to the requestor at its
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
);
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
);
977 respQueue
.push_back(dram_pkt
);
979 assert(respondEvent
.scheduled());
981 if (respQueue
.front()->readyTime
< respondEvent
.when()) {
982 assert(respQueue
.front()->readyTime
>= curTick());
983 reschedule(respondEvent
, respQueue
.front()->readyTime
);
989 SimpleDRAM::scheduleNextReq()
991 DPRINTF(DRAM
, "Reached scheduleNextReq()\n");
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())
1003 doDRAMAccess(readQueue
.front());
1008 SimpleDRAM::maxBankFreeAt() const
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
);
1020 SimpleDRAM::processRefreshEvent()
1022 DPRINTF(DRAM
, "Refreshing at tick %ld\n", curTick());
1024 Tick banksFree
= std::max(curTick(), maxBankFreeAt()) + tRFC
;
1026 for(int i
= 0; i
< ranksPerChannel
; i
++)
1027 for(int j
= 0; j
< banksPerRank
; j
++)
1028 banks
[i
][j
].freeAt
= banksFree
;
1030 schedule(refreshEvent
, curTick() + tREFI
);
1034 SimpleDRAM::regStats()
1036 using namespace Stats
;
1038 AbstractMemory::regStats();
1041 .name(name() + ".readReqs")
1042 .desc("Total number of read requests seen");
1045 .name(name() + ".writeReqs")
1046 .desc("Total number of write requests seen");
1049 .name(name() + ".servicedByWrQ")
1050 .desc("Number of read reqs serviced by write Q");
1053 .name(name() + ".cpureqs")
1054 .desc("Reqs generatd by CPU via cache - shady");
1057 .name(name() + ".neitherReadNorWrite")
1058 .desc("Reqs where no action is needed");
1061 .init(banksPerRank
* ranksPerChannel
)
1062 .name(name() + ".perBankRdReqs")
1063 .desc("Track reads on a per bank basis");
1066 .init(banksPerRank
* ranksPerChannel
)
1067 .name(name() + ".perBankWrReqs")
1068 .desc("Track writes on a per bank basis");
1071 .name(name() + ".avgRdQLen")
1072 .desc("Average read queue length over time")
1076 .name(name() + ".avgWrQLen")
1077 .desc("Average write queue length over time")
1081 .name(name() + ".totQLat")
1082 .desc("Total cycles spent in queuing delays");
1085 .name(name() + ".totBankLat")
1086 .desc("Total cycles spent in bank access");
1089 .name(name() + ".totBusLat")
1090 .desc("Total cycles spent in databus access");
1093 .name(name() + ".totMemAccLat")
1094 .desc("Sum of mem lat for all requests");
1097 .name(name() + ".avgQLat")
1098 .desc("Average queueing delay per request")
1101 avgQLat
= totQLat
/ (readReqs
- servicedByWrQ
);
1104 .name(name() + ".avgBankLat")
1105 .desc("Average bank access latency per request")
1108 avgBankLat
= totBankLat
/ (readReqs
- servicedByWrQ
);
1111 .name(name() + ".avgBusLat")
1112 .desc("Average bus latency per request")
1115 avgBusLat
= totBusLat
/ (readReqs
- servicedByWrQ
);
1118 .name(name() + ".avgMemAccLat")
1119 .desc("Average memory access latency")
1122 avgMemAccLat
= totMemAccLat
/ (readReqs
- servicedByWrQ
);
1125 .name(name() + ".numRdRetry")
1126 .desc("Number of times rd buffer was full causing retry");
1129 .name(name() + ".numWrRetry")
1130 .desc("Number of times wr buffer was full causing retry");
1133 .name(name() + ".readRowHits")
1134 .desc("Number of row buffer hits during reads");
1137 .name(name() + ".writeRowHits")
1138 .desc("Number of row buffer hits during writes");
1141 .name(name() + ".readRowHitRate")
1142 .desc("Row buffer hit rate for reads")
1145 readRowHitRate
= (readRowHits
/ (readReqs
- servicedByWrQ
)) * 100;
1148 .name(name() + ".writeRowHitRate")
1149 .desc("Row buffer hit rate for writes")
1152 writeRowHitRate
= (writeRowHits
/ writeReqs
) * 100;
1155 .init(ceilLog2(bytesPerCacheLine
) + 1)
1156 .name(name() + ".readPktSize")
1157 .desc("Categorize read packet sizes");
1160 .init(ceilLog2(bytesPerCacheLine
) + 1)
1161 .name(name() + ".writePktSize")
1162 .desc("Categorize write packet sizes");
1165 .init(readBufferSize
)
1166 .name(name() + ".rdQLenPdf")
1167 .desc("What read queue length does an incoming req see");
1170 .init(writeBufferSize
)
1171 .name(name() + ".wrQLenPdf")
1172 .desc("What write queue length does an incoming req see");
1176 .name(name() + ".bytesRead")
1177 .desc("Total number of bytes read from memory");
1180 .name(name() + ".bytesWritten")
1181 .desc("Total number of bytes written to memory");
1184 .name(name() + ".bytesConsumedRd")
1185 .desc("bytesRead derated as per pkt->getSize()");
1188 .name(name() + ".bytesConsumedWr")
1189 .desc("bytesWritten derated as per pkt->getSize()");
1192 .name(name() + ".avgRdBW")
1193 .desc("Average achieved read bandwidth in MB/s")
1196 avgRdBW
= (bytesRead
/ 1000000) / simSeconds
;
1199 .name(name() + ".avgWrBW")
1200 .desc("Average achieved write bandwidth in MB/s")
1203 avgWrBW
= (bytesWritten
/ 1000000) / simSeconds
;
1206 .name(name() + ".avgConsumedRdBW")
1207 .desc("Average consumed read bandwidth in MB/s")
1210 avgConsumedRdBW
= (bytesConsumedRd
/ 1000000) / simSeconds
;
1213 .name(name() + ".avgConsumedWrBW")
1214 .desc("Average consumed write bandwidth in MB/s")
1217 avgConsumedWrBW
= (bytesConsumedWr
/ 1000000) / simSeconds
;
1220 .name(name() + ".peakBW")
1221 .desc("Theoretical peak bandwidth in MB/s")
1224 peakBW
= (SimClock::Frequency
/ tBURST
) * bytesPerCacheLine
/ 1000000;
1227 .name(name() + ".busUtil")
1228 .desc("Data bus utilization in percentage")
1231 busUtil
= (avgRdBW
+ avgWrBW
) / peakBW
* 100;
1234 .name(name() + ".totGap")
1235 .desc("Total gap between requests");
1238 .name(name() + ".avgGap")
1239 .desc("Average gap between requests")
1242 avgGap
= totGap
/ (readReqs
+ writeReqs
);
1246 SimpleDRAM::recvFunctional(PacketPtr pkt
)
1248 // rely on the abstract memory
1249 functionalAccess(pkt
);
1253 SimpleDRAM::getSlavePort(const string
&if_name
, PortID idx
)
1255 if (if_name
!= "port") {
1256 return MemObject::getSlavePort(if_name
, idx
);
1263 SimpleDRAM::drain(DrainManager
*dm
)
1265 unsigned int count
= port
.drain(dm
);
1267 // if there is anything in any of our internal queues, keep track
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(),
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
1280 if (readQueue
.empty() && !writeQueue
.empty() &&
1281 !writeEvent
.scheduled())
1286 setDrainState(Drainable::Draining
);
1288 setDrainState(Drainable::Drained
);
1292 SimpleDRAM::MemoryPort::MemoryPort(const std::string
& name
, SimpleDRAM
& _memory
)
1293 : QueuedSlavePort(name
, &_memory
, queue
), queue(_memory
, *this),
1298 SimpleDRAM::MemoryPort::getAddrRanges() const
1300 AddrRangeList ranges
;
1301 ranges
.push_back(memory
.getAddrRange());
1306 SimpleDRAM::MemoryPort::recvFunctional(PacketPtr pkt
)
1308 pkt
->pushLabel(memory
.name());
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
);
1321 SimpleDRAM::MemoryPort::recvAtomic(PacketPtr pkt
)
1323 return memory
.recvAtomic(pkt
);
1327 SimpleDRAM::MemoryPort::recvTimingReq(PacketPtr pkt
)
1329 // pass it to the memory controller
1330 return memory
.recvTimingReq(pkt
);
1334 SimpleDRAMParams::create()
1336 return new SimpleDRAM(this);