gem5 [DEVELOP-FOR-25.0]
Loading...
Searching...
No Matches
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
47namespace gem5
48{
49
50namespace 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),
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>(
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
80void
82{
84
85 if (!port.isConnected()) {
86 fatal("DRAMSim2 %s is unconnected!\n", name());
87 } else {
88 port.sendRangeChange();
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
96void
98{
100
101 // kick off the clock ticks
103}
104
105void
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)
126 } else {
127 retryResp = true;
128
129 DPRINTF(DRAMSim2, "Waiting for response retry\n");
130
131 assert(!sendResponseEvent.scheduled());
132 }
133}
134
135unsigned int
140
141void
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
154 curTick() + wrapper.clockPeriod() * sim_clock::as_int::ns);
155}
156
157Tick
159{
160 access(pkt);
161
162 // 50 ns is just an arbitrary value at this point
163 return pkt->cacheResponding() ? 0 : 50000;
164}
165
166void
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
180bool
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
243void
245{
246 DPRINTF(DRAMSim2, "Retrying\n");
247
248 assert(retryResp);
249 retryResp = false;
250 sendResponse();
251}
252
253void
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
282 if (!retryResp && !sendResponseEvent.scheduled())
284 } else {
285 // queue the packet for deletion
286 pendingDelete.reset(pkt);
287 }
288}
289
290void DRAMSim2::readComplete(unsigned id, uint64_t addr, uint64_t cycle)
291{
292 assert(cycle == divCeil(curTick() - startTick,
293 wrapper.clockPeriod() * sim_clock::as_int::ns));
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
318void DRAMSim2::writeComplete(unsigned id, uint64_t addr, uint64_t cycle)
319{
320 assert(cycle == divCeil(curTick() - startTick,
321 wrapper.clockPeriod() * sim_clock::as_int::ns));
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)
340}
341
342Port &
343DRAMSim2::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
361 DRAMSim2& _memory)
362 : ResponsePort(_name), mem(_memory)
363{ }
364
367{
368 AddrRangeList ranges;
369 ranges.push_back(mem.getAddrRange());
370 return ranges;
371}
372
373Tick
375{
376 return mem.recvAtomic(pkt);
377}
378
379void
381{
382 mem.recvFunctional(pkt);
383}
384
385bool
387{
388 // pass it to the memory controller
389 return mem.recvTimingReq(pkt);
390}
391
392void
394{
395 mem.recvRespRetry();
396}
397
398} // namespace memory
399} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
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...
const std::string _name
Definition named.hh:54
virtual std::string name() const
Definition named.hh:60
bool isRead() const
Definition packet.hh:593
Addr getAddr() const
Definition packet.hh:807
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition packet.hh:1470
bool isResponse() const
Definition packet.hh:598
bool needsResponse() const
Definition packet.hh:608
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition packet.hh:449
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition packet.hh:431
bool isWrite() const
Definition packet.hh:594
bool trySatisfyFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
Definition packet.hh:1399
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition packet.hh:1480
bool cacheResponding() const
Definition packet.hh:659
Ports are used to interface objects to each other.
Definition port.hh:62
ResponsePort(const std::string &name, SimObject *_owner, PortID id=InvalidPortID)
Response port.
Definition port.cc:218
void access(PacketPtr pkt)
Perform an untimed memory access and update all the state (e.g.
uint64_t size() const
Get the memory size.
AbstractMemory(const AbstractMemory &)
void functionalAccess(PacketPtr pkt)
Perform an untimed memory read or write without changing anything but the memory itself.
System * system() const
read the system pointer Implemented for completeness with the setter
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.
std::list< AddrRange > AddrRangeList
Convenience typedef for a collection of address ranges.
Definition addr_range.hh:64
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.
Definition drain.hh:77
@ Drained
Buffers drained, ready for serialization/handover.
Definition drain.hh:78
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:232
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
virtual void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition sim_object.cc:73
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 0 > p
Bitfield< 3 > addr
Definition types.hh:84
Tick ns
nanosecond
Definition core.cc:68
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
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
Packet * PacketPtr
void registerExitCallback(const std::function< void()> &callback)
Register an exit callback.
Definition core.cc:143
const std::string & name()
Definition trace.cc:48

Generated on Mon May 26 2025 09:19:11 for gem5 by doxygen 1.13.2