gem5  v22.1.0.0
dramsim3.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/dramsim3.hh"
39 
40 #include "base/callback.hh"
41 #include "base/trace.hh"
42 #include "debug/DRAMsim3.hh"
43 #include "debug/Drain.hh"
44 #include "sim/system.hh"
45 
46 namespace gem5
47 {
48 
49 namespace memory
50 {
51 
54  port(name() + ".port", *this),
55  read_cb(std::bind(&DRAMsim3::readComplete,
56  this, 0, std::placeholders::_1)),
57  write_cb(std::bind(&DRAMsim3::writeComplete,
58  this, 0, std::placeholders::_1)),
59  wrapper(p.configFile, p.filePath, read_cb, write_cb),
60  retryReq(false), retryResp(false), startTick(0),
61  nbrOutstandingReads(0), nbrOutstandingWrites(0),
62  sendResponseEvent([this]{ sendResponse(); }, name()),
63  tickEvent([this]{ tick(); }, name())
64 {
65  DPRINTF(DRAMsim3,
66  "Instantiated DRAMsim3 with clock %d ns and queue size %d\n",
67  wrapper.clockPeriod(), wrapper.queueSize());
68 
69  // Register a callback to compensate for the destructor not
70  // being called. The callback prints the DRAMsim3 stats.
71  registerExitCallback([this]() { wrapper.printStats(); });
72 }
73 
74 void
76 {
78 
79  if (!port.isConnected()) {
80  fatal("DRAMsim3 %s is unconnected!\n", name());
81  } else {
83  }
84 
85  if (system()->cacheLineSize() != wrapper.burstSize())
86  fatal("DRAMsim3 burst size %d does not match cache line size %d\n",
87  wrapper.burstSize(), system()->cacheLineSize());
88 }
89 
90 void
92 {
93  startTick = curTick();
94 
95  // kick off the clock ticks
97 }
98 
99 void
102 }
103 
104 void
106 {
107  assert(!retryResp);
108  assert(!responseQueue.empty());
109 
110  DPRINTF(DRAMsim3, "Attempting to send response\n");
111 
112  bool success = port.sendTimingResp(responseQueue.front());
113  if (success) {
114  responseQueue.pop_front();
115 
116  DPRINTF(DRAMsim3, "Have %d read, %d write, %d responses outstanding\n",
118  responseQueue.size());
119 
120  if (!responseQueue.empty() && !sendResponseEvent.scheduled())
122 
123  if (nbrOutstanding() == 0)
124  signalDrainDone();
125  } else {
126  retryResp = true;
127 
128  DPRINTF(DRAMsim3, "Waiting for response retry\n");
129 
130  assert(!sendResponseEvent.scheduled());
131  }
132 }
133 
134 unsigned int
136 {
138 }
139 
140 void
142 {
143  // Only tick when it's timing mode
144  if (system()->isTimingMode()) {
145  wrapper.tick();
146 
147  // is the connected port waiting for a retry, if so check the
148  // state and send a retry if conditions have changed
149  if (retryReq && nbrOutstanding() < wrapper.queueSize()) {
150  retryReq = false;
151  port.sendRetryReq();
152  }
153  }
154 
157 }
158 
159 Tick
161 {
162  access(pkt);
163 
164  // 50 ns is just an arbitrary value at this point
165  return pkt->cacheResponding() ? 0 : 50000;
166 }
167 
168 void
170 {
171  pkt->pushLabel(name());
172 
173  functionalAccess(pkt);
174 
175  // potentially update the packets in our response queue as well
176  for (auto i = responseQueue.begin(); i != responseQueue.end(); ++i)
177  pkt->trySatisfyFunctional(*i);
178 
179  pkt->popLabel();
180 }
181 
182 bool
184 {
185  // if a cache is responding, sink the packet without further action
186  if (pkt->cacheResponding()) {
187  pendingDelete.reset(pkt);
188  return true;
189  }
190 
191  // we should not get a new request after committing to retry the
192  // current one, but unfortunately the CPU violates this rule, so
193  // simply ignore it for now
194  if (retryReq)
195  return false;
196 
197  // if we cannot accept we need to send a retry once progress can
198  // be made
199  bool can_accept = nbrOutstanding() < wrapper.queueSize();
200 
201  // keep track of the transaction
202  if (pkt->isRead()) {
203  if (can_accept) {
204  outstandingReads[pkt->getAddr()].push(pkt);
205 
206  // we count a transaction as outstanding until it has left the
207  // queue in the controller, and the response has been sent
208  // back, note that this will differ for reads and writes
210  }
211  } else if (pkt->isWrite()) {
212  if (can_accept) {
213  outstandingWrites[pkt->getAddr()].push(pkt);
214 
216 
217  // perform the access for writes
218  accessAndRespond(pkt);
219  }
220  } else {
221  // keep it simple and just respond if necessary
222  accessAndRespond(pkt);
223  return true;
224  }
225 
226  if (can_accept) {
227  // we should never have a situation when we think there is space,
228  // and there isn't
229  assert(wrapper.canAccept(pkt->getAddr(), pkt->isWrite()));
230 
231  DPRINTF(DRAMsim3, "Enqueueing address %lld\n", pkt->getAddr());
232 
233  // @todo what about the granularity here, implicit assumption that
234  // a transaction matches the burst size of the memory (which we
235  // cannot determine without parsing the ini file ourselves)
236  wrapper.enqueue(pkt->getAddr(), pkt->isWrite());
237 
238  return true;
239  } else {
240  retryReq = true;
241  return false;
242  }
243 }
244 
245 void
247 {
248  DPRINTF(DRAMsim3, "Retrying\n");
249 
250  assert(retryResp);
251  retryResp = false;
252  sendResponse();
253 }
254 
255 void
257 {
258  DPRINTF(DRAMsim3, "Access for address %lld\n", pkt->getAddr());
259 
260  bool needsResponse = pkt->needsResponse();
261 
262  // do the actual memory access which also turns the packet into a
263  // response
264  access(pkt);
265 
266  // turn packet around to go back to requestor if response expected
267  if (needsResponse) {
268  // access already turned the packet into a response
269  assert(pkt->isResponse());
270  // Here we pay for xbar additional delay and to process the payload
271  // of the packet.
272  Tick time = curTick() + pkt->headerDelay + pkt->payloadDelay;
273  // Reset the timings of the packet
274  pkt->headerDelay = pkt->payloadDelay = 0;
275 
276  DPRINTF(DRAMsim3, "Queuing response for address %lld\n",
277  pkt->getAddr());
278 
279  // queue it to be sent back
280  responseQueue.push_back(pkt);
281 
282  // if we are not already waiting for a retry, or are scheduled
283  // to send a response, schedule an event
286  } else {
287  // queue the packet for deletion
288  pendingDelete.reset(pkt);
289  }
290 }
291 
292 void DRAMsim3::readComplete(unsigned id, uint64_t addr)
293 {
294 
295  DPRINTF(DRAMsim3, "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 DRAMsim3::writeComplete(unsigned id, uint64_t addr)
319 {
320 
321  DPRINTF(DRAMsim3, "Write to address %lld complete\n", addr);
322 
323  // get the outstanding reads for the address in question
324  auto p = outstandingWrites.find(addr);
325  assert(p != outstandingWrites.end());
326 
327  // we have already responded, and this is only to keep track of
328  // what is outstanding
329  p->second.pop();
330  if (p->second.empty())
331  outstandingWrites.erase(p);
332 
333  assert(nbrOutstandingWrites != 0);
335 
336  if (nbrOutstanding() == 0)
337  signalDrainDone();
338 }
339 
340 Port&
341 DRAMsim3::getPort(const std::string &if_name, PortID idx)
342 {
343  if (if_name != "port") {
344  return ClockedObject::getPort(if_name, idx);
345  } else {
346  return port;
347  }
348 }
349 
352 {
353  // check our outstanding reads and writes and if any they need to
354  // drain
356 }
357 
358 DRAMsim3::MemoryPort::MemoryPort(const std::string& _name,
359  DRAMsim3& _memory)
360  : ResponsePort(_name, &_memory), mem(_memory)
361 { }
362 
365 {
366  AddrRangeList ranges;
367  ranges.push_back(mem.getAddrRange());
368  return ranges;
369 }
370 
371 Tick
373 {
374  return mem.recvAtomic(pkt);
375 }
376 
377 void
379 {
380  mem.recvFunctional(pkt);
381 }
382 
383 bool
385 {
386  // pass it to the memory controller
387  return mem.recvTimingReq(pkt);
388 }
389 
390 void
392 {
393  mem.recvRespRetry();
394 }
395 
396 } // namespace memory
397 } // 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.
unsigned int burstSize() const
Get the burst size in bytes used by DRAMsim3.
void tick()
Progress the memory controller one cycle.
void enqueue(uint64_t addr, bool is_write)
Enqueue a packet.
unsigned int queueSize() const
Get the transaction queue size used by DRAMsim3.
void resetStats()
Reset stats (useful for fastforwarding switch)
double clockPeriod() const
Get the internal clock period used by DRAMsim3, specified in ns.
bool canAccept(uint64_t addr, bool is_write) const
Determine if the controller can accept a new packet or not.
void recvRespRetry()
Called by the peer if sendTimingResp was called on this protocol (causing recvTimingResp to be called...
Definition: dramsim3.cc:391
MemoryPort(const std::string &_name, DRAMsim3 &_memory)
Definition: dramsim3.cc:358
void recvFunctional(PacketPtr pkt)
Receive a functional request packet from the peer.
Definition: dramsim3.cc:378
Tick recvAtomic(PacketPtr pkt)
Receive an atomic request packet from the peer.
Definition: dramsim3.cc:372
AddrRangeList getAddrRanges() const
Get a list of the non-overlapping address ranges the owner is responsible for.
Definition: dramsim3.cc:364
bool recvTimingReq(PacketPtr pkt)
Receive a timing request from the peer.
Definition: dramsim3.cc:384
Tick startTick
Keep track of when the wrapper is started.
Definition: dramsim3.hh:121
EventFunctionWrapper tickEvent
Event to schedule clock ticks.
Definition: dramsim3.hh:174
DRAMsim3Params Params
Definition: dramsim3.hh:184
bool recvTimingReq(PacketPtr pkt)
Definition: dramsim3.cc:183
void recvFunctional(PacketPtr pkt)
Definition: dramsim3.cc:169
void accessAndRespond(PacketPtr pkt)
When a packet is ready, use the "access()" method in AbstractMemory to actually create the response p...
Definition: dramsim3.cc:256
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: dramsim3.cc:75
void tick()
Progress the controller one clock cycle.
Definition: dramsim3.cc:141
std::deque< PacketPtr > responseQueue
Queue to hold response packets until we can send them back.
Definition: dramsim3.hh:145
void startup() override
startup() is the final initialization call before simulation.
Definition: dramsim3.cc:91
void resetStats() override
Callback to reset stats.
Definition: dramsim3.cc:100
Tick recvAtomic(PacketPtr pkt)
Definition: dramsim3.cc:160
std::unordered_map< Addr, std::queue< PacketPtr > > outstandingWrites
Definition: dramsim3.hh:130
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
Definition: dramsim3.cc:351
bool retryReq
Is the connected port waiting for a retry from us.
Definition: dramsim3.hh:111
DRAMsim3Wrapper wrapper
The actual DRAMsim3 wrapper.
Definition: dramsim3.hh:106
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: dramsim3.cc:341
void readComplete(unsigned id, uint64_t addr)
Read completion callback.
Definition: dramsim3.cc:292
EventFunctionWrapper sendResponseEvent
Event to schedule sending of responses.
Definition: dramsim3.hh:164
bool retryResp
Are we waiting for a retry for sending a response.
Definition: dramsim3.hh:116
std::unique_ptr< Packet > pendingDelete
Upstream caches need this packet until true is returned, so hold it for deletion until a subsequent c...
Definition: dramsim3.hh:180
unsigned int nbrOutstandingWrites
Definition: dramsim3.hh:138
unsigned int nbrOutstanding() const
Definition: dramsim3.cc:135
DRAMsim3(const Params &p)
Definition: dramsim3.cc:52
unsigned int nbrOutstandingReads
Count the number of outstanding transactions so that we can block any further requests until there is...
Definition: dramsim3.hh:137
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: dramsim3.hh:129
void writeComplete(unsigned id, uint64_t addr)
Write completion callback.
Definition: dramsim3.cc:318
DRAMsim3.
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
Overload hash function for BasicBlockRange type.
Definition: misc.hh:2826
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