2 * Copyright (c) 2013 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
40 #include "DRAMSim2/Callback.h"
41 #include "base/callback.hh"
42 #include "base/trace.hh"
43 #include "debug/DRAMSim2.hh"
44 #include "debug/Drain.hh"
45 #include "mem/dramsim2.hh"
46 #include "sim/system.hh"
48 DRAMSim2::DRAMSim2(const Params
* p
) :
50 port(name() + ".port", *this),
51 wrapper(p
->deviceConfigFile
, p
->systemConfigFile
, p
->filePath
,
52 p
->traceFile
, p
->range
.size() / 1024 / 1024, p
->enableDebug
),
53 retryReq(false), retryResp(false), startTick(0),
54 nbrOutstandingReads(0), nbrOutstandingWrites(0),
56 sendResponseEvent(this), tickEvent(this)
59 "Instantiated DRAMSim2 with clock %d ns and queue size %d\n",
60 wrapper
.clockPeriod(), wrapper
.queueSize());
62 DRAMSim::TransactionCompleteCB
* read_cb
=
63 new DRAMSim::Callback
<DRAMSim2
, void, unsigned, uint64_t, uint64_t>(
64 this, &DRAMSim2::readComplete
);
65 DRAMSim::TransactionCompleteCB
* write_cb
=
66 new DRAMSim::Callback
<DRAMSim2
, void, unsigned, uint64_t, uint64_t>(
67 this, &DRAMSim2::writeComplete
);
68 wrapper
.setCallbacks(read_cb
, write_cb
);
70 // Register a callback to compensate for the destructor not
71 // being called. The callback prints the DRAMSim2 stats.
72 Callback
* cb
= new MakeCallback
<DRAMSim2Wrapper
,
73 &DRAMSim2Wrapper::printStats
>(wrapper
);
74 registerExitCallback(cb
);
80 if (!port
.isConnected()) {
81 fatal("DRAMSim2 %s is unconnected!\n", name());
83 port
.sendRangeChange();
86 if (system()->cacheLineSize() != wrapper
.burstSize())
87 fatal("DRAMSim2 burst size %d does not match cache line size %d\n",
88 wrapper
.burstSize(), system()->cacheLineSize());
94 startTick
= curTick();
96 // kick off the clock ticks
97 schedule(tickEvent
, clockEdge());
101 DRAMSim2::sendResponse()
104 assert(!responseQueue
.empty());
106 DPRINTF(DRAMSim2
, "Attempting to send response\n");
108 bool success
= port
.sendTimingResp(responseQueue
.front());
110 responseQueue
.pop_front();
112 DPRINTF(DRAMSim2
, "Have %d read, %d write, %d responses outstanding\n",
113 nbrOutstandingReads
, nbrOutstandingWrites
,
114 responseQueue
.size());
116 if (!responseQueue
.empty() && !sendResponseEvent
.scheduled())
117 schedule(sendResponseEvent
, curTick());
119 // check if we were asked to drain and if we are now done
120 if (drainManager
&& nbrOutstanding() == 0) {
121 drainManager
->signalDrainDone();
127 DPRINTF(DRAMSim2
, "Waiting for response retry\n");
129 assert(!sendResponseEvent
.scheduled());
134 DRAMSim2::nbrOutstanding() const
136 return nbrOutstandingReads
+ nbrOutstandingWrites
+ responseQueue
.size();
144 // is the connected port waiting for a retry, if so check the
145 // state and send a retry if conditions have changed
146 if (retryReq
&& nbrOutstanding() < wrapper
.queueSize()) {
151 schedule(tickEvent
, curTick() + wrapper
.clockPeriod() * SimClock::Int::ns
);
155 DRAMSim2::recvAtomic(PacketPtr pkt
)
159 // 50 ns is just an arbitrary value at this point
160 return pkt
->memInhibitAsserted() ? 0 : 50000;
164 DRAMSim2::recvFunctional(PacketPtr pkt
)
166 pkt
->pushLabel(name());
168 functionalAccess(pkt
);
170 // potentially update the packets in our response queue as well
171 for (auto i
= responseQueue
.begin(); i
!= responseQueue
.end(); ++i
)
172 pkt
->checkFunctional(*i
);
178 DRAMSim2::recvTimingReq(PacketPtr pkt
)
180 // we should never see a new request while in retry
183 // @todo temporary hack to deal with memory corruption issues until
184 // 4-phase transactions are complete
185 for (int x
= 0; x
< pendingDelete
.size(); x
++)
186 delete pendingDelete
[x
];
187 pendingDelete
.clear();
189 if (pkt
->memInhibitAsserted()) {
190 // snooper will supply based on copy of packet
191 // still target's responsibility to delete packet
192 pendingDelete
.push_back(pkt
);
196 // if we cannot accept we need to send a retry once progress can
198 bool can_accept
= nbrOutstanding() < wrapper
.queueSize();
200 // keep track of the transaction
203 outstandingReads
[pkt
->getAddr()].push(pkt
);
205 // we count a transaction as outstanding until it has left the
206 // queue in the controller, and the response has been sent
207 // back, note that this will differ for reads and writes
208 ++nbrOutstandingReads
;
210 } else if (pkt
->isWrite()) {
212 outstandingWrites
[pkt
->getAddr()].push(pkt
);
214 ++nbrOutstandingWrites
;
216 // perform the access for writes
217 accessAndRespond(pkt
);
220 // keep it simple and just respond if necessary
221 accessAndRespond(pkt
);
226 // we should never have a situation when we think there is space,
228 assert(wrapper
.canAccept());
230 DPRINTF(DRAMSim2
, "Enqueueing address %lld\n", pkt
->getAddr());
232 // @todo what about the granularity here, implicit assumption that
233 // a transaction matches the burst size of the memory (which we
234 // cannot determine without parsing the ini file ourselves)
235 wrapper
.enqueue(pkt
->isWrite(), pkt
->getAddr());
245 DRAMSim2::recvRetry()
247 DPRINTF(DRAMSim2
, "Retrying\n");
255 DRAMSim2::accessAndRespond(PacketPtr pkt
)
257 DPRINTF(DRAMSim2
, "Access for address %lld\n", pkt
->getAddr());
259 bool needsResponse
= pkt
->needsResponse();
261 // do the actual memory access which also turns the packet into a
265 // turn packet around to go back to requester if response expected
267 // access already turned the packet into a response
268 assert(pkt
->isResponse());
270 // @todo someone should pay for this
271 pkt
->firstWordDelay
= pkt
->lastWordDelay
= 0;
273 DPRINTF(DRAMSim2
, "Queuing response for address %lld\n",
276 // queue it to be sent back
277 responseQueue
.push_back(pkt
);
279 // if we are not already waiting for a retry, or are scheduled
280 // to send a response, schedule an event
281 if (!retryResp
&& !sendResponseEvent
.scheduled())
282 schedule(sendResponseEvent
, curTick());
284 // @todo the packet is going to be deleted, and the DRAMPacket
285 // is still having a pointer to it
286 pendingDelete
.push_back(pkt
);
290 void DRAMSim2::readComplete(unsigned id
, uint64_t addr
, uint64_t cycle
)
292 assert(cycle
== divCeil(curTick() - startTick
,
293 wrapper
.clockPeriod() * SimClock::Int::ns
));
295 DPRINTF(DRAMSim2
, "Read to address %lld complete\n", addr
);
297 // get the outstanding reads for the address in question
298 auto p
= outstandingReads
.find(addr
);
299 assert(p
!= outstandingReads
.end());
301 // first in first out, which is not necessarily true, but it is
302 // the best we can do at this point
303 PacketPtr pkt
= p
->second
.front();
306 if (p
->second
.empty())
307 outstandingReads
.erase(p
);
309 // no need to check for drain here as the next call will add a
310 // response to the response queue straight away
311 assert(nbrOutstandingReads
!= 0);
312 --nbrOutstandingReads
;
314 // perform the actual memory access
315 accessAndRespond(pkt
);
318 void DRAMSim2::writeComplete(unsigned id
, uint64_t addr
, uint64_t cycle
)
320 assert(cycle
== divCeil(curTick() - startTick
,
321 wrapper
.clockPeriod() * SimClock::Int::ns
));
323 DPRINTF(DRAMSim2
, "Write to address %lld complete\n", addr
);
325 // get the outstanding reads for the address in question
326 auto p
= outstandingWrites
.find(addr
);
327 assert(p
!= outstandingWrites
.end());
329 // we have already responded, and this is only to keep track of
330 // what is outstanding
332 if (p
->second
.empty())
333 outstandingWrites
.erase(p
);
335 assert(nbrOutstandingWrites
!= 0);
336 --nbrOutstandingWrites
;
338 // check if we were asked to drain and if we are now done
339 if (drainManager
&& nbrOutstanding() == 0) {
340 drainManager
->signalDrainDone();
346 DRAMSim2::getSlavePort(const std::string
&if_name
, PortID idx
)
348 if (if_name
!= "port") {
349 return MemObject::getSlavePort(if_name
, idx
);
356 DRAMSim2::drain(DrainManager
* dm
)
358 // check our outstanding reads and writes and if any they need to
360 if (nbrOutstanding() != 0) {
361 setDrainState(Drainable::Draining
);
365 setDrainState(Drainable::Drained
);
370 DRAMSim2::MemoryPort::MemoryPort(const std::string
& _name
,
372 : SlavePort(_name
, &_memory
), memory(_memory
)
376 DRAMSim2::MemoryPort::getAddrRanges() const
378 AddrRangeList ranges
;
379 ranges
.push_back(memory
.getAddrRange());
384 DRAMSim2::MemoryPort::recvAtomic(PacketPtr pkt
)
386 return memory
.recvAtomic(pkt
);
390 DRAMSim2::MemoryPort::recvFunctional(PacketPtr pkt
)
392 memory
.recvFunctional(pkt
);
396 DRAMSim2::MemoryPort::recvTimingReq(PacketPtr pkt
)
398 // pass it to the memory controller
399 return memory
.recvTimingReq(pkt
);
403 DRAMSim2::MemoryPort::recvRetry()
409 DRAMSim2Params::create()
411 return new DRAMSim2(this);