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"
46 #include "sim/stat_control.hh"
50 SimpleDRAM::SimpleDRAM(const SimpleDRAMParams
* p
) :
52 port(name() + ".port", *this),
53 retryRdReq(false), retryWrReq(false),
54 rowHitFlag(false), stopReads(false), actTicks(p
->activation_limit
, 0),
55 writeEvent(this), respondEvent(this),
56 refreshEvent(this), nextReqEvent(this), drainManager(NULL
),
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 tXAW(p
->tXAW
), activationLimit(p
->activation_limit
),
68 memSchedPolicy(p
->mem_sched_policy
), addrMapping(p
->addr_mapping
),
69 pageMgmt(p
->page_policy
),
70 busBusyUntil(0), prevdramaccess(0), writeStartTime(0),
71 prevArrival(0), numReqs(0)
73 // create the bank states based on the dimensions of the ranks and
75 banks
.resize(ranksPerChannel
);
76 for (size_t c
= 0; c
< ranksPerChannel
; ++c
) {
77 banks
[c
].resize(banksPerRank
);
80 // round the write threshold percent to a whole number of entries
82 writeThreshold
= writeBufferSize
* writeThresholdPerc
/ 100.0;
88 if (!port
.isConnected()) {
89 fatal("SimpleDRAM %s is unconnected!\n", name());
91 port
.sendRangeChange();
94 // get the cache line size from the connected port
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 cache line size %d", bytesPerCacheLine
);
102 // determine the rows per bank by looking at the total capacity
103 uint64_t capacity
= AbstractMemory::size();
105 while (i
< 64 && capacity
> ((1 << i
))) {
109 // rounded up to nearest power of two
110 DPRINTF(DRAM
, "i is %lld\n", i
);
113 DPRINTF(DRAM
, "Memory capacity %lld (%lld) bytes\n", capacity
,
114 AbstractMemory::size());
115 rowsPerBank
= capacity
/ (bytesPerCacheLine
* linesPerRowBuffer
*
116 banksPerRank
* ranksPerChannel
);
121 SimpleDRAM::startup()
123 // print the configuration of the controller
126 // kick off the refresh
127 schedule(&refreshEvent
, curTick() + tREFI
);
132 SimpleDRAM::recvAtomic(PacketPtr pkt
)
134 DPRINTF(DRAM
, "recvAtomic: %s 0x%x\n", pkt
->cmdString(), pkt
->getAddr());
136 // do the actual memory access and turn the packet into a response
140 if (!pkt
->memInhibitAsserted() && pkt
->hasData()) {
141 // this value is not supposed to be accurate, just enough to
142 // keep things going, mimic a closed page
143 latency
= tRP
+ tRCD
+ tCL
;
149 SimpleDRAM::readQueueFull() const
151 DPRINTF(DRAM
, "Read queue limit %d current size %d\n",
152 readBufferSize
, dramReadQueue
.size() + dramRespQueue
.size());
154 return (dramReadQueue
.size() + dramRespQueue
.size()) == readBufferSize
;
158 SimpleDRAM::writeQueueFull() const
160 DPRINTF(DRAM
, "Write queue limit %d current size %d\n",
161 writeBufferSize
, dramWriteQueue
.size());
162 return dramWriteQueue
.size() == writeBufferSize
;
166 SimpleDRAM::DRAMPacket
*
167 SimpleDRAM::decodeAddr(PacketPtr pkt
)
169 // decode the address based on the address mapping scheme
171 // with R, C, B and K denoting rank, column, bank and rank,
172 // respectively, and going from MSB to LSB, the two schemes are
173 // RKBC (openmap) and RCKB (closedmap)
178 Addr addr
= pkt
->getAddr();
181 // truncate the address to the access granularity
182 addr
= addr
/ bytesPerCacheLine
;
184 // we have removed the lowest order address bits that denote the
185 // position within the cache line, proceed and select the
186 // appropriate bits for bank, rank and row (no column address is
188 if (addrMapping
== Enums::openmap
) {
189 // the lowest order bits denote the column to ensure that
190 // sequential cache lines occupy the same row
191 addr
= addr
/ linesPerRowBuffer
;
193 // after the column bits, we get the bank bits to interleave
195 bank
= addr
% banksPerRank
;
196 addr
= addr
/ banksPerRank
;
198 // after the bank, we get the rank bits which thus interleaves
200 rank
= addr
% ranksPerChannel
;
201 addr
= addr
/ ranksPerChannel
;
203 // lastly, get the row bits
204 row
= addr
% rowsPerBank
;
205 addr
= addr
/ rowsPerBank
;
206 } else if (addrMapping
== Enums::closemap
) {
207 // optimise for closed page mode and utilise maximum
208 // parallelism of the DRAM (at the cost of power)
210 // start with the bank bits, as this provides the maximum
211 // opportunity for parallelism between requests
212 bank
= addr
% banksPerRank
;
213 addr
= addr
/ banksPerRank
;
215 // next get the rank bits
216 rank
= addr
% ranksPerChannel
;
217 addr
= addr
/ ranksPerChannel
;
219 // next the column bits which we do not need to keep track of
220 // and simply skip past
221 addr
= addr
/ linesPerRowBuffer
;
223 // lastly, get the row bits
224 row
= addr
% rowsPerBank
;
225 addr
= addr
/ rowsPerBank
;
227 panic("Unknown address mapping policy chosen!");
229 assert(rank
< ranksPerChannel
);
230 assert(bank
< banksPerRank
);
231 assert(row
< rowsPerBank
);
233 DPRINTF(DRAM
, "Address: %lld Rank %d Bank %d Row %d\n",
234 temp
, rank
, bank
, row
);
236 // create the corresponding DRAM packet with the entry time and
237 // ready time set to the current tick, they will be updated later
238 DRAMPacket
* dram_pkt
= new DRAMPacket(pkt
, rank
, bank
, row
, temp
,
245 SimpleDRAM::addToReadQueue(PacketPtr pkt
)
247 // only add to the read queue here. whenever the request is
248 // eventually done, set the readyTime, and call schedule()
249 assert(!pkt
->isWrite());
251 // First check write buffer to see if the data is already at
253 std::list
<DRAMPacket
*>::const_iterator i
;
254 Addr addr
= pkt
->getAddr();
256 // @todo: add size check
257 for (i
= dramWriteQueue
.begin(); i
!= dramWriteQueue
.end(); ++i
) {
258 if ((*i
)->addr
== addr
){
260 DPRINTF(DRAM
,"Serviced by write Q\n");
261 bytesRead
+= bytesPerCacheLine
;
262 bytesConsumedRd
+= pkt
->getSize();
263 accessAndRespond(pkt
);
268 DRAMPacket
* dram_pkt
= decodeAddr(pkt
);
270 assert(dramReadQueue
.size() + dramRespQueue
.size() < readBufferSize
);
271 rdQLenPdf
[dramReadQueue
.size() + dramRespQueue
.size()]++;
273 DPRINTF(DRAM
, "Adding to read queue\n");
275 dramReadQueue
.push_back(dram_pkt
);
278 uint32_t bank_id
= banksPerRank
* dram_pkt
->rank
+ dram_pkt
->bank
;
279 assert(bank_id
< ranksPerChannel
* banksPerRank
);
280 perBankRdReqs
[bank_id
]++;
282 avgRdQLen
= dramReadQueue
.size() + dramRespQueue
.size();
284 // Special case where no arbitration is required between requests
285 if (!nextReqEvent
.scheduled() && !stopReads
) {
286 DPRINTF(DRAM
, "Request %lld - need to schedule immediately");
287 schedule(&nextReqEvent
, curTick() + 1);
292 SimpleDRAM::processWriteEvent()
294 assert(!dramWriteQueue
.empty());
295 uint32_t numWritesThisTime
= 0;
297 DPRINTF(DRAMWR
, "Beginning DRAM Writes\n");
298 Tick temp1 M5_VAR_USED
= std::max(curTick(), busBusyUntil
);
299 Tick temp2 M5_VAR_USED
= std::max(curTick(), maxBankFreeAt());
301 // @todo: are there any dangers with the untimed while loop?
302 while (!dramWriteQueue
.empty()) {
303 if (numWritesThisTime
> writeThreshold
)
307 DRAMPacket
* dram_pkt
= dramWriteQueue
.front();
308 // What's the earlier the request can be put on the bus
309 Tick schedTime
= std::max(curTick(), busBusyUntil
);
311 DPRINTF(DRAMWR
, "Asking for latency estimate at %lld\n",
314 pair
<Tick
, Tick
> lat
= estimateLatency(dram_pkt
, schedTime
+ tBURST
);
315 Tick accessLat
= lat
.second
;
317 // look at the rowHitFlag set by estimateLatency
319 // @todo: Race condition here where another packet gives rise
320 // to another call to estimateLatency in the meanwhile?
324 Bank
& bank
= dram_pkt
->bank_ref
;
326 if (pageMgmt
== Enums::open
) {
327 bank
.openRow
= dram_pkt
->row
;
328 bank
.freeAt
= schedTime
+ tBURST
+ std::max(accessLat
, tCL
);
329 busBusyUntil
= bank
.freeAt
- tCL
;
332 bank
.tRASDoneAt
= bank
.freeAt
+ tRP
;
333 recordActivate(bank
.freeAt
- tCL
- tRCD
);
334 busBusyUntil
= bank
.freeAt
- tCL
- tRCD
;
336 } else if (pageMgmt
== Enums::close
) {
337 bank
.freeAt
= schedTime
+ tBURST
+ accessLat
+ tRP
+ tRP
;
338 // Work backwards from bank.freeAt to determine activate time
339 recordActivate(bank
.freeAt
- tRP
- tRP
- tCL
- tRCD
);
340 busBusyUntil
= bank
.freeAt
- tRP
- tRP
- tCL
- tRCD
;
341 DPRINTF(DRAMWR
, "processWriteEvent::bank.freeAt for "
342 "banks_id %d is %lld\n",
343 dram_pkt
->rank
* banksPerRank
+ dram_pkt
->bank
,
346 panic("Unknown page management policy chosen\n");
348 DPRINTF(DRAMWR
,"Done writing to address %lld\n",dram_pkt
->addr
);
350 DPRINTF(DRAMWR
,"schedtime is %lld, tBURST is %lld, "
351 "busbusyuntil is %lld\n",
352 schedTime
, tBURST
, busBusyUntil
);
354 dramWriteQueue
.pop_front();
360 DPRINTF(DRAMWR
, "Completed %d writes, bus busy for %lld ticks,"\
361 "banks busy for %lld ticks\n", numWritesThisTime
,
362 busBusyUntil
- temp1
, maxBankFreeAt() - temp2
);
365 avgWrQLen
= dramWriteQueue
.size();
367 // turn the bus back around for reads again
368 busBusyUntil
+= tWTR
;
376 // if there is nothing left in any queue, signal a drain
377 if (dramWriteQueue
.empty() && dramReadQueue
.empty() &&
378 dramRespQueue
.empty () && drainManager
) {
379 drainManager
->signalDrainDone();
383 // Once you're done emptying the write queue, check if there's
384 // anything in the read queue, and call schedule if required
385 schedule(&nextReqEvent
, busBusyUntil
);
389 SimpleDRAM::triggerWrites()
391 DPRINTF(DRAM
, "Writes triggered at %lld\n", curTick());
392 // Flag variable to stop any more read scheduling
395 writeStartTime
= std::max(busBusyUntil
, curTick()) + tWTR
;
397 DPRINTF(DRAM
, "Writes scheduled at %lld\n", writeStartTime
);
399 assert(writeStartTime
>= curTick());
400 assert(!writeEvent
.scheduled());
401 schedule(&writeEvent
, writeStartTime
);
405 SimpleDRAM::addToWriteQueue(PacketPtr pkt
)
407 // only add to the write queue here. whenever the request is
408 // eventually done, set the readyTime, and call schedule()
409 assert(pkt
->isWrite());
411 DRAMPacket
* dram_pkt
= decodeAddr(pkt
);
413 assert(dramWriteQueue
.size() < writeBufferSize
);
414 wrQLenPdf
[dramWriteQueue
.size()]++;
416 DPRINTF(DRAM
, "Adding to write queue\n");
418 dramWriteQueue
.push_back(dram_pkt
);
421 uint32_t bank_id
= banksPerRank
* dram_pkt
->rank
+ dram_pkt
->bank
;
422 assert(bank_id
< ranksPerChannel
* banksPerRank
);
423 perBankWrReqs
[bank_id
]++;
425 avgWrQLen
= dramWriteQueue
.size();
427 // we do not wait for the writes to be send to the actual memory,
428 // but instead take responsibility for the consistency here and
429 // snoop the write queue for any upcoming reads
431 bytesConsumedWr
+= pkt
->getSize();
432 bytesWritten
+= bytesPerCacheLine
;
433 accessAndRespond(pkt
);
435 // If your write buffer is starting to fill up, drain it!
436 if (dramWriteQueue
.size() > writeThreshold
&& !stopReads
){
442 SimpleDRAM::printParams() const
444 // Sanity check print of important parameters
446 "Memory controller %s physical organization\n" \
447 "Bytes per cacheline %d\n" \
448 "Lines per row buffer %d\n" \
449 "Rows per bank %d\n" \
450 "Banks per rank %d\n" \
451 "Ranks per channel %d\n" \
452 "Total mem capacity %u\n",
453 name(), bytesPerCacheLine
,linesPerRowBuffer
, rowsPerBank
,
454 banksPerRank
, ranksPerChannel
, bytesPerCacheLine
*
455 linesPerRowBuffer
* rowsPerBank
* banksPerRank
* ranksPerChannel
);
457 string scheduler
= memSchedPolicy
== Enums::fcfs
? "FCFS" : "FR-FCFS";
458 string address_mapping
= addrMapping
== Enums::openmap
? "OPENMAP" :
460 string page_policy
= pageMgmt
== Enums::open
? "OPEN" : "CLOSE";
463 "Memory controller %s characteristics\n" \
464 "Read buffer size %d\n" \
465 "Write buffer size %d\n" \
466 "Write buffer thresh %d\n" \
468 "Address mapping %s\n" \
470 name(), readBufferSize
, writeBufferSize
, writeThreshold
,
471 scheduler
, address_mapping
, page_policy
);
473 DPRINTF(DRAM
, "Memory controller %s timing specs\n" \
477 "tBURST %d ticks\n" \
481 name(), tRCD
, tCL
, tRP
, tBURST
, tRFC
, tREFI
, tWTR
);
485 SimpleDRAM::printQs() const {
487 list
<DRAMPacket
*>::const_iterator i
;
489 DPRINTF(DRAM
, "===READ QUEUE===\n\n");
490 for (i
= dramReadQueue
.begin() ; i
!= dramReadQueue
.end() ; ++i
) {
491 DPRINTF(DRAM
, "Read %lu\n", (*i
)->addr
);
493 DPRINTF(DRAM
, "\n===RESP QUEUE===\n\n");
494 for (i
= dramRespQueue
.begin() ; i
!= dramRespQueue
.end() ; ++i
) {
495 DPRINTF(DRAM
, "Response %lu\n", (*i
)->addr
);
497 DPRINTF(DRAM
, "\n===WRITE QUEUE===\n\n");
498 for (i
= dramWriteQueue
.begin() ; i
!= dramWriteQueue
.end() ; ++i
) {
499 DPRINTF(DRAM
, "Write %lu\n", (*i
)->addr
);
504 SimpleDRAM::recvTimingReq(PacketPtr pkt
)
506 /// @todo temporary hack to deal with memory corruption issues until
507 /// 4-phase transactions are complete
508 for (int x
= 0; x
< pendingDelete
.size(); x
++)
509 delete pendingDelete
[x
];
510 pendingDelete
.clear();
513 // This is where we enter from the outside world
514 DPRINTF(DRAM
, "Inside recvTimingReq: request %s addr %lld size %d\n",
515 pkt
->cmdString(),pkt
->getAddr(), pkt
->getSize());
519 if (pkt
->getSize() == bytesPerCacheLine
)
522 if (numReqs
% 1000000 == 0)
525 // Calc avg gap between requests
526 if (prevArrival
!= 0) {
527 totGap
+= curTick() - prevArrival
;
529 prevArrival
= curTick();
531 // simply drop inhibited packets for now
532 if (pkt
->memInhibitAsserted()) {
533 DPRINTF(DRAM
,"Inhibited packet -- Dropping it now\n");
534 pendingDelete
.push_back(pkt
);
538 unsigned size
= pkt
->getSize();
539 if (size
> bytesPerCacheLine
)
540 panic("Request size %d is greater than cache line size %d",
541 size
, bytesPerCacheLine
);
544 index
= log2(bytesPerCacheLine
) + 1;
548 if (size
!= 0 && (1 << index
) != size
)
549 index
= log2(bytesPerCacheLine
) + 2;
551 // @todo: Do we really want to do all this before the packet is
552 // actually accepted?
554 /* Index 0 - Size 1 byte
555 Index 1 - Size 2 bytes
556 Index 2 - Size 4 bytes
559 Index 6 - Size 64 bytes
560 Index 7 - Size 0 bytes
561 Index 8 - Non-power-of-2 size */
564 readPktSize
[index
]++;
565 else if (pkt
->isWrite())
566 writePktSize
[index
]++;
568 neitherPktSize
[index
]++;
570 // check local buffers and do not accept if full
572 if (readQueueFull()) {
573 DPRINTF(DRAM
,"Read queue full, not accepting\n");
574 // remember that we have to retry this port
583 } else if (pkt
->isWrite()) {
584 if (writeQueueFull()) {
585 DPRINTF(DRAM
,"Write queue full, not accepting\n");
586 // remember that we have to retry this port
591 addToWriteQueue(pkt
);
596 DPRINTF(DRAM
,"Neither read nor write, ignore timing\n");
597 neitherReadNorWrite
++;
598 accessAndRespond(pkt
);
608 SimpleDRAM::processRespondEvent()
611 "processRespondEvent(): Some req has reached its readyTime\n");
613 PacketPtr pkt
= dramRespQueue
.front()->pkt
;
615 // Actually responds to the requestor
616 bytesConsumedRd
+= pkt
->getSize();
617 bytesRead
+= bytesPerCacheLine
;
618 accessAndRespond(pkt
);
620 DRAMPacket
* dram_pkt
= dramRespQueue
.front();
621 dramRespQueue
.pop_front();
625 avgRdQLen
= dramReadQueue
.size() + dramRespQueue
.size();
627 if (!dramRespQueue
.empty()){
628 assert(dramRespQueue
.front()->readyTime
>= curTick());
629 assert(!respondEvent
.scheduled());
630 schedule(&respondEvent
, dramRespQueue
.front()->readyTime
);
632 // if there is nothing left in any queue, signal a drain
633 if (dramWriteQueue
.empty() && dramReadQueue
.empty() &&
635 drainManager
->signalDrainDone();
642 SimpleDRAM::chooseNextWrite()
644 // This method does the arbitration between requests. The chosen
645 // packet is simply moved to the head of the queue. The other
646 // methods know that this is the place to look. For example, with
647 // FCFS, this method does nothing
648 assert(!dramWriteQueue
.empty());
650 if (dramWriteQueue
.size() == 1) {
651 DPRINTF(DRAMWR
, "chooseNextWrite(): Single element, nothing to do\n");
655 if (memSchedPolicy
== Enums::fcfs
) {
657 // Do nothing, since the correct request is already head
659 } else if (memSchedPolicy
== Enums::frfcfs
) {
661 list
<DRAMPacket
*>::iterator i
= dramWriteQueue
.begin();
662 bool foundRowHit
= false;
663 while (!foundRowHit
&& i
!= dramWriteQueue
.end()) {
664 DRAMPacket
* dram_pkt
= *i
;
665 const Bank
& bank
= dram_pkt
->bank_ref
;
666 if (bank
.openRow
== dram_pkt
->row
) { //FR part
667 DPRINTF(DRAMWR
,"Row buffer hit\n");
668 dramWriteQueue
.erase(i
);
669 dramWriteQueue
.push_front(dram_pkt
);
678 panic("No scheduling policy chosen\n");
680 DPRINTF(DRAMWR
, "chooseNextWrite(): Something chosen\n");
684 SimpleDRAM::chooseNextReq()
686 // This method does the arbitration between requests.
687 // The chosen packet is simply moved to the head of the
688 // queue. The other methods know that this is the place
689 // to look. For example, with FCFS, this method does nothing
690 list
<DRAMPacket
*>::iterator i
;
691 DRAMPacket
* dram_pkt
;
693 if (dramReadQueue
.empty()){
694 DPRINTF(DRAM
, "chooseNextReq(): Returning False\n");
698 if (dramReadQueue
.size() == 1)
701 if (memSchedPolicy
== Enums::fcfs
) {
703 // Do nothing, since the correct request is already head
705 } else if (memSchedPolicy
== Enums::frfcfs
) {
707 for (i
= dramReadQueue
.begin() ; i
!= dramReadQueue
.end() ; ++i
) {
709 const Bank
& bank
= dram_pkt
->bank_ref
;
710 if (bank
.openRow
== dram_pkt
->row
) { //FR part
711 DPRINTF(DRAM
, "Row buffer hit\n");
712 dramReadQueue
.erase(i
);
713 dramReadQueue
.push_front(dram_pkt
);
722 panic("No scheduling policy chosen!\n");
725 DPRINTF(DRAM
,"chooseNextReq(): Chosen something, returning True\n");
730 SimpleDRAM::accessAndRespond(PacketPtr pkt
)
732 DPRINTF(DRAM
, "Responding to Address %lld.. ",pkt
->getAddr());
734 bool needsResponse
= pkt
->needsResponse();
735 // do the actual memory access which also turns the packet into a
739 // turn packet around to go back to requester if response expected
741 // access already turned the packet into a response
742 assert(pkt
->isResponse());
744 // @todo someone should pay for this
745 pkt
->busFirstWordDelay
= pkt
->busLastWordDelay
= 0;
747 // queue the packet in the response queue to be sent out the
749 port
.schedTimingResp(pkt
, curTick() + 1);
753 DPRINTF(DRAM
, "Done\n");
759 SimpleDRAM::estimateLatency(DRAMPacket
* dram_pkt
, Tick inTime
)
761 // If a request reaches a bank at tick 'inTime', how much time
762 // *after* that does it take to finish the request, depending
763 // on bank status and page open policy. Note that this method
764 // considers only the time taken for the actual read or write
765 // to complete, NOT any additional time thereafter for tRAS or
771 const Bank
& bank
= dram_pkt
->bank_ref
;
772 if (pageMgmt
== Enums::open
) { // open-page policy
773 if (bank
.openRow
== dram_pkt
->row
) {
774 // When we have a row-buffer hit,
775 // we don't care about tRAS having expired or not,
776 // but do care about bank being free for access
779 if (bank
.freeAt
< inTime
) {
789 // Row-buffer miss, need to close existing row
790 // once tRAS has expired, then open the new one,
791 // then add cas latency.
792 Tick freeTime
= std::max(bank
.tRASDoneAt
, bank
.freeAt
);
794 if (freeTime
> inTime
)
795 accLat
+= freeTime
- inTime
;
797 accLat
+= tRP
+ tRCD
+ tCL
;
798 bankLat
+= tRP
+ tRCD
+ tCL
;
800 } else if (pageMgmt
== Enums::close
) {
802 // With a close page policy, no notion of
804 if (bank
.freeAt
> inTime
)
805 accLat
+= bank
.freeAt
- inTime
;
807 // page already closed, simply open the row, and
809 accLat
+= tRCD
+ tCL
;
810 bankLat
+= tRCD
+ tCL
;
812 panic("No page management policy chosen\n");
814 DPRINTF(DRAM
, "Returning < %lld, %lld > from estimateLatency()\n",
817 return make_pair(bankLat
, accLat
);
821 SimpleDRAM::processNextReqEvent()
827 SimpleDRAM::recordActivate(Tick act_tick
)
829 assert(actTicks
.size() == activationLimit
);
831 DPRINTF(DRAM
, "Activate at tick %d\n", act_tick
);
834 if (actTicks
.back() && (act_tick
- actTicks
.back()) < tXAW
) {
835 panic("Got %d activates in window %d (%d - %d) which is smaller "
836 "than %d\n", activationLimit
, act_tick
- actTicks
.back(),
837 act_tick
, actTicks
.back(), tXAW
);
840 // shift the times used for the book keeping, the last element
841 // (highest index) is the oldest one and hence the lowest value
844 // record an new activation (in the future)
845 actTicks
.push_front(act_tick
);
847 // cannot activate more than X times in time window tXAW, push the
848 // next one (the X + 1'st activate) to be tXAW away from the
849 // oldest in our window of X
850 if (actTicks
.back() && (act_tick
- actTicks
.back()) < tXAW
) {
851 DPRINTF(DRAM
, "Enforcing tXAW with X = %d, next activate no earlier "
852 "than %d\n", activationLimit
, actTicks
.back() + tXAW
);
853 for(int i
= 0; i
< ranksPerChannel
; i
++)
854 for(int j
= 0; j
< banksPerRank
; j
++)
855 // next activate must not happen before end of window
856 banks
[i
][j
].freeAt
= std::max(banks
[i
][j
].freeAt
,
857 actTicks
.back() + tXAW
);
862 SimpleDRAM::doDRAMAccess(DRAMPacket
* dram_pkt
)
865 DPRINTF(DRAM
, "Timing access to addr %lld, rank/bank/row %d %d %d\n",
866 dram_pkt
->addr
, dram_pkt
->rank
, dram_pkt
->bank
, dram_pkt
->row
);
868 assert(curTick() >= prevdramaccess
);
869 prevdramaccess
= curTick();
871 // estimate the bank and access latency
872 pair
<Tick
, Tick
> lat
= estimateLatency(dram_pkt
, curTick());
873 Tick bankLat
= lat
.first
;
874 Tick accessLat
= lat
.second
;
876 // This request was woken up at this time based on a prior call
877 // to estimateLatency(). However, between then and now, both the
878 // accessLatency and/or busBusyUntil may have changed. We need
879 // to correct for that.
881 Tick addDelay
= (curTick() + accessLat
< busBusyUntil
) ?
882 busBusyUntil
- (curTick() + accessLat
) : 0;
884 Bank
& bank
= dram_pkt
->bank_ref
;
887 if (pageMgmt
== Enums::open
) {
888 bank
.openRow
= dram_pkt
->row
;
889 bank
.freeAt
= curTick() + addDelay
+ accessLat
;
890 // If you activated a new row do to this access, the next access
891 // will have to respect tRAS for this bank. Assume tRAS ~= 3 * tRP.
892 // Also need to account for t_XAW
894 bank
.tRASDoneAt
= bank
.freeAt
+ tRP
;
895 recordActivate(bank
.freeAt
- tCL
- tRCD
); //since this is open page,
898 } else if (pageMgmt
== Enums::close
) { // accounting for tRAS also
899 // assuming that tRAS ~= 3 * tRP, and tRC ~= 4 * tRP, as is common
900 // (refer Jacob/Ng/Wang and Micron datasheets)
901 bank
.freeAt
= curTick() + addDelay
+ accessLat
+ tRP
+ tRP
;
902 recordActivate(bank
.freeAt
- tRP
- tRP
- tCL
- tRCD
); //essentially (freeAt - tRC)
903 DPRINTF(DRAM
,"doDRAMAccess::bank.freeAt is %lld\n",bank
.freeAt
);
905 panic("No page management policy chosen\n");
907 // Update request parameters
908 dram_pkt
->readyTime
= curTick() + addDelay
+ accessLat
+ tBURST
;
911 DPRINTF(DRAM
, "Req %lld: curtick is %lld accessLat is %d " \
912 "readytime is %lld busbusyuntil is %lld. " \
913 "Scheduling at readyTime\n", dram_pkt
->addr
,
914 curTick(), accessLat
, dram_pkt
->readyTime
, busBusyUntil
);
916 // Make sure requests are not overlapping on the databus
917 assert (dram_pkt
->readyTime
- busBusyUntil
>= tBURST
);
920 busBusyUntil
= dram_pkt
->readyTime
;
922 DPRINTF(DRAM
,"Access time is %lld\n",
923 dram_pkt
->readyTime
- dram_pkt
->entryTime
);
926 totMemAccLat
+= dram_pkt
->readyTime
- dram_pkt
->entryTime
;
927 totBankLat
+= bankLat
;
929 totQLat
+= dram_pkt
->readyTime
- dram_pkt
->entryTime
- bankLat
- tBURST
;
934 // At this point we're done dealing with the request
935 // It will be moved to a separate response queue with a
936 // correct readyTime, and eventually be sent back at that
940 // The absolute soonest you have to start thinking about the
941 // next request is the longest access time that can occur before
942 // busBusyUntil. Assuming you need to meet tRAS, then precharge,
943 // open a new row, and access, it is ~4*tRCD.
946 Tick newTime
= (busBusyUntil
> 4 * tRCD
) ?
947 std::max(busBusyUntil
- 4 * tRCD
, curTick()) :
950 if (!nextReqEvent
.scheduled() && !stopReads
){
951 schedule(&nextReqEvent
, newTime
);
953 if (newTime
< nextReqEvent
.when())
954 reschedule(&nextReqEvent
, newTime
);
961 SimpleDRAM::moveToRespQ()
963 // Remove from read queue
964 DRAMPacket
* dram_pkt
= dramReadQueue
.front();
965 dramReadQueue
.pop_front();
967 // Insert into response queue sorted by readyTime
968 // It will be sent back to the requestor at its
970 if (dramRespQueue
.empty()) {
971 dramRespQueue
.push_front(dram_pkt
);
972 assert(!respondEvent
.scheduled());
973 assert(dram_pkt
->readyTime
>= curTick());
974 schedule(&respondEvent
, dram_pkt
->readyTime
);
977 std::list
<DRAMPacket
*>::iterator i
= dramRespQueue
.begin();
978 while (!done
&& i
!= dramRespQueue
.end()) {
979 if ((*i
)->readyTime
> dram_pkt
->readyTime
) {
980 dramRespQueue
.insert(i
, dram_pkt
);
987 dramRespQueue
.push_back(dram_pkt
);
989 assert(respondEvent
.scheduled());
991 if (dramRespQueue
.front()->readyTime
< respondEvent
.when()) {
992 assert(dramRespQueue
.front()->readyTime
>= curTick());
993 reschedule(&respondEvent
, dramRespQueue
.front()->readyTime
);
1004 SimpleDRAM::scheduleNextReq()
1006 DPRINTF(DRAM
, "Reached scheduleNextReq()\n");
1008 // Figure out which request goes next, and move it to front()
1009 if (!chooseNextReq()) {
1010 // In the case there is no read request to go next, see if we
1011 // are asked to drain, and if so trigger writes, this also
1012 // ensures that if we hit the write limit we will do this
1013 // multiple times until we are completely drained
1014 if (drainManager
&& !dramWriteQueue
.empty() && !writeEvent
.scheduled())
1017 doDRAMAccess(dramReadQueue
.front());
1022 SimpleDRAM::maxBankFreeAt() const
1026 for(int i
= 0; i
< ranksPerChannel
; i
++)
1027 for(int j
= 0; j
< banksPerRank
; j
++)
1028 banksFree
= std::max(banks
[i
][j
].freeAt
, banksFree
);
1034 SimpleDRAM::processRefreshEvent()
1036 DPRINTF(DRAM
, "Refreshing at tick %ld\n", curTick());
1038 Tick banksFree
= std::max(curTick(), maxBankFreeAt()) + tRFC
;
1040 for(int i
= 0; i
< ranksPerChannel
; i
++)
1041 for(int j
= 0; j
< banksPerRank
; j
++)
1042 banks
[i
][j
].freeAt
= banksFree
;
1044 schedule(&refreshEvent
, curTick() + tREFI
);
1048 SimpleDRAM::regStats()
1050 using namespace Stats
;
1052 AbstractMemory::regStats();
1055 .name(name() + ".readReqs")
1056 .desc("Total number of read requests seen");
1059 .name(name() + ".writeReqs")
1060 .desc("Total number of write requests seen");
1063 .name(name() + ".servicedByWrQ")
1064 .desc("Number of read reqs serviced by write Q");
1067 .name(name() + ".cpureqs")
1068 .desc("Reqs generatd by CPU via cache - shady");
1071 .name(name() + ".neitherReadNorWrite")
1072 .desc("Reqs where no action is needed");
1075 .init(banksPerRank
* ranksPerChannel
)
1076 .name(name() + ".perBankRdReqs")
1077 .desc("Track reads on a per bank basis");
1080 .init(banksPerRank
* ranksPerChannel
)
1081 .name(name() + ".perBankWrReqs")
1082 .desc("Track writes on a per bank basis");
1085 .name(name() + ".avgRdQLen")
1086 .desc("Average read queue length over time")
1090 .name(name() + ".avgWrQLen")
1091 .desc("Average write queue length over time")
1095 .name(name() + ".totQLat")
1096 .desc("Total cycles spent in queuing delays");
1099 .name(name() + ".totBankLat")
1100 .desc("Total cycles spent in bank access");
1103 .name(name() + ".totBusLat")
1104 .desc("Total cycles spent in databus access");
1107 .name(name() + ".totMemAccLat")
1108 .desc("Sum of mem lat for all requests");
1111 .name(name() + ".avgQLat")
1112 .desc("Average queueing delay per request")
1115 avgQLat
= totQLat
/ (readReqs
- servicedByWrQ
);
1118 .name(name() + ".avgBankLat")
1119 .desc("Average bank access latency per request")
1122 avgBankLat
= totBankLat
/ (readReqs
- servicedByWrQ
);
1125 .name(name() + ".avgBusLat")
1126 .desc("Average bus latency per request")
1129 avgBusLat
= totBusLat
/ (readReqs
- servicedByWrQ
);
1132 .name(name() + ".avgMemAccLat")
1133 .desc("Average memory access latency")
1136 avgMemAccLat
= totMemAccLat
/ (readReqs
- servicedByWrQ
);
1139 .name(name() + ".numRdRetry")
1140 .desc("Number of times rd buffer was full causing retry");
1143 .name(name() + ".numWrRetry")
1144 .desc("Number of times wr buffer was full causing retry");
1147 .name(name() + ".readRowHits")
1148 .desc("Number of row buffer hits during reads");
1151 .name(name() + ".writeRowHits")
1152 .desc("Number of row buffer hits during writes");
1155 .name(name() + ".readRowHitRate")
1156 .desc("Row buffer hit rate for reads")
1159 readRowHitRate
= (readRowHits
/ (readReqs
- servicedByWrQ
)) * 100;
1162 .name(name() + ".writeRowHitRate")
1163 .desc("Row buffer hit rate for writes")
1166 writeRowHitRate
= (writeRowHits
/ writeReqs
) * 100;
1169 .init(log2(bytesPerCacheLine
)+3)
1170 .name(name() + ".readPktSize")
1171 .desc("Categorize read packet sizes");
1174 .init(log2(bytesPerCacheLine
)+3)
1175 .name(name() + ".writePktSize")
1176 .desc("categorize write packet sizes");
1179 .init(log2(bytesPerCacheLine
)+3)
1180 .name(name() + ".neitherpktsize")
1181 .desc("categorize neither packet sizes");
1184 .init(readBufferSize
+ 1)
1185 .name(name() + ".rdQLenPdf")
1186 .desc("What read queue length does an incoming req see");
1189 .init(writeBufferSize
+ 1)
1190 .name(name() + ".wrQLenPdf")
1191 .desc("What write queue length does an incoming req see");
1195 .name(name() + ".bytesRead")
1196 .desc("Total number of bytes read from memory");
1199 .name(name() + ".bytesWritten")
1200 .desc("Total number of bytes written to memory");
1203 .name(name() + ".bytesConsumedRd")
1204 .desc("bytesRead derated as per pkt->getSize()");
1207 .name(name() + ".bytesConsumedWr")
1208 .desc("bytesWritten derated as per pkt->getSize()");
1211 .name(name() + ".avgRdBW")
1212 .desc("Average achieved read bandwidth in MB/s")
1215 avgRdBW
= (bytesRead
/ 1000000) / simSeconds
;
1218 .name(name() + ".avgWrBW")
1219 .desc("Average achieved write bandwidth in MB/s")
1222 avgWrBW
= (bytesWritten
/ 1000000) / simSeconds
;
1225 .name(name() + ".avgConsumedRdBW")
1226 .desc("Average consumed read bandwidth in MB/s")
1229 avgConsumedRdBW
= (bytesConsumedRd
/ 1000000) / simSeconds
;
1232 .name(name() + ".avgConsumedWrBW")
1233 .desc("Average consumed write bandwidth in MB/s")
1236 avgConsumedWrBW
= (bytesConsumedWr
/ 1000000) / simSeconds
;
1239 .name(name() + ".peakBW")
1240 .desc("Theoretical peak bandwidth in MB/s")
1243 peakBW
= (SimClock::Frequency
/ tBURST
) * bytesPerCacheLine
/ 1000000;
1246 .name(name() + ".busUtil")
1247 .desc("Data bus utilization in percentage")
1250 busUtil
= (avgRdBW
+ avgWrBW
) / peakBW
* 100;
1253 .name(name() + ".totGap")
1254 .desc("Total gap between requests");
1257 .name(name() + ".avgGap")
1258 .desc("Average gap between requests")
1261 avgGap
= totGap
/ (readReqs
+ writeReqs
);
1265 SimpleDRAM::recvFunctional(PacketPtr pkt
)
1267 // rely on the abstract memory
1268 functionalAccess(pkt
);
1272 SimpleDRAM::getSlavePort(const string
&if_name
, PortID idx
)
1274 if (if_name
!= "port") {
1275 return MemObject::getSlavePort(if_name
, idx
);
1282 SimpleDRAM::drain(DrainManager
*dm
)
1284 unsigned int count
= port
.drain(dm
);
1286 // if there is anything in any of our internal queues, keep track
1288 if (!(dramWriteQueue
.empty() && dramReadQueue
.empty() &&
1289 dramRespQueue
.empty())) {
1290 DPRINTF(Drain
, "DRAM controller not drained, write: %d, read: %d,"
1291 " resp: %d\n", dramWriteQueue
.size(), dramReadQueue
.size(),
1292 dramRespQueue
.size());
1295 // the only part that is not drained automatically over time
1296 // is the write queue, thus trigger writes if there are any
1297 // waiting and no reads waiting, otherwise wait until the
1299 if (dramReadQueue
.empty() && !dramWriteQueue
.empty() &&
1300 !writeEvent
.scheduled())
1305 setDrainState(Drainable::Draining
);
1307 setDrainState(Drainable::Drained
);
1311 SimpleDRAM::MemoryPort::MemoryPort(const std::string
& name
, SimpleDRAM
& _memory
)
1312 : QueuedSlavePort(name
, &_memory
, queue
), queue(_memory
, *this),
1317 SimpleDRAM::MemoryPort::getAddrRanges() const
1319 AddrRangeList ranges
;
1320 ranges
.push_back(memory
.getAddrRange());
1325 SimpleDRAM::MemoryPort::recvFunctional(PacketPtr pkt
)
1327 pkt
->pushLabel(memory
.name());
1329 if (!queue
.checkFunctional(pkt
)) {
1330 // Default implementation of SimpleTimingPort::recvFunctional()
1331 // calls recvAtomic() and throws away the latency; we can save a
1332 // little here by just not calculating the latency.
1333 memory
.recvFunctional(pkt
);
1340 SimpleDRAM::MemoryPort::recvAtomic(PacketPtr pkt
)
1342 return memory
.recvAtomic(pkt
);
1346 SimpleDRAM::MemoryPort::recvTimingReq(PacketPtr pkt
)
1348 // pass it to the memory controller
1349 return memory
.recvTimingReq(pkt
);
1353 SimpleDRAMParams::create()
1355 return new SimpleDRAM(this);