dramsim2.cc (11284:b3926db25371) dramsim2.cc (11793:ef606668d247)
1/*
2 * Copyright (c) 2013 ARM Limited
3 * All rights reserved
4 *
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.
13 *
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.
24 *
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.
36 *
37 * Authors: Andreas Hansson
38 */
39
1/*
2 * Copyright (c) 2013 ARM Limited
3 * All rights reserved
4 *
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.
13 *
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.
24 *
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.
36 *
37 * Authors: Andreas Hansson
38 */
39
40#include "mem/dramsim2.hh"
41
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"
42#include "DRAMSim2/Callback.h"
43#include "base/callback.hh"
44#include "base/trace.hh"
45#include "debug/DRAMSim2.hh"
46#include "debug/Drain.hh"
45#include "mem/dramsim2.hh"
46#include "sim/system.hh"
47
48DRAMSim2::DRAMSim2(const Params* p) :
49 AbstractMemory(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),
55 sendResponseEvent(this), tickEvent(this)
56{
57 DPRINTF(DRAMSim2,
58 "Instantiated DRAMSim2 with clock %d ns and queue size %d\n",
59 wrapper.clockPeriod(), wrapper.queueSize());
60
61 DRAMSim::TransactionCompleteCB* read_cb =
62 new DRAMSim::Callback<DRAMSim2, void, unsigned, uint64_t, uint64_t>(
63 this, &DRAMSim2::readComplete);
64 DRAMSim::TransactionCompleteCB* write_cb =
65 new DRAMSim::Callback<DRAMSim2, void, unsigned, uint64_t, uint64_t>(
66 this, &DRAMSim2::writeComplete);
67 wrapper.setCallbacks(read_cb, write_cb);
68
69 // Register a callback to compensate for the destructor not
70 // being called. The callback prints the DRAMSim2 stats.
71 Callback* cb = new MakeCallback<DRAMSim2Wrapper,
72 &DRAMSim2Wrapper::printStats>(wrapper);
73 registerExitCallback(cb);
74}
75
76void
77DRAMSim2::init()
78{
79 AbstractMemory::init();
80
81 if (!port.isConnected()) {
82 fatal("DRAMSim2 %s is unconnected!\n", name());
83 } else {
84 port.sendRangeChange();
85 }
86
87 if (system()->cacheLineSize() != wrapper.burstSize())
88 fatal("DRAMSim2 burst size %d does not match cache line size %d\n",
89 wrapper.burstSize(), system()->cacheLineSize());
90}
91
92void
93DRAMSim2::startup()
94{
95 startTick = curTick();
96
97 // kick off the clock ticks
98 schedule(tickEvent, clockEdge());
99}
100
101void
102DRAMSim2::sendResponse()
103{
104 assert(!retryResp);
105 assert(!responseQueue.empty());
106
107 DPRINTF(DRAMSim2, "Attempting to send response\n");
108
109 bool success = port.sendTimingResp(responseQueue.front());
110 if (success) {
111 responseQueue.pop_front();
112
113 DPRINTF(DRAMSim2, "Have %d read, %d write, %d responses outstanding\n",
114 nbrOutstandingReads, nbrOutstandingWrites,
115 responseQueue.size());
116
117 if (!responseQueue.empty() && !sendResponseEvent.scheduled())
118 schedule(sendResponseEvent, curTick());
119
120 if (nbrOutstanding() == 0)
121 signalDrainDone();
122 } else {
123 retryResp = true;
124
125 DPRINTF(DRAMSim2, "Waiting for response retry\n");
126
127 assert(!sendResponseEvent.scheduled());
128 }
129}
130
131unsigned int
132DRAMSim2::nbrOutstanding() const
133{
134 return nbrOutstandingReads + nbrOutstandingWrites + responseQueue.size();
135}
136
137void
138DRAMSim2::tick()
139{
140 wrapper.tick();
141
142 // is the connected port waiting for a retry, if so check the
143 // state and send a retry if conditions have changed
144 if (retryReq && nbrOutstanding() < wrapper.queueSize()) {
145 retryReq = false;
146 port.sendRetryReq();
147 }
148
149 schedule(tickEvent, curTick() + wrapper.clockPeriod() * SimClock::Int::ns);
150}
151
152Tick
153DRAMSim2::recvAtomic(PacketPtr pkt)
154{
155 access(pkt);
156
157 // 50 ns is just an arbitrary value at this point
158 return pkt->cacheResponding() ? 0 : 50000;
159}
160
161void
162DRAMSim2::recvFunctional(PacketPtr pkt)
163{
164 pkt->pushLabel(name());
165
166 functionalAccess(pkt);
167
168 // potentially update the packets in our response queue as well
169 for (auto i = responseQueue.begin(); i != responseQueue.end(); ++i)
170 pkt->checkFunctional(*i);
171
172 pkt->popLabel();
173}
174
175bool
176DRAMSim2::recvTimingReq(PacketPtr pkt)
177{
178 // if a cache is responding, sink the packet without further action
179 if (pkt->cacheResponding()) {
180 pendingDelete.reset(pkt);
181 return true;
182 }
183
184 // we should not get a new request after committing to retry the
185 // current one, but unfortunately the CPU violates this rule, so
186 // simply ignore it for now
187 if (retryReq)
188 return false;
189
190 // if we cannot accept we need to send a retry once progress can
191 // be made
192 bool can_accept = nbrOutstanding() < wrapper.queueSize();
193
194 // keep track of the transaction
195 if (pkt->isRead()) {
196 if (can_accept) {
197 outstandingReads[pkt->getAddr()].push(pkt);
198
199 // we count a transaction as outstanding until it has left the
200 // queue in the controller, and the response has been sent
201 // back, note that this will differ for reads and writes
202 ++nbrOutstandingReads;
203 }
204 } else if (pkt->isWrite()) {
205 if (can_accept) {
206 outstandingWrites[pkt->getAddr()].push(pkt);
207
208 ++nbrOutstandingWrites;
209
210 // perform the access for writes
211 accessAndRespond(pkt);
212 }
213 } else {
214 // keep it simple and just respond if necessary
215 accessAndRespond(pkt);
216 return true;
217 }
218
219 if (can_accept) {
220 // we should never have a situation when we think there is space,
221 // and there isn't
222 assert(wrapper.canAccept());
223
224 DPRINTF(DRAMSim2, "Enqueueing address %lld\n", pkt->getAddr());
225
226 // @todo what about the granularity here, implicit assumption that
227 // a transaction matches the burst size of the memory (which we
228 // cannot determine without parsing the ini file ourselves)
229 wrapper.enqueue(pkt->isWrite(), pkt->getAddr());
230
231 return true;
232 } else {
233 retryReq = true;
234 return false;
235 }
236}
237
238void
239DRAMSim2::recvRespRetry()
240{
241 DPRINTF(DRAMSim2, "Retrying\n");
242
243 assert(retryResp);
244 retryResp = false;
245 sendResponse();
246}
247
248void
249DRAMSim2::accessAndRespond(PacketPtr pkt)
250{
251 DPRINTF(DRAMSim2, "Access for address %lld\n", pkt->getAddr());
252
253 bool needsResponse = pkt->needsResponse();
254
255 // do the actual memory access which also turns the packet into a
256 // response
257 access(pkt);
258
259 // turn packet around to go back to requester if response expected
260 if (needsResponse) {
261 // access already turned the packet into a response
262 assert(pkt->isResponse());
263 // Here we pay for xbar additional delay and to process the payload
264 // of the packet.
265 Tick time = curTick() + pkt->headerDelay + pkt->payloadDelay;
266 // Reset the timings of the packet
267 pkt->headerDelay = pkt->payloadDelay = 0;
268
269 DPRINTF(DRAMSim2, "Queuing response for address %lld\n",
270 pkt->getAddr());
271
272 // queue it to be sent back
273 responseQueue.push_back(pkt);
274
275 // if we are not already waiting for a retry, or are scheduled
276 // to send a response, schedule an event
277 if (!retryResp && !sendResponseEvent.scheduled())
278 schedule(sendResponseEvent, time);
279 } else {
280 // queue the packet for deletion
281 pendingDelete.reset(pkt);
282 }
283}
284
285void DRAMSim2::readComplete(unsigned id, uint64_t addr, uint64_t cycle)
286{
287 assert(cycle == divCeil(curTick() - startTick,
288 wrapper.clockPeriod() * SimClock::Int::ns));
289
290 DPRINTF(DRAMSim2, "Read to address %lld complete\n", addr);
291
292 // get the outstanding reads for the address in question
293 auto p = outstandingReads.find(addr);
294 assert(p != outstandingReads.end());
295
296 // first in first out, which is not necessarily true, but it is
297 // the best we can do at this point
298 PacketPtr pkt = p->second.front();
299 p->second.pop();
300
301 if (p->second.empty())
302 outstandingReads.erase(p);
303
304 // no need to check for drain here as the next call will add a
305 // response to the response queue straight away
306 assert(nbrOutstandingReads != 0);
307 --nbrOutstandingReads;
308
309 // perform the actual memory access
310 accessAndRespond(pkt);
311}
312
313void DRAMSim2::writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
314{
315 assert(cycle == divCeil(curTick() - startTick,
316 wrapper.clockPeriod() * SimClock::Int::ns));
317
318 DPRINTF(DRAMSim2, "Write to address %lld complete\n", addr);
319
320 // get the outstanding reads for the address in question
321 auto p = outstandingWrites.find(addr);
322 assert(p != outstandingWrites.end());
323
324 // we have already responded, and this is only to keep track of
325 // what is outstanding
326 p->second.pop();
327 if (p->second.empty())
328 outstandingWrites.erase(p);
329
330 assert(nbrOutstandingWrites != 0);
331 --nbrOutstandingWrites;
332
333 if (nbrOutstanding() == 0)
334 signalDrainDone();
335}
336
337BaseSlavePort&
338DRAMSim2::getSlavePort(const std::string &if_name, PortID idx)
339{
340 if (if_name != "port") {
341 return MemObject::getSlavePort(if_name, idx);
342 } else {
343 return port;
344 }
345}
346
347DrainState
348DRAMSim2::drain()
349{
350 // check our outstanding reads and writes and if any they need to
351 // drain
352 return nbrOutstanding() != 0 ? DrainState::Draining : DrainState::Drained;
353}
354
355DRAMSim2::MemoryPort::MemoryPort(const std::string& _name,
356 DRAMSim2& _memory)
357 : SlavePort(_name, &_memory), memory(_memory)
358{ }
359
360AddrRangeList
361DRAMSim2::MemoryPort::getAddrRanges() const
362{
363 AddrRangeList ranges;
364 ranges.push_back(memory.getAddrRange());
365 return ranges;
366}
367
368Tick
369DRAMSim2::MemoryPort::recvAtomic(PacketPtr pkt)
370{
371 return memory.recvAtomic(pkt);
372}
373
374void
375DRAMSim2::MemoryPort::recvFunctional(PacketPtr pkt)
376{
377 memory.recvFunctional(pkt);
378}
379
380bool
381DRAMSim2::MemoryPort::recvTimingReq(PacketPtr pkt)
382{
383 // pass it to the memory controller
384 return memory.recvTimingReq(pkt);
385}
386
387void
388DRAMSim2::MemoryPort::recvRespRetry()
389{
390 memory.recvRespRetry();
391}
392
393DRAMSim2*
394DRAMSim2Params::create()
395{
396 return new DRAMSim2(this);
397}
47#include "sim/system.hh"
48
49DRAMSim2::DRAMSim2(const Params* p) :
50 AbstractMemory(p),
51 port(name() + ".port", *this),
52 wrapper(p->deviceConfigFile, p->systemConfigFile, p->filePath,
53 p->traceFile, p->range.size() / 1024 / 1024, p->enableDebug),
54 retryReq(false), retryResp(false), startTick(0),
55 nbrOutstandingReads(0), nbrOutstandingWrites(0),
56 sendResponseEvent(this), tickEvent(this)
57{
58 DPRINTF(DRAMSim2,
59 "Instantiated DRAMSim2 with clock %d ns and queue size %d\n",
60 wrapper.clockPeriod(), wrapper.queueSize());
61
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);
69
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);
75}
76
77void
78DRAMSim2::init()
79{
80 AbstractMemory::init();
81
82 if (!port.isConnected()) {
83 fatal("DRAMSim2 %s is unconnected!\n", name());
84 } else {
85 port.sendRangeChange();
86 }
87
88 if (system()->cacheLineSize() != wrapper.burstSize())
89 fatal("DRAMSim2 burst size %d does not match cache line size %d\n",
90 wrapper.burstSize(), system()->cacheLineSize());
91}
92
93void
94DRAMSim2::startup()
95{
96 startTick = curTick();
97
98 // kick off the clock ticks
99 schedule(tickEvent, clockEdge());
100}
101
102void
103DRAMSim2::sendResponse()
104{
105 assert(!retryResp);
106 assert(!responseQueue.empty());
107
108 DPRINTF(DRAMSim2, "Attempting to send response\n");
109
110 bool success = port.sendTimingResp(responseQueue.front());
111 if (success) {
112 responseQueue.pop_front();
113
114 DPRINTF(DRAMSim2, "Have %d read, %d write, %d responses outstanding\n",
115 nbrOutstandingReads, nbrOutstandingWrites,
116 responseQueue.size());
117
118 if (!responseQueue.empty() && !sendResponseEvent.scheduled())
119 schedule(sendResponseEvent, curTick());
120
121 if (nbrOutstanding() == 0)
122 signalDrainDone();
123 } else {
124 retryResp = true;
125
126 DPRINTF(DRAMSim2, "Waiting for response retry\n");
127
128 assert(!sendResponseEvent.scheduled());
129 }
130}
131
132unsigned int
133DRAMSim2::nbrOutstanding() const
134{
135 return nbrOutstandingReads + nbrOutstandingWrites + responseQueue.size();
136}
137
138void
139DRAMSim2::tick()
140{
141 wrapper.tick();
142
143 // is the connected port waiting for a retry, if so check the
144 // state and send a retry if conditions have changed
145 if (retryReq && nbrOutstanding() < wrapper.queueSize()) {
146 retryReq = false;
147 port.sendRetryReq();
148 }
149
150 schedule(tickEvent, curTick() + wrapper.clockPeriod() * SimClock::Int::ns);
151}
152
153Tick
154DRAMSim2::recvAtomic(PacketPtr pkt)
155{
156 access(pkt);
157
158 // 50 ns is just an arbitrary value at this point
159 return pkt->cacheResponding() ? 0 : 50000;
160}
161
162void
163DRAMSim2::recvFunctional(PacketPtr pkt)
164{
165 pkt->pushLabel(name());
166
167 functionalAccess(pkt);
168
169 // potentially update the packets in our response queue as well
170 for (auto i = responseQueue.begin(); i != responseQueue.end(); ++i)
171 pkt->checkFunctional(*i);
172
173 pkt->popLabel();
174}
175
176bool
177DRAMSim2::recvTimingReq(PacketPtr pkt)
178{
179 // if a cache is responding, sink the packet without further action
180 if (pkt->cacheResponding()) {
181 pendingDelete.reset(pkt);
182 return true;
183 }
184
185 // we should not get a new request after committing to retry the
186 // current one, but unfortunately the CPU violates this rule, so
187 // simply ignore it for now
188 if (retryReq)
189 return false;
190
191 // if we cannot accept we need to send a retry once progress can
192 // be made
193 bool can_accept = nbrOutstanding() < wrapper.queueSize();
194
195 // keep track of the transaction
196 if (pkt->isRead()) {
197 if (can_accept) {
198 outstandingReads[pkt->getAddr()].push(pkt);
199
200 // we count a transaction as outstanding until it has left the
201 // queue in the controller, and the response has been sent
202 // back, note that this will differ for reads and writes
203 ++nbrOutstandingReads;
204 }
205 } else if (pkt->isWrite()) {
206 if (can_accept) {
207 outstandingWrites[pkt->getAddr()].push(pkt);
208
209 ++nbrOutstandingWrites;
210
211 // perform the access for writes
212 accessAndRespond(pkt);
213 }
214 } else {
215 // keep it simple and just respond if necessary
216 accessAndRespond(pkt);
217 return true;
218 }
219
220 if (can_accept) {
221 // we should never have a situation when we think there is space,
222 // and there isn't
223 assert(wrapper.canAccept());
224
225 DPRINTF(DRAMSim2, "Enqueueing address %lld\n", pkt->getAddr());
226
227 // @todo what about the granularity here, implicit assumption that
228 // a transaction matches the burst size of the memory (which we
229 // cannot determine without parsing the ini file ourselves)
230 wrapper.enqueue(pkt->isWrite(), pkt->getAddr());
231
232 return true;
233 } else {
234 retryReq = true;
235 return false;
236 }
237}
238
239void
240DRAMSim2::recvRespRetry()
241{
242 DPRINTF(DRAMSim2, "Retrying\n");
243
244 assert(retryResp);
245 retryResp = false;
246 sendResponse();
247}
248
249void
250DRAMSim2::accessAndRespond(PacketPtr pkt)
251{
252 DPRINTF(DRAMSim2, "Access for address %lld\n", pkt->getAddr());
253
254 bool needsResponse = pkt->needsResponse();
255
256 // do the actual memory access which also turns the packet into a
257 // response
258 access(pkt);
259
260 // turn packet around to go back to requester if response expected
261 if (needsResponse) {
262 // access already turned the packet into a response
263 assert(pkt->isResponse());
264 // Here we pay for xbar additional delay and to process the payload
265 // of the packet.
266 Tick time = curTick() + pkt->headerDelay + pkt->payloadDelay;
267 // Reset the timings of the packet
268 pkt->headerDelay = pkt->payloadDelay = 0;
269
270 DPRINTF(DRAMSim2, "Queuing response for address %lld\n",
271 pkt->getAddr());
272
273 // queue it to be sent back
274 responseQueue.push_back(pkt);
275
276 // if we are not already waiting for a retry, or are scheduled
277 // to send a response, schedule an event
278 if (!retryResp && !sendResponseEvent.scheduled())
279 schedule(sendResponseEvent, time);
280 } else {
281 // queue the packet for deletion
282 pendingDelete.reset(pkt);
283 }
284}
285
286void DRAMSim2::readComplete(unsigned id, uint64_t addr, uint64_t cycle)
287{
288 assert(cycle == divCeil(curTick() - startTick,
289 wrapper.clockPeriod() * SimClock::Int::ns));
290
291 DPRINTF(DRAMSim2, "Read to address %lld complete\n", addr);
292
293 // get the outstanding reads for the address in question
294 auto p = outstandingReads.find(addr);
295 assert(p != outstandingReads.end());
296
297 // first in first out, which is not necessarily true, but it is
298 // the best we can do at this point
299 PacketPtr pkt = p->second.front();
300 p->second.pop();
301
302 if (p->second.empty())
303 outstandingReads.erase(p);
304
305 // no need to check for drain here as the next call will add a
306 // response to the response queue straight away
307 assert(nbrOutstandingReads != 0);
308 --nbrOutstandingReads;
309
310 // perform the actual memory access
311 accessAndRespond(pkt);
312}
313
314void DRAMSim2::writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
315{
316 assert(cycle == divCeil(curTick() - startTick,
317 wrapper.clockPeriod() * SimClock::Int::ns));
318
319 DPRINTF(DRAMSim2, "Write to address %lld complete\n", addr);
320
321 // get the outstanding reads for the address in question
322 auto p = outstandingWrites.find(addr);
323 assert(p != outstandingWrites.end());
324
325 // we have already responded, and this is only to keep track of
326 // what is outstanding
327 p->second.pop();
328 if (p->second.empty())
329 outstandingWrites.erase(p);
330
331 assert(nbrOutstandingWrites != 0);
332 --nbrOutstandingWrites;
333
334 if (nbrOutstanding() == 0)
335 signalDrainDone();
336}
337
338BaseSlavePort&
339DRAMSim2::getSlavePort(const std::string &if_name, PortID idx)
340{
341 if (if_name != "port") {
342 return MemObject::getSlavePort(if_name, idx);
343 } else {
344 return port;
345 }
346}
347
348DrainState
349DRAMSim2::drain()
350{
351 // check our outstanding reads and writes and if any they need to
352 // drain
353 return nbrOutstanding() != 0 ? DrainState::Draining : DrainState::Drained;
354}
355
356DRAMSim2::MemoryPort::MemoryPort(const std::string& _name,
357 DRAMSim2& _memory)
358 : SlavePort(_name, &_memory), memory(_memory)
359{ }
360
361AddrRangeList
362DRAMSim2::MemoryPort::getAddrRanges() const
363{
364 AddrRangeList ranges;
365 ranges.push_back(memory.getAddrRange());
366 return ranges;
367}
368
369Tick
370DRAMSim2::MemoryPort::recvAtomic(PacketPtr pkt)
371{
372 return memory.recvAtomic(pkt);
373}
374
375void
376DRAMSim2::MemoryPort::recvFunctional(PacketPtr pkt)
377{
378 memory.recvFunctional(pkt);
379}
380
381bool
382DRAMSim2::MemoryPort::recvTimingReq(PacketPtr pkt)
383{
384 // pass it to the memory controller
385 return memory.recvTimingReq(pkt);
386}
387
388void
389DRAMSim2::MemoryPort::recvRespRetry()
390{
391 memory.recvRespRetry();
392}
393
394DRAMSim2*
395DRAMSim2Params::create()
396{
397 return new DRAMSim2(this);
398}