gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
dramsim2.cc
Go to the documentation of this file.
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 
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"
47 #include "sim/system.hh"
48 
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 {
59  "Instantiated DRAMSim2 with clock %d ns and queue size %d\n",
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>(
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.
75 }
76 
77 void
79 {
81 
82  if (!port.isConnected()) {
83  fatal("DRAMSim2 %s is unconnected!\n", name());
84  } else {
86  }
87 
88  if (system()->cacheLineSize() != wrapper.burstSize())
89  fatal("DRAMSim2 burst size %d does not match cache line size %d\n",
91 }
92 
93 void
95 {
96  startTick = curTick();
97 
98  // kick off the clock ticks
100 }
101 
102 void
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",
116  responseQueue.size());
117 
118  if (!responseQueue.empty() && !sendResponseEvent.scheduled())
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 
132 unsigned int
134 {
136 }
137 
138 void
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 
151 }
152 
153 Tick
155 {
156  access(pkt);
157 
158  // 50 ns is just an arbitrary value at this point
159  return pkt->cacheResponding() ? 0 : 50000;
160 }
161 
162 void
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 
176 bool
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
204  }
205  } else if (pkt->isWrite()) {
206  if (can_accept) {
207  outstandingWrites[pkt->getAddr()].push(pkt);
208 
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 
239 void
241 {
242  DPRINTF(DRAMSim2, "Retrying\n");
243 
244  assert(retryResp);
245  retryResp = false;
246  sendResponse();
247 }
248 
249 void
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
280  } else {
281  // queue the packet for deletion
282  pendingDelete.reset(pkt);
283  }
284 }
285 
286 void DRAMSim2::readComplete(unsigned id, uint64_t addr, uint64_t cycle)
287 {
288  assert(cycle == divCeil(curTick() - startTick,
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);
309 
310  // perform the actual memory access
311  accessAndRespond(pkt);
312 }
313 
314 void DRAMSim2::writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
315 {
316  assert(cycle == divCeil(curTick() - startTick,
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);
333 
334  if (nbrOutstanding() == 0)
335  signalDrainDone();
336 }
337 
339 DRAMSim2::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 
350 {
351  // check our outstanding reads and writes and if any they need to
352  // drain
354 }
355 
356 DRAMSim2::MemoryPort::MemoryPort(const std::string& _name,
357  DRAMSim2& _memory)
358  : SlavePort(_name, &_memory), memory(_memory)
359 { }
360 
363 {
364  AddrRangeList ranges;
365  ranges.push_back(memory.getAddrRange());
366  return ranges;
367 }
368 
369 Tick
371 {
372  return memory.recvAtomic(pkt);
373 }
374 
375 void
377 {
378  memory.recvFunctional(pkt);
379 }
380 
381 bool
383 {
384  // pass it to the memory controller
385  return memory.recvTimingReq(pkt);
386 }
387 
388 void
390 {
391  memory.recvRespRetry();
392 }
393 
394 DRAMSim2*
395 DRAMSim2Params::create()
396 {
397  return new DRAMSim2(this);
398 }
MemoryPort(const std::string &_name, DRAMSim2 &_memory)
Definition: dramsim2.cc:356
#define DPRINTF(x,...)
Definition: trace.hh:212
void functionalAccess(PacketPtr pkt)
Perform an untimed memory read or write without changing anything but the memory itself.
Tick recvAtomic(PacketPtr pkt)
Definition: dramsim2.cc:154
Wrapper class to avoid having DRAMSim2 names like ClockDomain etc clashing with the normal gem5 world...
void printStats()
Print the stats gathered in DRAMsim2.
void recvFunctional(PacketPtr pkt)
Definition: dramsim2.cc:163
Generic callback class.
Definition: callback.hh:41
const std::string & name()
Definition: trace.cc:49
Bitfield< 7 > i
Definition: miscregs.hh:1378
DrainState drain() override
Notify an object that it needs to drain its state.
Definition: dramsim2.cc:349
DrainState
Object drain/handover states.
Definition: drain.hh:71
void recvRespRetry()
Definition: dramsim2.cc:240
Running normally.
void enqueue(bool is_write, uint64_t addr)
Enqueue a packet.
void recvFunctional(PacketPtr pkt)
Receive a functional request packet from the master port.
Definition: dramsim2.cc:376
Tick startTick
Definition: stat_control.cc:72
bool retryResp
Are we waiting for a retry for sending a response.
Definition: dramsim2.hh:104
ip6_addr_t addr
Definition: inet.hh:335
bool isWrite() const
Definition: packet.hh:503
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:381
std::unique_ptr< Packet > pendingDelete
Upstream caches need this packet until true is returned, so hold it for deletion until a subsequent c...
Definition: dramsim2.hh:167
DRAMSim2.
A SlavePort is a specialisation of a port.
Definition: port.hh:331
virtual BaseSlavePort & getSlavePort(const std::string &if_name, PortID idx=InvalidPortID)
Get a slave port with a given name and index.
Definition: mem_object.cc:58
unsigned int nbrOutstanding() const
Definition: dramsim2.cc:133
void readComplete(unsigned id, uint64_t addr, uint64_t cycle)
Read completion callback.
Definition: dramsim2.cc:286
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1160
A BaseSlavePort is a protocol-agnostic slave port, responsible only for the structural connection to ...
Definition: port.hh:139
std::unordered_map< Addr, std::queue< PacketPtr > > outstandingWrites
Definition: dramsim2.hh:118
unsigned int cacheLineSize() const
Get the cache line size of the system.
Definition: system.hh:193
unsigned int nbrOutstandingWrites
Definition: dramsim2.hh:126
void recvRespRetry()
Called by the master port if sendTimingResp was called on this slave port (causing recvTimingResp to ...
Definition: dramsim2.cc:389
void tick()
Progress the controller one clock cycle.
Definition: dramsim2.cc:139
double clockPeriod() const
Get the internal clock period used by DRAMSim2, specified in ns.
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
void startup() override
startup() is the final initialization call before simulation.
Definition: dramsim2.cc:94
bool sendTimingResp(PacketPtr pkt)
Attempt to send a timing response to the master port by calling its corresponding receive function...
Definition: port.cc:251
Tick curTick()
The current simulated tick.
Definition: core.hh:47
bool recvTimingReq(PacketPtr pkt)
Definition: dramsim2.cc:177
std::deque< PacketPtr > responseQueue
Queue to hold response packets until we can send them back.
Definition: dramsim2.hh:133
AbstractMemoryParams Params
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition: packet.hh:340
uint64_t Tick
Tick count type.
Definition: types.hh:63
System * system() const
read the system pointer Implemented for completeness with the setter
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1170
void writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
Write completion callback.
Definition: dramsim2.cc:314
void access(PacketPtr pkt)
Perform an untimed memory access and update all the state (e.g.
#define fatal(...)
Definition: misc.hh:163
void registerExitCallback(Callback *callback)
Register an exit callback.
Definition: core.cc:116
void accessAndRespond(PacketPtr pkt)
When a packet is ready, use the "access()" method in AbstractMemory to actually create the response p...
Definition: dramsim2.cc:250
bool needsResponse() const
Definition: packet.hh:516
DRAMSim2Wrapper wrapper
The actual DRAMSim2 wrapper.
Definition: dramsim2.hh:94
bool isRead() const
Definition: packet.hh:502
Tick startTick
Keep track of when the wrapper is started.
Definition: dramsim2.hh:109
bool cacheResponding() const
Definition: packet.hh:558
Draining buffers pending serialization/handover.
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition: packet.hh:358
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:245
EventWrapper< DRAMSim2,&DRAMSim2::sendResponse > sendResponseEvent
Event to schedule sending of responses.
Definition: dramsim2.hh:151
virtual BaseSlavePort & getSlavePort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a slave port with a given name and index.
Definition: dramsim2.cc:339
void sendRangeChange() const
Called by the owner to send a range change.
Definition: port.hh:410
void setCallbacks(DRAMSim::TransactionCompleteCB *read_callback, DRAMSim::TransactionCompleteCB *write_callback)
Set the callbacks to use for read and write completion.
bool checkFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
Definition: packet.hh:1115
EventWrapper< DRAMSim2,&DRAMSim2::tick > tickEvent
Event to schedule clock ticks.
Definition: dramsim2.hh:161
unsigned int queueSize() const
Get the transaction queue size used by DRAMSim2.
std::unordered_map< Addr, std::queue< PacketPtr > > outstandingReads
Keep track of what packets are outstanding per address, and do so separately for reads and writes...
Definition: dramsim2.hh:117
void init() override
Initialise this memory.
Definition: abstract_mem.cc:66
Tick recvAtomic(PacketPtr pkt)
Receive an atomic request packet from the master port.
Definition: dramsim2.cc:370
int size()
Definition: pagetable.hh:146
virtual const std::string name() const
Definition: sim_object.hh:117
bool retryReq
Is the connected port waiting for a retry from us.
Definition: dramsim2.hh:99
bool canAccept() const
Determine if the controller can accept a new packet or not.
DRAMSim2(const Params *p)
Definition: dramsim2.cc:49
void sendRetryReq()
Send a retry to the master port that previously attempted a sendTimingReq to this slave port and fail...
Definition: port.cc:265
void sendResponse()
Definition: dramsim2.cc:103
MemoryPort port
Definition: dramsim2.hh:89
bool isConnected() const
Definition: port.cc:110
void signalDrainDone() const
Signal that an object is drained.
Definition: drain.hh:267
T divCeil(const T &a, const U &b)
Definition: intmath.hh:198
void schedule(Event &event, Tick when)
Definition: eventq.hh:728
An abstract memory represents a contiguous block of physical memory, with an associated address range...
Tick ns
nanosecond
Definition: core.cc:66
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:181
unsigned int burstSize() const
Get the burst size in bytes used by DRAMSim2.
Helper template class to turn a simple class member function into a callback.
Definition: callback.hh:64
void tick()
Progress the memory controller one cycle.
unsigned int nbrOutstandingReads
Count the number of outstanding transactions so that we can block any further requests until there is...
Definition: dramsim2.hh:125
AddrRangeList getAddrRanges() const
Get a list of the non-overlapping address ranges the owner is responsible for.
Definition: dramsim2.cc:362
Bitfield< 0 > p
bool recvTimingReq(PacketPtr pkt)
Receive a timing request from the master port.
Definition: dramsim2.cc:382
void init() override
Initialise this memory.
Definition: dramsim2.cc:78
bool isResponse() const
Definition: packet.hh:506
Addr getAddr() const
Definition: packet.hh:639

Generated on Fri Jun 9 2017 13:03:49 for gem5 by doxygen 1.8.6