305a7bcaf9679f25b378645a8bda350fde31b143
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
+ std::max(accessLat
, tCL
);
303 busBusyUntil
= bank
.freeAt
- tCL
;
306 bank
.tRASDoneAt
= bank
.freeAt
+ tRP
;
307 busBusyUntil
= bank
.freeAt
- tCL
- tRCD
;
309 } else if (pageMgmt
== Enums::close
) {
310 bank
.freeAt
= schedTime
+ tBURST
+ accessLat
+ tRP
+ tRP
;
311 busBusyUntil
= bank
.freeAt
- tRP
- tRP
- tCL
- tRCD
;
312 DPRINTF(DRAMWR
, "processWriteEvent::bank.freeAt for "
313 "banks_id %d is %lld\n",
314 dram_pkt
->rank
* banksPerRank
+ dram_pkt
->bank
,
317 panic("Unknown page management policy chosen\n");
319 DPRINTF(DRAMWR
,"Done writing to address %lld\n",dram_pkt
->addr
);
321 DPRINTF(DRAMWR
,"schedtime is %lld, tBURST is %lld, "
322 "busbusyuntil is %lld\n",
323 schedTime
, tBURST
, busBusyUntil
);
325 dramWriteQueue
.pop_front();
331 DPRINTF(DRAMWR
, "Completed %d writes, bus busy for %lld ticks,"\
332 "banks busy for %lld ticks\n", numWritesThisTime
,
333 busBusyUntil
- temp1
, maxBankFreeAt() - temp2
);
336 avgWrQLen
= dramWriteQueue
.size();
338 // turn the bus back around for reads again
339 busBusyUntil
+= tWTR
;
347 // if there is nothing left in any queue, signal a drain
348 if (dramWriteQueue
.empty() && dramReadQueue
.empty() &&
349 dramRespQueue
.empty () && drainManager
) {
350 drainManager
->signalDrainDone();
354 // Once you're done emptying the write queue, check if there's
355 // anything in the read queue, and call schedule if required
356 schedule(&nextReqEvent
, busBusyUntil
);
360 SimpleDRAM::triggerWrites()
362 DPRINTF(DRAM
, "Writes triggered at %lld\n", curTick());
363 // Flag variable to stop any more read scheduling
366 writeStartTime
= std::max(busBusyUntil
, curTick()) + tWTR
;
368 DPRINTF(DRAM
, "Writes scheduled at %lld\n", writeStartTime
);
370 assert(writeStartTime
>= curTick());
371 assert(!writeEvent
.scheduled());
372 schedule(&writeEvent
, writeStartTime
);
376 SimpleDRAM::addToWriteQueue(PacketPtr pkt
)
378 // only add to the write queue here. whenever the request is
379 // eventually done, set the readyTime, and call schedule()
380 assert(pkt
->isWrite());
382 DRAMPacket
* dram_pkt
= decodeAddr(pkt
);
384 assert(dramWriteQueue
.size() < writeBufferSize
);
385 wrQLenPdf
[dramWriteQueue
.size()]++;
387 DPRINTF(DRAM
, "Adding to write queue\n");
389 dramWriteQueue
.push_back(dram_pkt
);
392 uint32_t bank_id
= banksPerRank
* dram_pkt
->rank
+ dram_pkt
->bank
;
393 assert(bank_id
< ranksPerChannel
* banksPerRank
);
394 perBankWrReqs
[bank_id
]++;
396 avgWrQLen
= dramWriteQueue
.size();
398 // we do not wait for the writes to be send to the actual memory,
399 // but instead take responsibility for the consistency here and
400 // snoop the write queue for any upcoming reads
402 bytesConsumedWr
+= pkt
->getSize();
403 bytesWritten
+= bytesPerCacheLine
;
404 accessAndRespond(pkt
);
406 // If your write buffer is starting to fill up, drain it!
407 if (dramWriteQueue
.size() > writeThreshold
&& !stopReads
){
413 SimpleDRAM::printParams() const
415 // Sanity check print of important parameters
417 "Memory controller %s physical organization\n" \
418 "Bytes per cacheline %d\n" \
419 "Lines per row buffer %d\n" \
420 "Rows per bank %d\n" \
421 "Banks per rank %d\n" \
422 "Ranks per channel %d\n" \
423 "Total mem capacity %u\n",
424 name(), bytesPerCacheLine
,linesPerRowBuffer
, rowsPerBank
,
425 banksPerRank
, ranksPerChannel
, bytesPerCacheLine
*
426 linesPerRowBuffer
* rowsPerBank
* banksPerRank
* ranksPerChannel
);
428 string scheduler
= memSchedPolicy
== Enums::fcfs
? "FCFS" : "FR-FCFS";
429 string address_mapping
= addrMapping
== Enums::openmap
? "OPENMAP" :
431 string page_policy
= pageMgmt
== Enums::open
? "OPEN" : "CLOSE";
434 "Memory controller %s characteristics\n" \
435 "Read buffer size %d\n" \
436 "Write buffer size %d\n" \
437 "Write buffer thresh %d\n" \
439 "Address mapping %s\n" \
441 name(), readBufferSize
, writeBufferSize
, writeThreshold
,
442 scheduler
, address_mapping
, page_policy
);
444 DPRINTF(DRAM
, "Memory controller %s timing specs\n" \
448 "tBURST %d ticks\n" \
452 name(), tRCD
, tCL
, tRP
, tBURST
, tRFC
, tREFI
, tWTR
);
456 SimpleDRAM::printQs() const {
458 list
<DRAMPacket
*>::const_iterator i
;
460 DPRINTF(DRAM
, "===READ QUEUE===\n\n");
461 for (i
= dramReadQueue
.begin() ; i
!= dramReadQueue
.end() ; ++i
) {
462 DPRINTF(DRAM
, "Read %lu\n", (*i
)->addr
);
464 DPRINTF(DRAM
, "\n===RESP QUEUE===\n\n");
465 for (i
= dramRespQueue
.begin() ; i
!= dramRespQueue
.end() ; ++i
) {
466 DPRINTF(DRAM
, "Response %lu\n", (*i
)->addr
);
468 DPRINTF(DRAM
, "\n===WRITE QUEUE===\n\n");
469 for (i
= dramWriteQueue
.begin() ; i
!= dramWriteQueue
.end() ; ++i
) {
470 DPRINTF(DRAM
, "Write %lu\n", (*i
)->addr
);
475 SimpleDRAM::recvTimingReq(PacketPtr pkt
)
477 /// @todo temporary hack to deal with memory corruption issues until
478 /// 4-phase transactions are complete
479 for (int x
= 0; x
< pendingDelete
.size(); x
++)
480 delete pendingDelete
[x
];
481 pendingDelete
.clear();
484 // This is where we enter from the outside world
485 DPRINTF(DRAM
, "Inside recvTimingReq: request %s addr %lld size %d\n",
486 pkt
->cmdString(),pkt
->getAddr(), pkt
->getSize());
490 if (pkt
->getSize() == bytesPerCacheLine
)
493 if (numReqs
% 1000000 == 0)
496 // Calc avg gap between requests
497 if (prevArrival
!= 0) {
498 totGap
+= curTick() - prevArrival
;
500 prevArrival
= curTick();
502 // simply drop inhibited packets for now
503 if (pkt
->memInhibitAsserted()) {
504 DPRINTF(DRAM
,"Inhibited packet -- Dropping it now\n");
505 pendingDelete
.push_back(pkt
);
509 unsigned size
= pkt
->getSize();
510 if (size
> bytesPerCacheLine
)
511 panic("Request size %d is greater than cache line size %d",
512 size
, bytesPerCacheLine
);
515 index
= log2(bytesPerCacheLine
) + 1;
519 if (size
!= 0 && (1 << index
) != size
)
520 index
= log2(bytesPerCacheLine
) + 2;
522 // @todo: Do we really want to do all this before the packet is
523 // actually accepted?
525 /* Index 0 - Size 1 byte
526 Index 1 - Size 2 bytes
527 Index 2 - Size 4 bytes
530 Index 6 - Size 64 bytes
531 Index 7 - Size 0 bytes
532 Index 8 - Non-power-of-2 size */
535 readPktSize
[index
]++;
536 else if (pkt
->isWrite())
537 writePktSize
[index
]++;
539 neitherPktSize
[index
]++;
541 // check local buffers and do not accept if full
543 if (readQueueFull()) {
544 DPRINTF(DRAM
,"Read queue full, not accepting\n");
545 // remember that we have to retry this port
554 } else if (pkt
->isWrite()) {
555 if (writeQueueFull()) {
556 DPRINTF(DRAM
,"Write queue full, not accepting\n");
557 // remember that we have to retry this port
562 addToWriteQueue(pkt
);
567 DPRINTF(DRAM
,"Neither read nor write, ignore timing\n");
568 neitherReadNorWrite
++;
569 accessAndRespond(pkt
);
579 SimpleDRAM::processRespondEvent()
582 "processRespondEvent(): Some req has reached its readyTime\n");
584 PacketPtr pkt
= dramRespQueue
.front()->pkt
;
586 // Actually responds to the requestor
587 bytesConsumedRd
+= pkt
->getSize();
588 bytesRead
+= bytesPerCacheLine
;
589 accessAndRespond(pkt
);
591 DRAMPacket
* dram_pkt
= dramRespQueue
.front();
592 dramRespQueue
.pop_front();
596 avgRdQLen
= dramReadQueue
.size() + dramRespQueue
.size();
598 if (!dramRespQueue
.empty()){
599 assert(dramRespQueue
.front()->readyTime
>= curTick());
600 assert(!respondEvent
.scheduled());
601 schedule(&respondEvent
, dramRespQueue
.front()->readyTime
);
603 // if there is nothing left in any queue, signal a drain
604 if (dramWriteQueue
.empty() && dramReadQueue
.empty() &&
606 drainManager
->signalDrainDone();
613 SimpleDRAM::chooseNextWrite()
615 // This method does the arbitration between requests. The chosen
616 // packet is simply moved to the head of the queue. The other
617 // methods know that this is the place to look. For example, with
618 // FCFS, this method does nothing
619 assert(!dramWriteQueue
.empty());
621 if (dramWriteQueue
.size() == 1) {
622 DPRINTF(DRAMWR
, "chooseNextWrite(): Single element, nothing to do\n");
626 if (memSchedPolicy
== Enums::fcfs
) {
628 // Do nothing, since the correct request is already head
630 } else if (memSchedPolicy
== Enums::frfcfs
) {
632 list
<DRAMPacket
*>::iterator i
= dramWriteQueue
.begin();
633 bool foundRowHit
= false;
634 while (!foundRowHit
&& i
!= dramWriteQueue
.end()) {
635 DRAMPacket
* dram_pkt
= *i
;
636 const Bank
& bank
= dram_pkt
->bank_ref
;
637 if (bank
.openRow
== dram_pkt
->row
) { //FR part
638 DPRINTF(DRAMWR
,"Row buffer hit\n");
639 dramWriteQueue
.erase(i
);
640 dramWriteQueue
.push_front(dram_pkt
);
649 panic("No scheduling policy chosen\n");
651 DPRINTF(DRAMWR
, "chooseNextWrite(): Something chosen\n");
655 SimpleDRAM::chooseNextReq()
657 // This method does the arbitration between requests.
658 // The chosen packet is simply moved to the head of the
659 // queue. The other methods know that this is the place
660 // to look. For example, with FCFS, this method does nothing
661 list
<DRAMPacket
*>::iterator i
;
662 DRAMPacket
* dram_pkt
;
664 if (dramReadQueue
.empty()){
665 DPRINTF(DRAM
, "chooseNextReq(): Returning False\n");
669 if (dramReadQueue
.size() == 1)
672 if (memSchedPolicy
== Enums::fcfs
) {
674 // Do nothing, since the correct request is already head
676 } else if (memSchedPolicy
== Enums::frfcfs
) {
678 for (i
= dramReadQueue
.begin() ; i
!= dramReadQueue
.end() ; ++i
) {
680 const Bank
& bank
= dram_pkt
->bank_ref
;
681 if (bank
.openRow
== dram_pkt
->row
) { //FR part
682 DPRINTF(DRAM
, "Row buffer hit\n");
683 dramReadQueue
.erase(i
);
684 dramReadQueue
.push_front(dram_pkt
);
693 panic("No scheduling policy chosen!\n");
696 DPRINTF(DRAM
,"chooseNextReq(): Chosen something, returning True\n");
701 SimpleDRAM::accessAndRespond(PacketPtr pkt
)
703 DPRINTF(DRAM
, "Responding to Address %lld.. ",pkt
->getAddr());
705 bool needsResponse
= pkt
->needsResponse();
706 // do the actual memory access which also turns the packet into a
710 // turn packet around to go back to requester if response expected
712 // access already turned the packet into a response
713 assert(pkt
->isResponse());
715 // queue the packet in the response queue to be sent out the
717 port
.schedTimingResp(pkt
, curTick() + 1);
721 DPRINTF(DRAM
, "Done\n");
727 SimpleDRAM::estimateLatency(DRAMPacket
* dram_pkt
, Tick inTime
)
729 // If a request reaches a bank at tick 'inTime', how much time
730 // *after* that does it take to finish the request, depending
731 // on bank status and page open policy. Note that this method
732 // considers only the time taken for the actual read or write
733 // to complete, NOT any additional time thereafter for tRAS or
739 const Bank
& bank
= dram_pkt
->bank_ref
;
740 if (pageMgmt
== Enums::open
) { // open-page policy
741 if (bank
.openRow
== dram_pkt
->row
) {
742 // When we have a row-buffer hit,
743 // we don't care about tRAS having expired or not,
744 // but do care about bank being free for access
747 if (bank
.freeAt
< inTime
) {
757 // Row-buffer miss, need to close existing row
758 // once tRAS has expired, then open the new one,
759 // then add cas latency.
760 Tick freeTime
= std::max(bank
.tRASDoneAt
, bank
.freeAt
);
762 if (freeTime
> inTime
)
763 accLat
+= freeTime
- inTime
;
765 accLat
+= tRP
+ tRCD
+ tCL
;
766 bankLat
+= tRP
+ tRCD
+ tCL
;
768 } else if (pageMgmt
== Enums::close
) {
770 // With a close page policy, no notion of
772 if (bank
.freeAt
> inTime
)
773 accLat
+= bank
.freeAt
- inTime
;
775 // page already closed, simply open the row, and
777 accLat
+= tRCD
+ tCL
;
778 bankLat
+= tRCD
+ tCL
;
780 panic("No page management policy chosen\n");
782 DPRINTF(DRAM
, "Returning < %lld, %lld > from estimateLatency()\n",
785 return make_pair(bankLat
, accLat
);
789 SimpleDRAM::processNextReqEvent()
795 SimpleDRAM::doDRAMAccess(DRAMPacket
* dram_pkt
)
798 DPRINTF(DRAM
, "Timing access to addr %lld, rank/bank/row %d %d %d\n",
799 dram_pkt
->addr
, dram_pkt
->rank
, dram_pkt
->bank
, dram_pkt
->row
);
801 assert(curTick() >= prevdramaccess
);
802 prevdramaccess
= curTick();
804 // estimate the bank and access latency
805 pair
<Tick
, Tick
> lat
= estimateLatency(dram_pkt
, curTick());
806 Tick bankLat
= lat
.first
;
807 Tick accessLat
= lat
.second
;
809 // This request was woken up at this time based on a prior call
810 // to estimateLatency(). However, between then and now, both the
811 // accessLatency and/or busBusyUntil may have changed. We need
812 // to correct for that.
814 Tick addDelay
= (curTick() + accessLat
< busBusyUntil
) ?
815 busBusyUntil
- (curTick() + accessLat
) : 0;
817 Bank
& bank
= dram_pkt
->bank_ref
;
820 if (pageMgmt
== Enums::open
) {
821 bank
.openRow
= dram_pkt
->row
;
822 bank
.freeAt
= curTick() + addDelay
+ accessLat
;
823 // If you activated a new row do to this access, the next access
824 // will have to respect tRAS for this bank. Assume tRAS ~= 3 * tRP
826 bank
.tRASDoneAt
= bank
.freeAt
+ tRP
;
828 } else if (pageMgmt
== Enums::close
) { // accounting for tRAS also
829 // assuming that tRAS ~= 3 * tRP, and tRAS ~= 4 * tRP, as is common
830 // (refer Jacob/Ng/Wang and Micron datasheets)
831 bank
.freeAt
= curTick() + addDelay
+ accessLat
+ tRP
+ tRP
;
832 DPRINTF(DRAM
,"doDRAMAccess::bank.freeAt is %lld\n",bank
.freeAt
);
834 panic("No page management policy chosen\n");
836 // Update request parameters
837 dram_pkt
->readyTime
= curTick() + addDelay
+ accessLat
+ tBURST
;
840 DPRINTF(DRAM
, "Req %lld: curtick is %lld accessLat is %d " \
841 "readytime is %lld busbusyuntil is %lld. " \
842 "Scheduling at readyTime\n", dram_pkt
->addr
,
843 curTick(), accessLat
, dram_pkt
->readyTime
, busBusyUntil
);
845 // Make sure requests are not overlapping on the databus
846 assert (dram_pkt
->readyTime
- busBusyUntil
>= tBURST
);
849 busBusyUntil
= dram_pkt
->readyTime
;
851 DPRINTF(DRAM
,"Access time is %lld\n",
852 dram_pkt
->readyTime
- dram_pkt
->entryTime
);
855 totMemAccLat
+= dram_pkt
->readyTime
- dram_pkt
->entryTime
;
856 totBankLat
+= bankLat
;
858 totQLat
+= dram_pkt
->readyTime
- dram_pkt
->entryTime
- bankLat
- tBURST
;
863 // At this point we're done dealing with the request
864 // It will be moved to a separate response queue with a
865 // correct readyTime, and eventually be sent back at that
869 // The absolute soonest you have to start thinking about the
870 // next request is the longest access time that can occur before
871 // busBusyUntil. Assuming you need to meet tRAS, then precharge,
872 // open a new row, and access, it is ~4*tRCD.
875 Tick newTime
= (busBusyUntil
> 4 * tRCD
) ?
876 std::max(busBusyUntil
- 4 * tRCD
, curTick()) :
879 if (!nextReqEvent
.scheduled() && !stopReads
){
880 schedule(&nextReqEvent
, newTime
);
882 if (newTime
< nextReqEvent
.when())
883 reschedule(&nextReqEvent
, newTime
);
890 SimpleDRAM::moveToRespQ()
892 // Remove from read queue
893 DRAMPacket
* dram_pkt
= dramReadQueue
.front();
894 dramReadQueue
.pop_front();
896 // Insert into response queue sorted by readyTime
897 // It will be sent back to the requestor at its
899 if (dramRespQueue
.empty()) {
900 dramRespQueue
.push_front(dram_pkt
);
901 assert(!respondEvent
.scheduled());
902 assert(dram_pkt
->readyTime
>= curTick());
903 schedule(&respondEvent
, dram_pkt
->readyTime
);
906 std::list
<DRAMPacket
*>::iterator i
= dramRespQueue
.begin();
907 while (!done
&& i
!= dramRespQueue
.end()) {
908 if ((*i
)->readyTime
> dram_pkt
->readyTime
) {
909 dramRespQueue
.insert(i
, dram_pkt
);
916 dramRespQueue
.push_back(dram_pkt
);
918 assert(respondEvent
.scheduled());
920 if (dramRespQueue
.front()->readyTime
< respondEvent
.when()) {
921 assert(dramRespQueue
.front()->readyTime
>= curTick());
922 reschedule(&respondEvent
, dramRespQueue
.front()->readyTime
);
933 SimpleDRAM::scheduleNextReq()
935 DPRINTF(DRAM
, "Reached scheduleNextReq()\n");
937 // Figure out which request goes next, and move it to front()
938 if (!chooseNextReq()) {
939 // In the case there is no read request to go next, see if we
940 // are asked to drain, and if so trigger writes, this also
941 // ensures that if we hit the write limit we will do this
942 // multiple times until we are completely drained
943 if (drainManager
&& !dramWriteQueue
.empty() && !writeEvent
.scheduled())
946 doDRAMAccess(dramReadQueue
.front());
951 SimpleDRAM::maxBankFreeAt() const
955 for(int i
= 0; i
< ranksPerChannel
; i
++)
956 for(int j
= 0; j
< banksPerRank
; j
++)
957 banksFree
= std::max(banks
[i
][j
].freeAt
, banksFree
);
963 SimpleDRAM::processRefreshEvent()
965 DPRINTF(DRAM
, "Refreshing at tick %ld\n", curTick());
967 Tick banksFree
= std::max(curTick(), maxBankFreeAt()) + tRFC
;
969 for(int i
= 0; i
< ranksPerChannel
; i
++)
970 for(int j
= 0; j
< banksPerRank
; j
++)
971 banks
[i
][j
].freeAt
= banksFree
;
973 schedule(&refreshEvent
, curTick() + tREFI
);
977 SimpleDRAM::regStats()
979 using namespace Stats
;
981 AbstractMemory::regStats();
984 .name(name() + ".readReqs")
985 .desc("Total number of read requests seen");
988 .name(name() + ".writeReqs")
989 .desc("Total number of write requests seen");
992 .name(name() + ".servicedByWrQ")
993 .desc("Number of read reqs serviced by write Q");
996 .name(name() + ".cpureqs")
997 .desc("Reqs generatd by CPU via cache - shady");
1000 .name(name() + ".neitherReadNorWrite")
1001 .desc("Reqs where no action is needed");
1004 .init(banksPerRank
* ranksPerChannel
)
1005 .name(name() + ".perBankRdReqs")
1006 .desc("Track reads on a per bank basis");
1009 .init(banksPerRank
* ranksPerChannel
)
1010 .name(name() + ".perBankWrReqs")
1011 .desc("Track writes on a per bank basis");
1014 .name(name() + ".avgRdQLen")
1015 .desc("Average read queue length over time")
1019 .name(name() + ".avgWrQLen")
1020 .desc("Average write queue length over time")
1024 .name(name() + ".totQLat")
1025 .desc("Total cycles spent in queuing delays");
1028 .name(name() + ".totBankLat")
1029 .desc("Total cycles spent in bank access");
1032 .name(name() + ".totBusLat")
1033 .desc("Total cycles spent in databus access");
1036 .name(name() + ".totMemAccLat")
1037 .desc("Sum of mem lat for all requests");
1040 .name(name() + ".avgQLat")
1041 .desc("Average queueing delay per request")
1044 avgQLat
= totQLat
/ (readReqs
- servicedByWrQ
);
1047 .name(name() + ".avgBankLat")
1048 .desc("Average bank access latency per request")
1051 avgBankLat
= totBankLat
/ (readReqs
- servicedByWrQ
);
1054 .name(name() + ".avgBusLat")
1055 .desc("Average bus latency per request")
1058 avgBusLat
= totBusLat
/ (readReqs
- servicedByWrQ
);
1061 .name(name() + ".avgMemAccLat")
1062 .desc("Average memory access latency")
1065 avgMemAccLat
= totMemAccLat
/ (readReqs
- servicedByWrQ
);
1068 .name(name() + ".numRdRetry")
1069 .desc("Number of times rd buffer was full causing retry");
1072 .name(name() + ".numWrRetry")
1073 .desc("Number of times wr buffer was full causing retry");
1076 .name(name() + ".readRowHits")
1077 .desc("Number of row buffer hits during reads");
1080 .name(name() + ".writeRowHits")
1081 .desc("Number of row buffer hits during writes");
1084 .name(name() + ".readRowHitRate")
1085 .desc("Row buffer hit rate for reads")
1088 readRowHitRate
= (readRowHits
/ (readReqs
- servicedByWrQ
)) * 100;
1091 .name(name() + ".writeRowHitRate")
1092 .desc("Row buffer hit rate for writes")
1095 writeRowHitRate
= (writeRowHits
/ writeReqs
) * 100;
1098 .init(log2(bytesPerCacheLine
)+3)
1099 .name(name() + ".readPktSize")
1100 .desc("Categorize read packet sizes");
1103 .init(log2(bytesPerCacheLine
)+3)
1104 .name(name() + ".writePktSize")
1105 .desc("categorize write packet sizes");
1108 .init(log2(bytesPerCacheLine
)+3)
1109 .name(name() + ".neitherpktsize")
1110 .desc("categorize neither packet sizes");
1113 .init(readBufferSize
+ 1)
1114 .name(name() + ".rdQLenPdf")
1115 .desc("What read queue length does an incoming req see");
1118 .init(writeBufferSize
+ 1)
1119 .name(name() + ".wrQLenPdf")
1120 .desc("What write queue length does an incoming req see");
1124 .name(name() + ".bytesRead")
1125 .desc("Total number of bytes read from memory");
1128 .name(name() + ".bytesWritten")
1129 .desc("Total number of bytes written to memory");
1132 .name(name() + ".bytesConsumedRd")
1133 .desc("bytesRead derated as per pkt->getSize()");
1136 .name(name() + ".bytesConsumedWr")
1137 .desc("bytesWritten derated as per pkt->getSize()");
1140 .name(name() + ".avgRdBW")
1141 .desc("Average achieved read bandwidth in MB/s")
1144 avgRdBW
= (bytesRead
/ 1000000) / simSeconds
;
1147 .name(name() + ".avgWrBW")
1148 .desc("Average achieved write bandwidth in MB/s")
1151 avgWrBW
= (bytesWritten
/ 1000000) / simSeconds
;
1154 .name(name() + ".avgConsumedRdBW")
1155 .desc("Average consumed read bandwidth in MB/s")
1158 avgConsumedRdBW
= (bytesConsumedRd
/ 1000000) / simSeconds
;
1161 .name(name() + ".avgConsumedWrBW")
1162 .desc("Average consumed write bandwidth in MB/s")
1165 avgConsumedWrBW
= (bytesConsumedWr
/ 1000000) / simSeconds
;
1168 .name(name() + ".peakBW")
1169 .desc("Theoretical peak bandwidth in MB/s")
1172 peakBW
= (SimClock::Frequency
/ tBURST
) * bytesPerCacheLine
/ 1000000;
1175 .name(name() + ".busUtil")
1176 .desc("Data bus utilization in percentage")
1179 busUtil
= (avgRdBW
+ avgWrBW
) / peakBW
* 100;
1182 .name(name() + ".totGap")
1183 .desc("Total gap between requests");
1186 .name(name() + ".avgGap")
1187 .desc("Average gap between requests")
1190 avgGap
= totGap
/ (readReqs
+ writeReqs
);
1194 SimpleDRAM::recvFunctional(PacketPtr pkt
)
1196 // rely on the abstract memory
1197 functionalAccess(pkt
);
1201 SimpleDRAM::getSlavePort(const string
&if_name
, PortID idx
)
1203 if (if_name
!= "port") {
1204 return MemObject::getSlavePort(if_name
, idx
);
1211 SimpleDRAM::drain(DrainManager
*dm
)
1213 unsigned int count
= port
.drain(dm
);
1215 // if there is anything in any of our internal queues, keep track
1217 if (!(dramWriteQueue
.empty() && dramReadQueue
.empty() &&
1218 dramRespQueue
.empty())) {
1219 DPRINTF(Drain
, "DRAM controller not drained, write: %d, read: %d,"
1220 " resp: %d\n", dramWriteQueue
.size(), dramReadQueue
.size(),
1221 dramRespQueue
.size());
1224 // the only part that is not drained automatically over time
1225 // is the write queue, thus trigger writes if there are any
1226 // waiting and no reads waiting, otherwise wait until the
1228 if (dramReadQueue
.empty() && !dramWriteQueue
.empty() &&
1229 !writeEvent
.scheduled())
1234 setDrainState(Drainable::Draining
);
1236 setDrainState(Drainable::Drained
);
1240 SimpleDRAM::MemoryPort::MemoryPort(const std::string
& name
, SimpleDRAM
& _memory
)
1241 : QueuedSlavePort(name
, &_memory
, queue
), queue(_memory
, *this),
1246 SimpleDRAM::MemoryPort::getAddrRanges() const
1248 AddrRangeList ranges
;
1249 ranges
.push_back(memory
.getAddrRange());
1254 SimpleDRAM::MemoryPort::recvFunctional(PacketPtr pkt
)
1256 pkt
->pushLabel(memory
.name());
1258 if (!queue
.checkFunctional(pkt
)) {
1259 // Default implementation of SimpleTimingPort::recvFunctional()
1260 // calls recvAtomic() and throws away the latency; we can save a
1261 // little here by just not calculating the latency.
1262 memory
.recvFunctional(pkt
);
1269 SimpleDRAM::MemoryPort::recvAtomic(PacketPtr pkt
)
1271 return memory
.recvAtomic(pkt
);
1275 SimpleDRAM::MemoryPort::recvTimingReq(PacketPtr pkt
)
1277 // pass it to the memory controller
1278 return memory
.recvTimingReq(pkt
);
1282 SimpleDRAMParams::create()
1284 return new SimpleDRAM(this);