dramsim2.cc (10721:3e6a3eaac71b) dramsim2.cc (10910:32f3d1c454ec)
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 "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"
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 drainManager(NULL),
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 // check if we were asked to drain and if we are now done
122 if (drainManager && nbrOutstanding() == 0) {
123 drainManager->signalDrainDone();
124 drainManager = NULL;
125 }
126 } else {
127 retryResp = true;
128
129 DPRINTF(DRAMSim2, "Waiting for response retry\n");
130
131 assert(!sendResponseEvent.scheduled());
132 }
133}
134
135unsigned int
136DRAMSim2::nbrOutstanding() const
137{
138 return nbrOutstandingReads + nbrOutstandingWrites + responseQueue.size();
139}
140
141void
142DRAMSim2::tick()
143{
144 wrapper.tick();
145
146 // is the connected port waiting for a retry, if so check the
147 // state and send a retry if conditions have changed
148 if (retryReq && nbrOutstanding() < wrapper.queueSize()) {
149 retryReq = false;
150 port.sendRetryReq();
151 }
152
153 schedule(tickEvent, curTick() + wrapper.clockPeriod() * SimClock::Int::ns);
154}
155
156Tick
157DRAMSim2::recvAtomic(PacketPtr pkt)
158{
159 access(pkt);
160
161 // 50 ns is just an arbitrary value at this point
162 return pkt->memInhibitAsserted() ? 0 : 50000;
163}
164
165void
166DRAMSim2::recvFunctional(PacketPtr pkt)
167{
168 pkt->pushLabel(name());
169
170 functionalAccess(pkt);
171
172 // potentially update the packets in our response queue as well
173 for (auto i = responseQueue.begin(); i != responseQueue.end(); ++i)
174 pkt->checkFunctional(*i);
175
176 pkt->popLabel();
177}
178
179bool
180DRAMSim2::recvTimingReq(PacketPtr pkt)
181{
182 // we should never see a new request while in retry
183 assert(!retryReq);
184
185 // @todo temporary hack to deal with memory corruption issues until
186 // 4-phase transactions are complete
187 for (int x = 0; x < pendingDelete.size(); x++)
188 delete pendingDelete[x];
189 pendingDelete.clear();
190
191 if (pkt->memInhibitAsserted()) {
192 // snooper will supply based on copy of packet
193 // still target's responsibility to delete packet
194 pendingDelete.push_back(pkt);
195 return true;
196 }
197
198 // if we cannot accept we need to send a retry once progress can
199 // be made
200 bool can_accept = nbrOutstanding() < wrapper.queueSize();
201
202 // keep track of the transaction
203 if (pkt->isRead()) {
204 if (can_accept) {
205 outstandingReads[pkt->getAddr()].push(pkt);
206
207 // we count a transaction as outstanding until it has left the
208 // queue in the controller, and the response has been sent
209 // back, note that this will differ for reads and writes
210 ++nbrOutstandingReads;
211 }
212 } else if (pkt->isWrite()) {
213 if (can_accept) {
214 outstandingWrites[pkt->getAddr()].push(pkt);
215
216 ++nbrOutstandingWrites;
217
218 // perform the access for writes
219 accessAndRespond(pkt);
220 }
221 } else {
222 // keep it simple and just respond if necessary
223 accessAndRespond(pkt);
224 return true;
225 }
226
227 if (can_accept) {
228 // we should never have a situation when we think there is space,
229 // and there isn't
230 assert(wrapper.canAccept());
231
232 DPRINTF(DRAMSim2, "Enqueueing address %lld\n", pkt->getAddr());
233
234 // @todo what about the granularity here, implicit assumption that
235 // a transaction matches the burst size of the memory (which we
236 // cannot determine without parsing the ini file ourselves)
237 wrapper.enqueue(pkt->isWrite(), pkt->getAddr());
238
239 return true;
240 } else {
241 retryReq = true;
242 return false;
243 }
244}
245
246void
247DRAMSim2::recvRespRetry()
248{
249 DPRINTF(DRAMSim2, "Retrying\n");
250
251 assert(retryResp);
252 retryResp = false;
253 sendResponse();
254}
255
256void
257DRAMSim2::accessAndRespond(PacketPtr pkt)
258{
259 DPRINTF(DRAMSim2, "Access for address %lld\n", pkt->getAddr());
260
261 bool needsResponse = pkt->needsResponse();
262
263 // do the actual memory access which also turns the packet into a
264 // response
265 access(pkt);
266
267 // turn packet around to go back to requester if response expected
268 if (needsResponse) {
269 // access already turned the packet into a response
270 assert(pkt->isResponse());
271 // Here we pay for xbar additional delay and to process the payload
272 // of the packet.
273 Tick time = curTick() + pkt->headerDelay + pkt->payloadDelay;
274 // Reset the timings of the packet
275 pkt->headerDelay = pkt->payloadDelay = 0;
276
277 DPRINTF(DRAMSim2, "Queuing response for address %lld\n",
278 pkt->getAddr());
279
280 // queue it to be sent back
281 responseQueue.push_back(pkt);
282
283 // if we are not already waiting for a retry, or are scheduled
284 // to send a response, schedule an event
285 if (!retryResp && !sendResponseEvent.scheduled())
286 schedule(sendResponseEvent, time);
287 } else {
288 // @todo the packet is going to be deleted, and the DRAMPacket
289 // is still having a pointer to it
290 pendingDelete.push_back(pkt);
291 }
292}
293
294void DRAMSim2::readComplete(unsigned id, uint64_t addr, uint64_t cycle)
295{
296 assert(cycle == divCeil(curTick() - startTick,
297 wrapper.clockPeriod() * SimClock::Int::ns));
298
299 DPRINTF(DRAMSim2, "Read to address %lld complete\n", addr);
300
301 // get the outstanding reads for the address in question
302 auto p = outstandingReads.find(addr);
303 assert(p != outstandingReads.end());
304
305 // first in first out, which is not necessarily true, but it is
306 // the best we can do at this point
307 PacketPtr pkt = p->second.front();
308 p->second.pop();
309
310 if (p->second.empty())
311 outstandingReads.erase(p);
312
313 // no need to check for drain here as the next call will add a
314 // response to the response queue straight away
315 assert(nbrOutstandingReads != 0);
316 --nbrOutstandingReads;
317
318 // perform the actual memory access
319 accessAndRespond(pkt);
320}
321
322void DRAMSim2::writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
323{
324 assert(cycle == divCeil(curTick() - startTick,
325 wrapper.clockPeriod() * SimClock::Int::ns));
326
327 DPRINTF(DRAMSim2, "Write to address %lld complete\n", addr);
328
329 // get the outstanding reads for the address in question
330 auto p = outstandingWrites.find(addr);
331 assert(p != outstandingWrites.end());
332
333 // we have already responded, and this is only to keep track of
334 // what is outstanding
335 p->second.pop();
336 if (p->second.empty())
337 outstandingWrites.erase(p);
338
339 assert(nbrOutstandingWrites != 0);
340 --nbrOutstandingWrites;
341
342 // check if we were asked to drain and if we are now done
343 if (drainManager && nbrOutstanding() == 0) {
344 drainManager->signalDrainDone();
345 drainManager = NULL;
346 }
347}
348
349BaseSlavePort&
350DRAMSim2::getSlavePort(const std::string &if_name, PortID idx)
351{
352 if (if_name != "port") {
353 return MemObject::getSlavePort(if_name, idx);
354 } else {
355 return port;
356 }
357}
358
359unsigned int
360DRAMSim2::drain(DrainManager* dm)
361{
362 // check our outstanding reads and writes and if any they need to
363 // drain
364 if (nbrOutstanding() != 0) {
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 "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"
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 drainManager(NULL),
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 // check if we were asked to drain and if we are now done
122 if (drainManager && nbrOutstanding() == 0) {
123 drainManager->signalDrainDone();
124 drainManager = NULL;
125 }
126 } else {
127 retryResp = true;
128
129 DPRINTF(DRAMSim2, "Waiting for response retry\n");
130
131 assert(!sendResponseEvent.scheduled());
132 }
133}
134
135unsigned int
136DRAMSim2::nbrOutstanding() const
137{
138 return nbrOutstandingReads + nbrOutstandingWrites + responseQueue.size();
139}
140
141void
142DRAMSim2::tick()
143{
144 wrapper.tick();
145
146 // is the connected port waiting for a retry, if so check the
147 // state and send a retry if conditions have changed
148 if (retryReq && nbrOutstanding() < wrapper.queueSize()) {
149 retryReq = false;
150 port.sendRetryReq();
151 }
152
153 schedule(tickEvent, curTick() + wrapper.clockPeriod() * SimClock::Int::ns);
154}
155
156Tick
157DRAMSim2::recvAtomic(PacketPtr pkt)
158{
159 access(pkt);
160
161 // 50 ns is just an arbitrary value at this point
162 return pkt->memInhibitAsserted() ? 0 : 50000;
163}
164
165void
166DRAMSim2::recvFunctional(PacketPtr pkt)
167{
168 pkt->pushLabel(name());
169
170 functionalAccess(pkt);
171
172 // potentially update the packets in our response queue as well
173 for (auto i = responseQueue.begin(); i != responseQueue.end(); ++i)
174 pkt->checkFunctional(*i);
175
176 pkt->popLabel();
177}
178
179bool
180DRAMSim2::recvTimingReq(PacketPtr pkt)
181{
182 // we should never see a new request while in retry
183 assert(!retryReq);
184
185 // @todo temporary hack to deal with memory corruption issues until
186 // 4-phase transactions are complete
187 for (int x = 0; x < pendingDelete.size(); x++)
188 delete pendingDelete[x];
189 pendingDelete.clear();
190
191 if (pkt->memInhibitAsserted()) {
192 // snooper will supply based on copy of packet
193 // still target's responsibility to delete packet
194 pendingDelete.push_back(pkt);
195 return true;
196 }
197
198 // if we cannot accept we need to send a retry once progress can
199 // be made
200 bool can_accept = nbrOutstanding() < wrapper.queueSize();
201
202 // keep track of the transaction
203 if (pkt->isRead()) {
204 if (can_accept) {
205 outstandingReads[pkt->getAddr()].push(pkt);
206
207 // we count a transaction as outstanding until it has left the
208 // queue in the controller, and the response has been sent
209 // back, note that this will differ for reads and writes
210 ++nbrOutstandingReads;
211 }
212 } else if (pkt->isWrite()) {
213 if (can_accept) {
214 outstandingWrites[pkt->getAddr()].push(pkt);
215
216 ++nbrOutstandingWrites;
217
218 // perform the access for writes
219 accessAndRespond(pkt);
220 }
221 } else {
222 // keep it simple and just respond if necessary
223 accessAndRespond(pkt);
224 return true;
225 }
226
227 if (can_accept) {
228 // we should never have a situation when we think there is space,
229 // and there isn't
230 assert(wrapper.canAccept());
231
232 DPRINTF(DRAMSim2, "Enqueueing address %lld\n", pkt->getAddr());
233
234 // @todo what about the granularity here, implicit assumption that
235 // a transaction matches the burst size of the memory (which we
236 // cannot determine without parsing the ini file ourselves)
237 wrapper.enqueue(pkt->isWrite(), pkt->getAddr());
238
239 return true;
240 } else {
241 retryReq = true;
242 return false;
243 }
244}
245
246void
247DRAMSim2::recvRespRetry()
248{
249 DPRINTF(DRAMSim2, "Retrying\n");
250
251 assert(retryResp);
252 retryResp = false;
253 sendResponse();
254}
255
256void
257DRAMSim2::accessAndRespond(PacketPtr pkt)
258{
259 DPRINTF(DRAMSim2, "Access for address %lld\n", pkt->getAddr());
260
261 bool needsResponse = pkt->needsResponse();
262
263 // do the actual memory access which also turns the packet into a
264 // response
265 access(pkt);
266
267 // turn packet around to go back to requester if response expected
268 if (needsResponse) {
269 // access already turned the packet into a response
270 assert(pkt->isResponse());
271 // Here we pay for xbar additional delay and to process the payload
272 // of the packet.
273 Tick time = curTick() + pkt->headerDelay + pkt->payloadDelay;
274 // Reset the timings of the packet
275 pkt->headerDelay = pkt->payloadDelay = 0;
276
277 DPRINTF(DRAMSim2, "Queuing response for address %lld\n",
278 pkt->getAddr());
279
280 // queue it to be sent back
281 responseQueue.push_back(pkt);
282
283 // if we are not already waiting for a retry, or are scheduled
284 // to send a response, schedule an event
285 if (!retryResp && !sendResponseEvent.scheduled())
286 schedule(sendResponseEvent, time);
287 } else {
288 // @todo the packet is going to be deleted, and the DRAMPacket
289 // is still having a pointer to it
290 pendingDelete.push_back(pkt);
291 }
292}
293
294void DRAMSim2::readComplete(unsigned id, uint64_t addr, uint64_t cycle)
295{
296 assert(cycle == divCeil(curTick() - startTick,
297 wrapper.clockPeriod() * SimClock::Int::ns));
298
299 DPRINTF(DRAMSim2, "Read to address %lld complete\n", addr);
300
301 // get the outstanding reads for the address in question
302 auto p = outstandingReads.find(addr);
303 assert(p != outstandingReads.end());
304
305 // first in first out, which is not necessarily true, but it is
306 // the best we can do at this point
307 PacketPtr pkt = p->second.front();
308 p->second.pop();
309
310 if (p->second.empty())
311 outstandingReads.erase(p);
312
313 // no need to check for drain here as the next call will add a
314 // response to the response queue straight away
315 assert(nbrOutstandingReads != 0);
316 --nbrOutstandingReads;
317
318 // perform the actual memory access
319 accessAndRespond(pkt);
320}
321
322void DRAMSim2::writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
323{
324 assert(cycle == divCeil(curTick() - startTick,
325 wrapper.clockPeriod() * SimClock::Int::ns));
326
327 DPRINTF(DRAMSim2, "Write to address %lld complete\n", addr);
328
329 // get the outstanding reads for the address in question
330 auto p = outstandingWrites.find(addr);
331 assert(p != outstandingWrites.end());
332
333 // we have already responded, and this is only to keep track of
334 // what is outstanding
335 p->second.pop();
336 if (p->second.empty())
337 outstandingWrites.erase(p);
338
339 assert(nbrOutstandingWrites != 0);
340 --nbrOutstandingWrites;
341
342 // check if we were asked to drain and if we are now done
343 if (drainManager && nbrOutstanding() == 0) {
344 drainManager->signalDrainDone();
345 drainManager = NULL;
346 }
347}
348
349BaseSlavePort&
350DRAMSim2::getSlavePort(const std::string &if_name, PortID idx)
351{
352 if (if_name != "port") {
353 return MemObject::getSlavePort(if_name, idx);
354 } else {
355 return port;
356 }
357}
358
359unsigned int
360DRAMSim2::drain(DrainManager* dm)
361{
362 // check our outstanding reads and writes and if any they need to
363 // drain
364 if (nbrOutstanding() != 0) {
365 setDrainState(Drainable::Draining);
365 setDrainState(DrainState::Draining);
366 drainManager = dm;
367 return 1;
368 } else {
366 drainManager = dm;
367 return 1;
368 } else {
369 setDrainState(Drainable::Drained);
369 setDrainState(DrainState::Drained);
370 return 0;
371 }
372}
373
374DRAMSim2::MemoryPort::MemoryPort(const std::string& _name,
375 DRAMSim2& _memory)
376 : SlavePort(_name, &_memory), memory(_memory)
377{ }
378
379AddrRangeList
380DRAMSim2::MemoryPort::getAddrRanges() const
381{
382 AddrRangeList ranges;
383 ranges.push_back(memory.getAddrRange());
384 return ranges;
385}
386
387Tick
388DRAMSim2::MemoryPort::recvAtomic(PacketPtr pkt)
389{
390 return memory.recvAtomic(pkt);
391}
392
393void
394DRAMSim2::MemoryPort::recvFunctional(PacketPtr pkt)
395{
396 memory.recvFunctional(pkt);
397}
398
399bool
400DRAMSim2::MemoryPort::recvTimingReq(PacketPtr pkt)
401{
402 // pass it to the memory controller
403 return memory.recvTimingReq(pkt);
404}
405
406void
407DRAMSim2::MemoryPort::recvRespRetry()
408{
409 memory.recvRespRetry();
410}
411
412DRAMSim2*
413DRAMSim2Params::create()
414{
415 return new DRAMSim2(this);
416}
370 return 0;
371 }
372}
373
374DRAMSim2::MemoryPort::MemoryPort(const std::string& _name,
375 DRAMSim2& _memory)
376 : SlavePort(_name, &_memory), memory(_memory)
377{ }
378
379AddrRangeList
380DRAMSim2::MemoryPort::getAddrRanges() const
381{
382 AddrRangeList ranges;
383 ranges.push_back(memory.getAddrRange());
384 return ranges;
385}
386
387Tick
388DRAMSim2::MemoryPort::recvAtomic(PacketPtr pkt)
389{
390 return memory.recvAtomic(pkt);
391}
392
393void
394DRAMSim2::MemoryPort::recvFunctional(PacketPtr pkt)
395{
396 memory.recvFunctional(pkt);
397}
398
399bool
400DRAMSim2::MemoryPort::recvTimingReq(PacketPtr pkt)
401{
402 // pass it to the memory controller
403 return memory.recvTimingReq(pkt);
404}
405
406void
407DRAMSim2::MemoryPort::recvRespRetry()
408{
409 memory.recvRespRetry();
410}
411
412DRAMSim2*
413DRAMSim2Params::create()
414{
415 return new DRAMSim2(this);
416}