gem5 v24.0.0.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),
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>(
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 {
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",
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
149 retryReq = false;
151 }
152
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
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,
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,
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
360DRAMSim2::MemoryPort::MemoryPort(const std::string& _name,
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:210
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:295
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
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:349
bool sendTimingResp(PacketPtr pkt)
Attempt to send a timing response to the request port by calling its corresponding receive function.
Definition port.hh:454
void sendRangeChange() const
Called by the owner to send a range change.
Definition port.hh:380
void sendRetryReq()
Send a retry to the request port that previously attempted a sendTimingReq to this response port and ...
Definition port.hh:489
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.
uint64_t size() const
Get the memory size.
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
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:458
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
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 - Pranith Kumar Copyright (c) 2020 Inria 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
void registerExitCallback(const std::function< void()> &callback)
Register an exit callback.
Definition core.cc:143
Definition mem.h:38
bool_vector8 mem[]
Definition reset_stim.h:43
const std::string & name()
Definition trace.cc:48

Generated on Tue Jun 18 2024 16:24:05 for gem5 by doxygen 1.11.0