gem5  v22.1.0.0
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 
38 #include "mem/dramsim2.hh"
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 "sim/system.hh"
46 
47 namespace gem5
48 {
49 
50 namespace memory
51 {
52 
55  port(name() + ".port", *this),
56  wrapper(p.deviceConfigFile, p.systemConfigFile, p.filePath,
57  p.traceFile, p.range.size() / 1024 / 1024, p.enableDebug),
58  retryReq(false), retryResp(false), startTick(0),
59  nbrOutstandingReads(0), nbrOutstandingWrites(0),
60  sendResponseEvent([this]{ sendResponse(); }, name()),
61  tickEvent([this]{ tick(); }, name())
62 {
63  DPRINTF(DRAMSim2,
64  "Instantiated DRAMSim2 with clock %d ns and queue size %d\n",
65  wrapper.clockPeriod(), wrapper.queueSize());
66 
67  DRAMSim::TransactionCompleteCB* read_cb =
68  new DRAMSim::Callback<DRAMSim2, void, unsigned, uint64_t, uint64_t>(
69  this, &DRAMSim2::readComplete);
70  DRAMSim::TransactionCompleteCB* write_cb =
71  new DRAMSim::Callback<DRAMSim2, void, unsigned, uint64_t, uint64_t>(
73  wrapper.setCallbacks(read_cb, write_cb);
74 
75  // Register a callback to compensate for the destructor not
76  // being called. The callback prints the DRAMSim2 stats.
77  registerExitCallback([this]() { wrapper.printStats(); });
78 }
79 
80 void
82 {
84 
85  if (!port.isConnected()) {
86  fatal("DRAMSim2 %s is unconnected!\n", name());
87  } else {
89  }
90 
91  if (system()->cacheLineSize() != wrapper.burstSize())
92  fatal("DRAMSim2 burst size %d does not match cache line size %d\n",
93  wrapper.burstSize(), system()->cacheLineSize());
94 }
95 
96 void
98 {
99  startTick = curTick();
100 
101  // kick off the clock ticks
103 }
104 
105 void
107 {
108  assert(!retryResp);
109  assert(!responseQueue.empty());
110 
111  DPRINTF(DRAMSim2, "Attempting to send response\n");
112 
113  bool success = port.sendTimingResp(responseQueue.front());
114  if (success) {
115  responseQueue.pop_front();
116 
117  DPRINTF(DRAMSim2, "Have %d read, %d write, %d responses outstanding\n",
119  responseQueue.size());
120 
121  if (!responseQueue.empty() && !sendResponseEvent.scheduled())
123 
124  if (nbrOutstanding() == 0)
125  signalDrainDone();
126  } else {
127  retryResp = true;
128 
129  DPRINTF(DRAMSim2, "Waiting for response retry\n");
130 
131  assert(!sendResponseEvent.scheduled());
132  }
133 }
134 
135 unsigned int
137 {
139 }
140 
141 void
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 
155 }
156 
157 Tick
159 {
160  access(pkt);
161 
162  // 50 ns is just an arbitrary value at this point
163  return pkt->cacheResponding() ? 0 : 50000;
164 }
165 
166 void
168 {
169  pkt->pushLabel(name());
170 
171  functionalAccess(pkt);
172 
173  // potentially update the packets in our response queue as well
174  for (auto i = responseQueue.begin(); i != responseQueue.end(); ++i)
175  pkt->trySatisfyFunctional(*i);
176 
177  pkt->popLabel();
178 }
179 
180 bool
182 {
183  // if a cache is responding, sink the packet without further action
184  if (pkt->cacheResponding()) {
185  pendingDelete.reset(pkt);
186  return true;
187  }
188 
189  // we should not get a new request after committing to retry the
190  // current one, but unfortunately the CPU violates this rule, so
191  // simply ignore it for now
192  if (retryReq)
193  return false;
194 
195  // if we cannot accept we need to send a retry once progress can
196  // be made
197  bool can_accept = nbrOutstanding() < wrapper.queueSize();
198 
199  // keep track of the transaction
200  if (pkt->isRead()) {
201  if (can_accept) {
202  outstandingReads[pkt->getAddr()].push(pkt);
203 
204  // we count a transaction as outstanding until it has left the
205  // queue in the controller, and the response has been sent
206  // back, note that this will differ for reads and writes
208  }
209  } else if (pkt->isWrite()) {
210  if (can_accept) {
211  outstandingWrites[pkt->getAddr()].push(pkt);
212 
214 
215  // perform the access for writes
216  accessAndRespond(pkt);
217  }
218  } else {
219  // keep it simple and just respond if necessary
220  accessAndRespond(pkt);
221  return true;
222  }
223 
224  if (can_accept) {
225  // we should never have a situation when we think there is space,
226  // and there isn't
227  assert(wrapper.canAccept());
228 
229  DPRINTF(DRAMSim2, "Enqueueing address %lld\n", pkt->getAddr());
230 
231  // @todo what about the granularity here, implicit assumption that
232  // a transaction matches the burst size of the memory (which we
233  // cannot determine without parsing the ini file ourselves)
234  wrapper.enqueue(pkt->isWrite(), pkt->getAddr());
235 
236  return true;
237  } else {
238  retryReq = true;
239  return false;
240  }
241 }
242 
243 void
245 {
246  DPRINTF(DRAMSim2, "Retrying\n");
247 
248  assert(retryResp);
249  retryResp = false;
250  sendResponse();
251 }
252 
253 void
255 {
256  DPRINTF(DRAMSim2, "Access for address %lld\n", pkt->getAddr());
257 
258  bool needsResponse = pkt->needsResponse();
259 
260  // do the actual memory access which also turns the packet into a
261  // response
262  access(pkt);
263 
264  // turn packet around to go back to requestor if response expected
265  if (needsResponse) {
266  // access already turned the packet into a response
267  assert(pkt->isResponse());
268  // Here we pay for xbar additional delay and to process the payload
269  // of the packet.
270  Tick time = curTick() + pkt->headerDelay + pkt->payloadDelay;
271  // Reset the timings of the packet
272  pkt->headerDelay = pkt->payloadDelay = 0;
273 
274  DPRINTF(DRAMSim2, "Queuing response for address %lld\n",
275  pkt->getAddr());
276 
277  // queue it to be sent back
278  responseQueue.push_back(pkt);
279 
280  // if we are not already waiting for a retry, or are scheduled
281  // to send a response, schedule an event
284  } else {
285  // queue the packet for deletion
286  pendingDelete.reset(pkt);
287  }
288 }
289 
290 void DRAMSim2::readComplete(unsigned id, uint64_t addr, uint64_t cycle)
291 {
292  assert(cycle == divCeil(curTick() - startTick,
294 
295  DPRINTF(DRAMSim2, "Read to address %lld complete\n", addr);
296 
297  // get the outstanding reads for the address in question
298  auto p = outstandingReads.find(addr);
299  assert(p != outstandingReads.end());
300 
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();
304  p->second.pop();
305 
306  if (p->second.empty())
307  outstandingReads.erase(p);
308 
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);
313 
314  // perform the actual memory access
315  accessAndRespond(pkt);
316 }
317 
318 void DRAMSim2::writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
319 {
320  assert(cycle == divCeil(curTick() - startTick,
322 
323  DPRINTF(DRAMSim2, "Write to address %lld complete\n", addr);
324 
325  // get the outstanding reads for the address in question
326  auto p = outstandingWrites.find(addr);
327  assert(p != outstandingWrites.end());
328 
329  // we have already responded, and this is only to keep track of
330  // what is outstanding
331  p->second.pop();
332  if (p->second.empty())
333  outstandingWrites.erase(p);
334 
335  assert(nbrOutstandingWrites != 0);
337 
338  if (nbrOutstanding() == 0)
339  signalDrainDone();
340 }
341 
342 Port &
343 DRAMSim2::getPort(const std::string &if_name, PortID idx)
344 {
345  if (if_name != "port") {
346  return AbstractMemory::getPort(if_name, idx);
347  } else {
348  return port;
349  }
350 }
351 
354 {
355  // check our outstanding reads and writes and if any they need to
356  // drain
358 }
359 
360 DRAMSim2::MemoryPort::MemoryPort(const std::string& _name,
361  DRAMSim2& _memory)
362  : ResponsePort(_name, &_memory), mem(_memory)
363 { }
364 
367 {
368  AddrRangeList ranges;
369  ranges.push_back(mem.getAddrRange());
370  return ranges;
371 }
372 
373 Tick
375 {
376  return mem.recvAtomic(pkt);
377 }
378 
379 void
381 {
382  mem.recvFunctional(pkt);
383 }
384 
385 bool
387 {
388  // pass it to the memory controller
389  return mem.recvTimingReq(pkt);
390 }
391 
392 void
394 {
395  mem.recvRespRetry();
396 }
397 
398 } // namespace memory
399 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
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...
virtual std::string name() const
Definition: named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
bool isRead() const
Definition: packet.hh:592
Addr getAddr() const
Definition: packet.hh:805
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1448
bool isResponse() const
Definition: packet.hh:597
bool needsResponse() const
Definition: packet.hh:607
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition: packet.hh:448
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition: packet.hh:430
bool isWrite() const
Definition: packet.hh:593
bool trySatisfyFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
Definition: packet.hh:1386
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1458
bool cacheResponding() const
Definition: packet.hh:657
Ports are used to interface objects to each other.
Definition: port.hh:62
bool isConnected() const
Is this port currently connected to a peer?
Definition: port.hh:133
A ResponsePort is a specialization of a port.
Definition: port.hh:270
bool sendTimingResp(PacketPtr pkt)
Attempt to send a timing response to the request port by calling its corresponding receive function.
Definition: port.hh:370
void sendRangeChange() const
Called by the owner to send a range change.
Definition: port.hh:296
void sendRetryReq()
Send a retry to the request port that previously attempted a sendTimingReq to this response port and ...
Definition: port.hh:401
An abstract memory represents a contiguous block of physical memory, with an associated address range...
void access(PacketPtr pkt)
Perform an untimed memory access and update all the state (e.g.
System * system() const
read the system pointer Implemented for completeness with the setter
void functionalAccess(PacketPtr pkt)
Perform an untimed memory read or write without changing anything but the memory itself.
void enqueue(bool is_write, uint64_t addr)
Enqueue a packet.
double clockPeriod() const
Get the internal clock period used by DRAMSim2, specified in ns.
unsigned int queueSize() const
Get the transaction queue size used by DRAMSim2.
unsigned int burstSize() const
Get the burst size in bytes used by DRAMSim2.
bool canAccept() const
Determine if the controller can accept a new packet or not.
void tick()
Progress the memory controller one cycle.
Tick recvAtomic(PacketPtr pkt)
Receive an atomic request packet from the peer.
Definition: dramsim2.cc:374
MemoryPort(const std::string &_name, DRAMSim2 &_memory)
Definition: dramsim2.cc:360
void recvFunctional(PacketPtr pkt)
Receive a functional request packet from the peer.
Definition: dramsim2.cc:380
void recvRespRetry()
Called by the peer if sendTimingResp was called on this protocol (causing recvTimingResp to be called...
Definition: dramsim2.cc:393
bool recvTimingReq(PacketPtr pkt)
Receive a timing request from the peer.
Definition: dramsim2.cc:386
AddrRangeList getAddrRanges() const
Get a list of the non-overlapping address ranges the owner is responsible for.
Definition: dramsim2.cc:366
DRAMSim2Wrapper wrapper
The actual DRAMSim2 wrapper.
Definition: dramsim2.hh:98
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: dramsim2.cc:343
bool retryResp
Are we waiting for a retry for sending a response.
Definition: dramsim2.hh:108
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: dramsim2.cc:81
DRAMSim2Params Params
Definition: dramsim2.hh:175
void accessAndRespond(PacketPtr pkt)
When a packet is ready, use the "access()" method in AbstractMemory to actually create the response p...
Definition: dramsim2.cc:254
EventFunctionWrapper tickEvent
Event to schedule clock ticks.
Definition: dramsim2.hh:165
unsigned int nbrOutstanding() const
Definition: dramsim2.cc:136
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:171
void writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
Write completion callback.
Definition: dramsim2.cc:318
bool retryReq
Is the connected port waiting for a retry from us.
Definition: dramsim2.hh:103
std::unordered_map< Addr, std::queue< PacketPtr > > outstandingWrites
Definition: dramsim2.hh:122
bool recvTimingReq(PacketPtr pkt)
Definition: dramsim2.cc:181
Tick startTick
Keep track of when the wrapper is started.
Definition: dramsim2.hh:113
unsigned int nbrOutstandingReads
Count the number of outstanding transactions so that we can block any further requests until there is...
Definition: dramsim2.hh:129
Tick recvAtomic(PacketPtr pkt)
Definition: dramsim2.cc:158
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:121
void startup() override
startup() is the final initialization call before simulation.
Definition: dramsim2.cc:97
void recvFunctional(PacketPtr pkt)
Definition: dramsim2.cc:167
DRAMSim2(const Params &p)
Definition: dramsim2.cc:53
EventFunctionWrapper sendResponseEvent
Event to schedule sending of responses.
Definition: dramsim2.hh:155
void readComplete(unsigned id, uint64_t addr, uint64_t cycle)
Read completion callback.
Definition: dramsim2.cc:290
unsigned int nbrOutstandingWrites
Definition: dramsim2.hh:130
std::deque< PacketPtr > responseQueue
Queue to hold response packets until we can send them back.
Definition: dramsim2.hh:137
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
Definition: dramsim2.cc:353
void tick()
Progress the controller one clock cycle.
Definition: dramsim2.cc:142
DRAMSim2.
static constexpr T divCeil(const T &a, const U &b)
Definition: intmath.hh:110
void signalDrainDone() const
Signal that an object is drained.
Definition: drain.hh:305
DrainState
Object drain/handover states.
Definition: drain.hh:75
@ Draining
Draining buffers pending serialization/handover.
@ Drained
Buffers drained, ready for serialization/handover.
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:465
void schedule(Event &event, Tick when)
Definition: eventq.hh:1019
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
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
virtual void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: sim_object.cc:76
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 3 > addr
Definition: types.hh:84
Tick ns
nanosecond
Definition: core.cc:71
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:245
uint64_t Tick
Tick count type.
Definition: types.hh:58
void registerExitCallback(const std::function< void()> &callback)
Register an exit callback.
Definition: core.cc:146
Definition: mem.h:38
bool_vector8 mem[]
Definition: reset_stim.h:43
const std::string & name()
Definition: trace.cc:49

Generated on Wed Dec 21 2022 10:22:37 for gem5 by doxygen 1.9.1