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),
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 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)
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 cache line size from the connected port
94 bytesPerCacheLine
= port
.peerBlockSize();
96 // we could deal with plenty options here, but for now do a quick
98 if (bytesPerCacheLine
!= 64 && bytesPerCacheLine
!= 32)
99 panic("Unexpected cache line size %d", bytesPerCacheLine
);
101 // determine the rows per bank by looking at the total capacity
102 uint64_t capacity
= AbstractMemory::size();
104 while (i
< 64 && capacity
> ((1 << i
))) {
108 // rounded up to nearest power of two
109 DPRINTF(DRAM
, "i is %lld\n", i
);
112 DPRINTF(DRAM
, "Memory capacity %lld (%lld) bytes\n", capacity
,
113 AbstractMemory::size());
114 rowsPerBank
= capacity
/ (bytesPerCacheLine
* linesPerRowBuffer
*
115 banksPerRank
* ranksPerChannel
);
120 SimpleDRAM::startup()
122 // print the configuration of the controller
125 // kick off the refresh
126 schedule(&refreshEvent
, curTick() + tREFI
);
131 SimpleDRAM::recvAtomic(PacketPtr pkt
)
133 DPRINTF(DRAM
, "recvAtomic: %s 0x%x\n", pkt
->cmdString(), pkt
->getAddr());
135 // do the actual memory access and turn the packet into a response
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
;
148 SimpleDRAM::readQueueFull() const
150 DPRINTF(DRAM
, "Read queue limit %d current size %d\n",
151 readBufferSize
, dramReadQueue
.size() + dramRespQueue
.size());
153 return (dramReadQueue
.size() + dramRespQueue
.size()) == readBufferSize
;
157 SimpleDRAM::writeQueueFull() const
159 DPRINTF(DRAM
, "Write queue limit %d current size %d\n",
160 writeBufferSize
, dramWriteQueue
.size());
161 return dramWriteQueue
.size() == writeBufferSize
;
165 SimpleDRAM::DRAMPacket
*
166 SimpleDRAM::decodeAddr(PacketPtr pkt
)
172 Addr addr
= pkt
->getAddr();
175 // truncate the address to the access granularity
176 addr
= addr
/ bytesPerCacheLine
;
178 if (addrMapping
== Enums::openmap
) {
179 addr
= addr
/ linesPerRowBuffer
;
181 bank
= addr
% banksPerRank
;
182 addr
= addr
/ banksPerRank
;
184 rank
= addr
% ranksPerChannel
;
185 addr
= addr
/ ranksPerChannel
;
187 row
= addr
% rowsPerBank
;
188 addr
= addr
/ rowsPerBank
;
189 } else if (addrMapping
== Enums::closemap
) {
190 bank
= addr
% banksPerRank
;
191 addr
= addr
/ banksPerRank
;
193 rank
= addr
% ranksPerChannel
;
194 addr
= addr
/ ranksPerChannel
;
196 addr
= addr
/ linesPerRowBuffer
;
198 row
= addr
% rowsPerBank
;
199 addr
= addr
/ rowsPerBank
;
201 panic("Unknown address mapping policy chosen!");
203 assert(rank
< ranksPerChannel
);
204 assert(bank
< banksPerRank
);
205 assert(row
< rowsPerBank
);
207 DPRINTF(DRAM
, "Address: %lld Rank %d Bank %d Row %d\n",
208 temp
, rank
, bank
, row
);
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
,
219 SimpleDRAM::addToReadQueue(PacketPtr pkt
)
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());
225 // First check write buffer to see if the data is already at
227 std::list
<DRAMPacket
*>::const_iterator i
;
228 Addr addr
= pkt
->getAddr();
230 // @todo: add size check
231 for (i
= dramWriteQueue
.begin(); i
!= dramWriteQueue
.end(); ++i
) {
232 if ((*i
)->addr
== addr
){
234 DPRINTF(DRAM
,"Serviced by write Q\n");
235 bytesRead
+= bytesPerCacheLine
;
236 bytesConsumedRd
+= pkt
->getSize();
237 accessAndRespond(pkt
);
242 DRAMPacket
* dram_pkt
= decodeAddr(pkt
);
244 assert(dramReadQueue
.size() + dramRespQueue
.size() < readBufferSize
);
245 rdQLenPdf
[dramReadQueue
.size() + dramRespQueue
.size()]++;
247 DPRINTF(DRAM
, "Adding to read queue\n");
249 dramReadQueue
.push_back(dram_pkt
);
252 uint32_t bank_id
= banksPerRank
* dram_pkt
->rank
+ dram_pkt
->bank
;
253 assert(bank_id
< ranksPerChannel
* banksPerRank
);
254 perBankRdReqs
[bank_id
]++;
256 avgRdQLen
= dramReadQueue
.size() + dramRespQueue
.size();
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);
266 SimpleDRAM::processWriteEvent()
268 assert(!dramWriteQueue
.empty());
269 uint32_t numWritesThisTime
= 0;
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());
275 // @todo: are there any dangers with the untimed while loop?
276 while (!dramWriteQueue
.empty()) {
277 if (numWritesThisTime
> writeThreshold
)
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
);
285 DPRINTF(DRAMWR
, "Asking for latency estimate at %lld\n",
288 pair
<Tick
, Tick
> lat
= estimateLatency(dram_pkt
, schedTime
+ tBURST
);
289 Tick accessLat
= lat
.second
;
291 // look at the rowHitFlag set by estimateLatency
293 // @todo: Race condition here where another packet gives rise
294 // to another call to estimateLatency in the meanwhile?
298 Bank
& bank
= dram_pkt
->bank_ref
;
300 if (pageMgmt
== Enums::open
) {
301 bank
.openRow
= dram_pkt
->row
;
302 bank
.freeAt
= schedTime
+ tBURST
+ accessLat
;
305 bank
.tRASDoneAt
= bank
.freeAt
+ tRP
;
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
,
314 panic("Unknown page management policy chosen\n");
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
319 busBusyUntil
= schedTime
+ tBURST
;
320 DPRINTF(DRAMWR
,"Done writing to address %lld\n",dram_pkt
->addr
);
323 DPRINTF(DRAMWR
,"schedtime is %lld, tBURST is %lld, "
324 "busbusyuntil is %lld\n",
325 schedTime
, tBURST
, busBusyUntil
);
327 dramWriteQueue
.pop_front();
333 DPRINTF(DRAMWR
, "Completed %d writes, bus busy for %lld ticks,"\
334 "banks busy for %lld ticks\n", numWritesThisTime
,
335 busBusyUntil
- temp1
, maxBankFreeAt() - temp2
);
338 avgWrQLen
= dramWriteQueue
.size();
340 // turn the bus back around for reads again
341 busBusyUntil
+= tWTR
;
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();
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
);
362 SimpleDRAM::triggerWrites()
364 DPRINTF(DRAM
, "Writes triggered at %lld\n", curTick());
365 // Flag variable to stop any more read scheduling
368 writeStartTime
= std::max(busBusyUntil
, curTick()) + tWTR
;
370 DPRINTF(DRAM
, "Writes scheduled at %lld\n", writeStartTime
);
372 assert(writeStartTime
>= curTick());
373 assert(!writeEvent
.scheduled());
374 schedule(&writeEvent
, writeStartTime
);
378 SimpleDRAM::addToWriteQueue(PacketPtr pkt
)
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());
384 DRAMPacket
* dram_pkt
= decodeAddr(pkt
);
386 assert(dramWriteQueue
.size() < writeBufferSize
);
387 wrQLenPdf
[dramWriteQueue
.size()]++;
389 DPRINTF(DRAM
, "Adding to write queue\n");
391 dramWriteQueue
.push_back(dram_pkt
);
394 uint32_t bank_id
= banksPerRank
* dram_pkt
->rank
+ dram_pkt
->bank
;
395 assert(bank_id
< ranksPerChannel
* banksPerRank
);
396 perBankWrReqs
[bank_id
]++;
398 avgWrQLen
= dramWriteQueue
.size();
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
404 bytesConsumedWr
+= pkt
->getSize();
405 bytesWritten
+= bytesPerCacheLine
;
406 accessAndRespond(pkt
);
408 // If your write buffer is starting to fill up, drain it!
409 if (dramWriteQueue
.size() > writeThreshold
&& !stopReads
){
415 SimpleDRAM::printParams() const
417 // Sanity check print of important parameters
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
);
430 string scheduler
= memSchedPolicy
== Enums::fcfs
? "FCFS" : "FR-FCFS";
431 string address_mapping
= addrMapping
== Enums::openmap
? "OPENMAP" :
433 string page_policy
= pageMgmt
== Enums::open
? "OPEN" : "CLOSE";
436 "Memory controller %s characteristics\n" \
437 "Read buffer size %d\n" \
438 "Write buffer size %d\n" \
439 "Write buffer thresh %d\n" \
441 "Address mapping %s\n" \
443 name(), readBufferSize
, writeBufferSize
, writeThreshold
,
444 scheduler
, address_mapping
, page_policy
);
446 DPRINTF(DRAM
, "Memory controller %s timing specs\n" \
450 "tBURST %d ticks\n" \
454 name(), tRCD
, tCL
, tRP
, tBURST
, tRFC
, tREFI
, tWTR
);
458 SimpleDRAM::printQs() const {
460 list
<DRAMPacket
*>::const_iterator i
;
462 DPRINTF(DRAM
, "===READ QUEUE===\n\n");
463 for (i
= dramReadQueue
.begin() ; i
!= dramReadQueue
.end() ; ++i
) {
464 DPRINTF(DRAM
, "Read %lu\n", (*i
)->addr
);
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
);
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
);
477 SimpleDRAM::recvTimingReq(PacketPtr pkt
)
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();
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());
492 if (pkt
->getSize() == bytesPerCacheLine
)
495 if (numReqs
% 1000000 == 0)
498 // Calc avg gap between requests
499 if (prevArrival
!= 0) {
500 totGap
+= curTick() - prevArrival
;
502 prevArrival
= curTick();
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
);
511 unsigned size
= pkt
->getSize();
512 if (size
> bytesPerCacheLine
)
513 panic("Request size %d is greater than cache line size %d",
514 size
, bytesPerCacheLine
);
517 index
= log2(bytesPerCacheLine
) + 1;
521 if (size
!= 0 && (1 << index
) != size
)
522 index
= log2(bytesPerCacheLine
) + 2;
524 // @todo: Do we really want to do all this before the packet is
525 // actually accepted?
527 /* Index 0 - Size 1 byte
528 Index 1 - Size 2 bytes
529 Index 2 - Size 4 bytes
532 Index 6 - Size 64 bytes
533 Index 7 - Size 0 bytes
534 Index 8 - Non-power-of-2 size */
537 readPktSize
[index
]++;
538 else if (pkt
->isWrite())
539 writePktSize
[index
]++;
541 neitherPktSize
[index
]++;
543 // check local buffers and do not accept if full
545 if (readQueueFull()) {
546 DPRINTF(DRAM
,"Read queue full, not accepting\n");
547 // remember that we have to retry this port
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
564 addToWriteQueue(pkt
);
569 DPRINTF(DRAM
,"Neither read nor write, ignore timing\n");
570 neitherReadNorWrite
++;
571 accessAndRespond(pkt
);
581 SimpleDRAM::processRespondEvent()
584 "processRespondEvent(): Some req has reached its readyTime\n");
586 PacketPtr pkt
= dramRespQueue
.front()->pkt
;
588 // Actually responds to the requestor
589 bytesConsumedRd
+= pkt
->getSize();
590 bytesRead
+= bytesPerCacheLine
;
591 accessAndRespond(pkt
);
593 DRAMPacket
* dram_pkt
= dramRespQueue
.front();
594 dramRespQueue
.pop_front();
598 avgRdQLen
= dramReadQueue
.size() + dramRespQueue
.size();
600 if (!dramRespQueue
.empty()){
601 assert(dramRespQueue
.front()->readyTime
>= curTick());
602 assert(!respondEvent
.scheduled());
603 schedule(&respondEvent
, dramRespQueue
.front()->readyTime
);
605 // if there is nothing left in any queue, signal a drain
606 if (dramWriteQueue
.empty() && dramReadQueue
.empty() &&
608 drainManager
->signalDrainDone();
615 SimpleDRAM::chooseNextWrite()
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());
623 if (dramWriteQueue
.size() == 1) {
624 DPRINTF(DRAMWR
, "chooseNextWrite(): Single element, nothing to do\n");
628 if (memSchedPolicy
== Enums::fcfs
) {
630 // Do nothing, since the correct request is already head
632 } else if (memSchedPolicy
== Enums::frfcfs
) {
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
);
651 panic("No scheduling policy chosen\n");
653 DPRINTF(DRAMWR
, "chooseNextWrite(): Something chosen\n");
657 SimpleDRAM::chooseNextReq()
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
;
666 if (dramReadQueue
.empty()){
667 DPRINTF(DRAM
, "chooseNextReq(): Returning False\n");
671 if (dramReadQueue
.size() == 1)
674 if (memSchedPolicy
== Enums::fcfs
) {
676 // Do nothing, since the correct request is already head
678 } else if (memSchedPolicy
== Enums::frfcfs
) {
680 for (i
= dramReadQueue
.begin() ; i
!= dramReadQueue
.end() ; ++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
);
695 panic("No scheduling policy chosen!\n");
698 DPRINTF(DRAM
,"chooseNextReq(): Chosen something, returning True\n");
703 SimpleDRAM::accessAndRespond(PacketPtr pkt
)
705 DPRINTF(DRAM
, "Responding to Address %lld.. ",pkt
->getAddr());
707 bool needsResponse
= pkt
->needsResponse();
708 // do the actual memory access which also turns the packet into a
712 // turn packet around to go back to requester if response expected
714 // access already turned the packet into a response
715 assert(pkt
->isResponse());
717 // queue the packet in the response queue to be sent out the
719 port
.schedTimingResp(pkt
, curTick() + 1);
723 DPRINTF(DRAM
, "Done\n");
729 SimpleDRAM::estimateLatency(DRAMPacket
* dram_pkt
, Tick inTime
)
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
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
749 if (bank
.freeAt
< inTime
) {
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
);
764 if (freeTime
> inTime
)
765 accLat
+= freeTime
- inTime
;
767 accLat
+= tRP
+ tRCD
+ tCL
;
768 bankLat
+= tRP
+ tRCD
+ tCL
;
770 } else if (pageMgmt
== Enums::close
) {
772 // With a close page policy, no notion of
774 if (bank
.freeAt
> inTime
)
775 accLat
+= bank
.freeAt
- inTime
;
777 // page already closed, simply open the row, and
779 accLat
+= tRCD
+ tCL
;
780 bankLat
+= tRCD
+ tCL
;
782 panic("No page management policy chosen\n");
784 DPRINTF(DRAM
, "Returning %lld from estimateLatency()\n",accLat
);
786 return make_pair(bankLat
, accLat
);
790 SimpleDRAM::processNextReqEvent()
796 SimpleDRAM::doDRAMAccess(DRAMPacket
* dram_pkt
)
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
);
802 assert(curTick() >= prevdramaccess
);
803 prevdramaccess
= curTick();
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
;
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.
815 Tick addDelay
= (curTick() + accessLat
< busBusyUntil
) ?
816 busBusyUntil
- (curTick() + accessLat
) : 0;
818 Bank
& bank
= dram_pkt
->bank_ref
;
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
827 bank
.tRASDoneAt
= bank
.freeAt
+ tRP
;
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
);
835 panic("No page management policy chosen\n");
837 // Update request parameters
838 dram_pkt
->readyTime
= curTick() + addDelay
+ accessLat
+ tBURST
;
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
);
846 // Make sure requests are not overlapping on the databus
847 assert (dram_pkt
->readyTime
- busBusyUntil
>= tBURST
);
850 busBusyUntil
= dram_pkt
->readyTime
;
852 DPRINTF(DRAM
,"Access time is %lld\n",
853 dram_pkt
->readyTime
- dram_pkt
->entryTime
);
856 totMemAccLat
+= dram_pkt
->readyTime
- dram_pkt
->entryTime
;
857 totBankLat
+= bankLat
;
859 totQLat
+= dram_pkt
->readyTime
- dram_pkt
->entryTime
- bankLat
- tBURST
;
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
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.
876 Tick newTime
= (busBusyUntil
> 4 * tRCD
) ?
877 std::max(busBusyUntil
- 4 * tRCD
, curTick()) :
880 if (!nextReqEvent
.scheduled() && !stopReads
){
881 schedule(&nextReqEvent
, newTime
);
883 if (newTime
< nextReqEvent
.when())
884 reschedule(&nextReqEvent
, newTime
);
891 SimpleDRAM::moveToRespQ()
893 // Remove from read queue
894 DRAMPacket
* dram_pkt
= dramReadQueue
.front();
895 dramReadQueue
.pop_front();
897 // Insert into response queue sorted by readyTime
898 // It will be sent back to the requestor at its
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
);
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
);
917 dramRespQueue
.push_back(dram_pkt
);
919 assert(respondEvent
.scheduled());
921 if (dramRespQueue
.front()->readyTime
< respondEvent
.when()) {
922 assert(dramRespQueue
.front()->readyTime
>= curTick());
923 reschedule(&respondEvent
, dramRespQueue
.front()->readyTime
);
934 SimpleDRAM::scheduleNextReq()
936 DPRINTF(DRAM
, "Reached scheduleNextReq()\n");
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())
947 doDRAMAccess(dramReadQueue
.front());
952 SimpleDRAM::maxBankFreeAt() const
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
);
964 SimpleDRAM::processRefreshEvent()
966 DPRINTF(DRAM
, "Refreshing at tick %ld\n", curTick());
968 Tick banksFree
= std::max(curTick(), maxBankFreeAt()) + tRFC
;
970 for(int i
= 0; i
< ranksPerChannel
; i
++)
971 for(int j
= 0; j
< banksPerRank
; j
++)
972 banks
[i
][j
].freeAt
= banksFree
;
974 schedule(&refreshEvent
, curTick() + tREFI
);
978 SimpleDRAM::regStats()
980 using namespace Stats
;
982 AbstractMemory::regStats();
985 .name(name() + ".readReqs")
986 .desc("Total number of read requests seen");
989 .name(name() + ".writeReqs")
990 .desc("Total number of write requests seen");
993 .name(name() + ".servicedByWrQ")
994 .desc("Number of read reqs serviced by write Q");
997 .name(name() + ".cpureqs")
998 .desc("Reqs generatd by CPU via cache - shady");
1001 .name(name() + ".neitherReadNorWrite")
1002 .desc("Reqs where no action is needed");
1005 .init(banksPerRank
* ranksPerChannel
)
1006 .name(name() + ".perBankRdReqs")
1007 .desc("Track reads on a per bank basis");
1010 .init(banksPerRank
* ranksPerChannel
)
1011 .name(name() + ".perBankWrReqs")
1012 .desc("Track writes on a per bank basis");
1015 .name(name() + ".avgRdQLen")
1016 .desc("Average read queue length over time")
1020 .name(name() + ".avgWrQLen")
1021 .desc("Average write queue length over time")
1025 .name(name() + ".totQLat")
1026 .desc("Total cycles spent in queuing delays");
1029 .name(name() + ".totBankLat")
1030 .desc("Total cycles spent in bank access");
1033 .name(name() + ".totBusLat")
1034 .desc("Total cycles spent in databus access");
1037 .name(name() + ".totMemAccLat")
1038 .desc("Sum of mem lat for all requests");
1041 .name(name() + ".avgQLat")
1042 .desc("Average queueing delay per request")
1045 avgQLat
= totQLat
/ (readReqs
- servicedByWrQ
);
1048 .name(name() + ".avgBankLat")
1049 .desc("Average bank access latency per request")
1052 avgBankLat
= totBankLat
/ (readReqs
- servicedByWrQ
);
1055 .name(name() + ".avgBusLat")
1056 .desc("Average bus latency per request")
1059 avgBusLat
= totBusLat
/ (readReqs
- servicedByWrQ
);
1062 .name(name() + ".avgMemAccLat")
1063 .desc("Average memory access latency")
1066 avgMemAccLat
= totMemAccLat
/ (readReqs
- servicedByWrQ
);
1069 .name(name() + ".numRdRetry")
1070 .desc("Number of times rd buffer was full causing retry");
1073 .name(name() + ".numWrRetry")
1074 .desc("Number of times wr buffer was full causing retry");
1077 .name(name() + ".readRowHits")
1078 .desc("Number of row buffer hits during reads");
1081 .name(name() + ".writeRowHits")
1082 .desc("Number of row buffer hits during writes");
1085 .name(name() + ".readRowHitRate")
1086 .desc("Row buffer hit rate for reads")
1089 readRowHitRate
= (readRowHits
/ (readReqs
- servicedByWrQ
)) * 100;
1092 .name(name() + ".writeRowHitRate")
1093 .desc("Row buffer hit rate for writes")
1096 writeRowHitRate
= (writeRowHits
/ writeReqs
) * 100;
1099 .init(log2(bytesPerCacheLine
)+3)
1100 .name(name() + ".readPktSize")
1101 .desc("Categorize read packet sizes");
1104 .init(log2(bytesPerCacheLine
)+3)
1105 .name(name() + ".writePktSize")
1106 .desc("categorize write packet sizes");
1109 .init(log2(bytesPerCacheLine
)+3)
1110 .name(name() + ".neitherpktsize")
1111 .desc("categorize neither packet sizes");
1114 .init(readBufferSize
+ 1)
1115 .name(name() + ".rdQLenPdf")
1116 .desc("What read queue length does an incoming req see");
1119 .init(writeBufferSize
+ 1)
1120 .name(name() + ".wrQLenPdf")
1121 .desc("What write queue length does an incoming req see");
1125 .name(name() + ".bytesRead")
1126 .desc("Total number of bytes read from memory");
1129 .name(name() + ".bytesWritten")
1130 .desc("Total number of bytes written to memory");
1133 .name(name() + ".bytesConsumedRd")
1134 .desc("bytesRead derated as per pkt->getSize()");
1137 .name(name() + ".bytesConsumedWr")
1138 .desc("bytesWritten derated as per pkt->getSize()");
1141 .name(name() + ".avgRdBW")
1142 .desc("Average achieved read bandwidth in MB/s")
1145 avgRdBW
= (bytesRead
/ 1000000) / simSeconds
;
1148 .name(name() + ".avgWrBW")
1149 .desc("Average achieved write bandwidth in MB/s")
1152 avgWrBW
= (bytesWritten
/ 1000000) / simSeconds
;
1155 .name(name() + ".avgConsumedRdBW")
1156 .desc("Average consumed read bandwidth in MB/s")
1159 avgConsumedRdBW
= (bytesConsumedRd
/ 1000000) / simSeconds
;
1162 .name(name() + ".avgConsumedWrBW")
1163 .desc("Average consumed write bandwidth in MB/s")
1166 avgConsumedWrBW
= (bytesConsumedWr
/ 1000000) / simSeconds
;
1169 .name(name() + ".peakBW")
1170 .desc("Theoretical peak bandwidth in MB/s")
1173 peakBW
= (SimClock::Frequency
/ tBURST
) * bytesPerCacheLine
/ 1000000;
1176 .name(name() + ".busUtil")
1177 .desc("Data bus utilization in percentage")
1180 busUtil
= (avgRdBW
+ avgWrBW
) / peakBW
* 100;
1183 .name(name() + ".totGap")
1184 .desc("Total gap between requests");
1187 .name(name() + ".avgGap")
1188 .desc("Average gap between requests")
1191 avgGap
= totGap
/ (readReqs
+ writeReqs
);
1195 SimpleDRAM::recvFunctional(PacketPtr pkt
)
1197 // rely on the abstract memory
1198 functionalAccess(pkt
);
1202 SimpleDRAM::getSlavePort(const string
&if_name
, PortID idx
)
1204 if (if_name
!= "port") {
1205 return MemObject::getSlavePort(if_name
, idx
);
1212 SimpleDRAM::drain(DrainManager
*dm
)
1214 unsigned int count
= port
.drain(dm
);
1216 // if there is anything in any of our internal queues, keep track
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());
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
1229 if (dramReadQueue
.empty() && !dramWriteQueue
.empty() &&
1230 !writeEvent
.scheduled())
1235 setDrainState(Drainable::Draining
);
1237 setDrainState(Drainable::Drained
);
1241 SimpleDRAM::MemoryPort::MemoryPort(const std::string
& name
, SimpleDRAM
& _memory
)
1242 : QueuedSlavePort(name
, &_memory
, queue
), queue(_memory
, *this),
1247 SimpleDRAM::MemoryPort::getAddrRanges() const
1249 AddrRangeList ranges
;
1250 ranges
.push_back(memory
.getAddrRange());
1255 SimpleDRAM::MemoryPort::recvFunctional(PacketPtr pkt
)
1257 pkt
->pushLabel(memory
.name());
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
);
1270 SimpleDRAM::MemoryPort::recvAtomic(PacketPtr pkt
)
1272 return memory
.recvAtomic(pkt
);
1276 SimpleDRAM::MemoryPort::recvTimingReq(PacketPtr pkt
)
1278 // pass it to the memory controller
1279 return memory
.recvTimingReq(pkt
);
1283 SimpleDRAMParams::create()
1285 return new SimpleDRAM(this);