gem5  v19.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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]{ sendResponse(); }, name()),
57  tickEvent([this]{ tick(); }, name())
58 {
60  "Instantiated DRAMSim2 with clock %d ns and queue size %d\n",
62 
63  DRAMSim::TransactionCompleteCB* read_cb =
64  new DRAMSim::Callback<DRAMSim2, void, unsigned, uint64_t, uint64_t>(
65  this, &DRAMSim2::readComplete);
66  DRAMSim::TransactionCompleteCB* write_cb =
67  new DRAMSim::Callback<DRAMSim2, void, unsigned, uint64_t, uint64_t>(
69  wrapper.setCallbacks(read_cb, write_cb);
70 
71  // Register a callback to compensate for the destructor not
72  // being called. The callback prints the DRAMSim2 stats.
76 }
77 
78 void
80 {
82 
83  if (!port.isConnected()) {
84  fatal("DRAMSim2 %s is unconnected!\n", name());
85  } else {
87  }
88 
89  if (system()->cacheLineSize() != wrapper.burstSize())
90  fatal("DRAMSim2 burst size %d does not match cache line size %d\n",
92 }
93 
94 void
96 {
97  startTick = curTick();
98 
99  // kick off the clock ticks
101 }
102 
103 void
105 {
106  assert(!retryResp);
107  assert(!responseQueue.empty());
108 
109  DPRINTF(DRAMSim2, "Attempting to send response\n");
110 
111  bool success = port.sendTimingResp(responseQueue.front());
112  if (success) {
113  responseQueue.pop_front();
114 
115  DPRINTF(DRAMSim2, "Have %d read, %d write, %d responses outstanding\n",
117  responseQueue.size());
118 
119  if (!responseQueue.empty() && !sendResponseEvent.scheduled())
121 
122  if (nbrOutstanding() == 0)
123  signalDrainDone();
124  } else {
125  retryResp = true;
126 
127  DPRINTF(DRAMSim2, "Waiting for response retry\n");
128 
129  assert(!sendResponseEvent.scheduled());
130  }
131 }
132 
133 unsigned int
135 {
137 }
138 
139 void
141 {
142  wrapper.tick();
143 
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()) {
147  retryReq = false;
148  port.sendRetryReq();
149  }
150 
152 }
153 
154 Tick
156 {
157  access(pkt);
158 
159  // 50 ns is just an arbitrary value at this point
160  return pkt->cacheResponding() ? 0 : 50000;
161 }
162 
163 void
165 {
166  pkt->pushLabel(name());
167 
168  functionalAccess(pkt);
169 
170  // potentially update the packets in our response queue as well
171  for (auto i = responseQueue.begin(); i != responseQueue.end(); ++i)
172  pkt->trySatisfyFunctional(*i);
173 
174  pkt->popLabel();
175 }
176 
177 bool
179 {
180  // if a cache is responding, sink the packet without further action
181  if (pkt->cacheResponding()) {
182  pendingDelete.reset(pkt);
183  return true;
184  }
185 
186  // we should not get a new request after committing to retry the
187  // current one, but unfortunately the CPU violates this rule, so
188  // simply ignore it for now
189  if (retryReq)
190  return false;
191 
192  // if we cannot accept we need to send a retry once progress can
193  // be made
194  bool can_accept = nbrOutstanding() < wrapper.queueSize();
195 
196  // keep track of the transaction
197  if (pkt->isRead()) {
198  if (can_accept) {
199  outstandingReads[pkt->getAddr()].push(pkt);
200 
201  // we count a transaction as outstanding until it has left the
202  // queue in the controller, and the response has been sent
203  // back, note that this will differ for reads and writes
205  }
206  } else if (pkt->isWrite()) {
207  if (can_accept) {
208  outstandingWrites[pkt->getAddr()].push(pkt);
209 
211 
212  // perform the access for writes
213  accessAndRespond(pkt);
214  }
215  } else {
216  // keep it simple and just respond if necessary
217  accessAndRespond(pkt);
218  return true;
219  }
220 
221  if (can_accept) {
222  // we should never have a situation when we think there is space,
223  // and there isn't
224  assert(wrapper.canAccept());
225 
226  DPRINTF(DRAMSim2, "Enqueueing address %lld\n", pkt->getAddr());
227 
228  // @todo what about the granularity here, implicit assumption that
229  // a transaction matches the burst size of the memory (which we
230  // cannot determine without parsing the ini file ourselves)
231  wrapper.enqueue(pkt->isWrite(), pkt->getAddr());
232 
233  return true;
234  } else {
235  retryReq = true;
236  return false;
237  }
238 }
239 
240 void
242 {
243  DPRINTF(DRAMSim2, "Retrying\n");
244 
245  assert(retryResp);
246  retryResp = false;
247  sendResponse();
248 }
249 
250 void
252 {
253  DPRINTF(DRAMSim2, "Access for address %lld\n", pkt->getAddr());
254 
255  bool needsResponse = pkt->needsResponse();
256 
257  // do the actual memory access which also turns the packet into a
258  // response
259  access(pkt);
260 
261  // turn packet around to go back to requester if response expected
262  if (needsResponse) {
263  // access already turned the packet into a response
264  assert(pkt->isResponse());
265  // Here we pay for xbar additional delay and to process the payload
266  // of the packet.
267  Tick time = curTick() + pkt->headerDelay + pkt->payloadDelay;
268  // Reset the timings of the packet
269  pkt->headerDelay = pkt->payloadDelay = 0;
270 
271  DPRINTF(DRAMSim2, "Queuing response for address %lld\n",
272  pkt->getAddr());
273 
274  // queue it to be sent back
275  responseQueue.push_back(pkt);
276 
277  // if we are not already waiting for a retry, or are scheduled
278  // to send a response, schedule an event
281  } else {
282  // queue the packet for deletion
283  pendingDelete.reset(pkt);
284  }
285 }
286 
287 void DRAMSim2::readComplete(unsigned id, uint64_t addr, uint64_t cycle)
288 {
289  assert(cycle == divCeil(curTick() - startTick,
291 
292  DPRINTF(DRAMSim2, "Read to address %lld complete\n", addr);
293 
294  // get the outstanding reads for the address in question
295  auto p = outstandingReads.find(addr);
296  assert(p != outstandingReads.end());
297 
298  // first in first out, which is not necessarily true, but it is
299  // the best we can do at this point
300  PacketPtr pkt = p->second.front();
301  p->second.pop();
302 
303  if (p->second.empty())
304  outstandingReads.erase(p);
305 
306  // no need to check for drain here as the next call will add a
307  // response to the response queue straight away
308  assert(nbrOutstandingReads != 0);
310 
311  // perform the actual memory access
312  accessAndRespond(pkt);
313 }
314 
315 void DRAMSim2::writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
316 {
317  assert(cycle == divCeil(curTick() - startTick,
319 
320  DPRINTF(DRAMSim2, "Write to address %lld complete\n", addr);
321 
322  // get the outstanding reads for the address in question
323  auto p = outstandingWrites.find(addr);
324  assert(p != outstandingWrites.end());
325 
326  // we have already responded, and this is only to keep track of
327  // what is outstanding
328  p->second.pop();
329  if (p->second.empty())
330  outstandingWrites.erase(p);
331 
332  assert(nbrOutstandingWrites != 0);
334 
335  if (nbrOutstanding() == 0)
336  signalDrainDone();
337 }
338 
339 Port &
340 DRAMSim2::getPort(const std::string &if_name, PortID idx)
341 {
342  if (if_name != "port") {
343  return AbstractMemory::getPort(if_name, idx);
344  } else {
345  return port;
346  }
347 }
348 
351 {
352  // check our outstanding reads and writes and if any they need to
353  // drain
355 }
356 
357 DRAMSim2::MemoryPort::MemoryPort(const std::string& _name,
358  DRAMSim2& _memory)
359  : SlavePort(_name, &_memory), memory(_memory)
360 { }
361 
364 {
365  AddrRangeList ranges;
366  ranges.push_back(memory.getAddrRange());
367  return ranges;
368 }
369 
370 Tick
372 {
373  return memory.recvAtomic(pkt);
374 }
375 
376 void
378 {
379  memory.recvFunctional(pkt);
380 }
381 
382 bool
384 {
385  // pass it to the memory controller
386  return memory.recvTimingReq(pkt);
387 }
388 
389 void
391 {
392  memory.recvRespRetry();
393 }
394 
395 DRAMSim2*
396 DRAMSim2Params::create()
397 {
398  return new DRAMSim2(this);
399 }
MemoryPort(const std::string &_name, DRAMSim2 &_memory)
Definition: dramsim2.cc:357
#define DPRINTF(x,...)
Definition: trace.hh:229
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:155
Ports are used to interface objects to each other.
Definition: port.hh:60
Wrapper class to avoid having DRAMSim2 names like ClockDomain etc clashing with the normal gem5 world...
void printStats()
Print the stats gathered in DRAMsim2.
EventFunctionWrapper sendResponseEvent
Event to schedule sending of responses.
Definition: dramsim2.hh:151
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Definition: sim_object.cc:126
void recvFunctional(PacketPtr pkt)
Definition: dramsim2.cc:164
void sendRangeChange() const
Called by the owner to send a range change.
Definition: port.hh:286
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:175
Generic callback class.
Definition: callback.hh:41
const std::string & name()
Definition: trace.cc:54
Bitfield< 7 > i
DrainState drain() override
Notify an object that it needs to drain its state.
Definition: dramsim2.cc:350
DrainState
Object drain/handover states.
Definition: drain.hh:71
void recvRespRetry()
Definition: dramsim2.cc:241
Running normally.
unsigned int nbrOutstanding() const
Definition: dramsim2.cc:134
void enqueue(bool is_write, uint64_t addr)
Enqueue a packet.
void recvFunctional(PacketPtr pkt)
Receive a functional request packet from the peer.
Definition: dramsim2.cc:377
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 cacheResponding() const
Definition: packet.hh:591
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
void signalDrainDone() const
Signal that an object is drained.
Definition: drain.hh:267
DRAMSim2.
bool isConnected() const
Is this port currently connected to a peer?
Definition: port.hh:128
A SlavePort is a specialisation of a port.
Definition: port.hh:258
void readComplete(unsigned id, uint64_t addr, uint64_t cycle)
Read completion callback.
Definition: dramsim2.cc:287
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1326
bool isWrite() const
Definition: packet.hh:529
std::unordered_map< Addr, std::queue< PacketPtr > > outstandingWrites
Definition: dramsim2.hh:118
bool isRead() const
Definition: packet.hh:528
unsigned int nbrOutstandingWrites
Definition: dramsim2.hh:126
void recvRespRetry()
Called by the peer if sendTimingResp was called on this protocol (causing recvTimingResp to be called...
Definition: dramsim2.cc:390
void tick()
Progress the controller one clock cycle.
Definition: dramsim2.cc:140
void startup() override
startup() is the final initialization call before simulation.
Definition: dramsim2.cc:95
bool sendTimingResp(PacketPtr pkt)
Attempt to send a timing response to the master port by calling its corresponding receive function...
Definition: port.hh:357
Tick curTick()
The current simulated tick.
Definition: core.hh:47
bool recvTimingReq(PacketPtr pkt)
Definition: dramsim2.cc:178
bool needsResponse() const
Definition: packet.hh:542
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:385
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:366
unsigned int burstSize() const
Get the burst size in bytes used by DRAMSim2.
uint64_t Tick
Tick count type.
Definition: types.hh:63
bool isResponse() const
Definition: packet.hh:532
bool trySatisfyFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
Definition: packet.hh:1264
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1336
void writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
Write completion callback.
Definition: dramsim2.cc:315
void access(PacketPtr pkt)
Perform an untimed memory access and update all the state (e.g.
Addr getAddr() const
Definition: packet.hh:726
void registerExitCallback(Callback *callback)
Register an exit callback.
Definition: core.cc:143
void accessAndRespond(PacketPtr pkt)
When a packet is ready, use the "access()" method in AbstractMemory to actually create the response p...
Definition: dramsim2.cc:251
DRAMSim2Wrapper wrapper
The actual DRAMSim2 wrapper.
Definition: dramsim2.hh:94
unsigned int queueSize() const
Get the transaction queue size used by DRAMSim2.
Tick startTick
Keep track of when the wrapper is started.
Definition: dramsim2.hh:109
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:384
virtual const std::string name() const
Definition: sim_object.hh:120
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:255
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...
bool canAccept() const
Determine if the controller can accept a new packet or not.
void setCallbacks(DRAMSim::TransactionCompleteCB *read_callback, DRAMSim::TransactionCompleteCB *write_callback)
Set the callbacks to use for read and write completion.
AddrRangeList getAddrRanges() const
Get a list of the non-overlapping address ranges the owner is responsible for.
Definition: dramsim2.cc:363
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:71
Tick recvAtomic(PacketPtr pkt)
Receive an atomic request packet from the peer.
Definition: dramsim2.cc:371
bool retryReq
Is the connected port waiting for a retry from us.
Definition: dramsim2.hh:99
System * system() const
read the system pointer Implemented for completeness with the setter
DRAMSim2(const Params *p)
Definition: dramsim2.cc:49
Cycles cycle
void sendRetryReq()
Send a retry to the master port that previously attempted a sendTimingReq to this slave port and fail...
Definition: port.hh:380
void sendResponse()
Definition: dramsim2.cc:104
EventFunctionWrapper tickEvent
Event to schedule clock ticks.
Definition: dramsim2.hh:161
MemoryPort port
Definition: dramsim2.hh:89
T divCeil(const T &a, const U &b)
Definition: intmath.hh:153
void schedule(Event &event, Tick when)
Definition: eventq.hh:744
Definition: mem.h:38
An abstract memory represents a contiguous block of physical memory, with an associated address range...
Tick ns
nanosecond
Definition: core.cc:68
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:237
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.
double clockPeriod() const
Get the internal clock period used by DRAMSim2, specified in ns.
unsigned int nbrOutstandingReads
Count the number of outstanding transactions so that we can block any further requests until there is...
Definition: dramsim2.hh:125
Bitfield< 0 > p
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: dramsim2.cc:340
bool recvTimingReq(PacketPtr pkt)
Receive a timing request from the peer.
Definition: dramsim2.cc:383
void init() override
Initialise this memory.
Definition: dramsim2.cc:79
unsigned int cacheLineSize() const
Get the cache line size of the system.
Definition: system.hh:188

Generated on Fri Feb 28 2020 16:27:02 for gem5 by doxygen 1.8.13