gem5 v24.0.0.0
Loading...
Searching...
No Matches
simple_mem.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010-2013, 2015 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 * Copyright (c) 2001-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
40
41#include "mem/simple_mem.hh"
42
43#include "base/random.hh"
44#include "base/trace.hh"
45#include "debug/Drain.hh"
46
47namespace gem5
48{
49
50namespace memory
51{
52
53SimpleMemory::SimpleMemory(const SimpleMemoryParams &p) :
55 port(name() + ".port", *this), latency(p.latency),
56 latency_var(p.latency_var), bandwidth(p.bandwidth), isBusy(false),
57 retryReq(false), retryResp(false),
58 releaseEvent([this]{ release(); }, name()),
59 dequeueEvent([this]{ dequeue(); }, name())
60{
61}
62
63void
65{
67
68 // allow unconnected memories as this is used in several ruby
69 // systems at the moment
70 if (port.isConnected()) {
72 }
73}
74
75Tick
77{
78 panic_if(pkt->cacheResponding(), "Should not see packets where cache "
79 "is responding");
80
81 access(pkt);
82 return getLatency();
83}
84
85Tick
87{
88 Tick latency = recvAtomic(pkt);
89 getBackdoor(_backdoor);
90 return latency;
91}
92
93void
95{
96 pkt->pushLabel(name());
97
99
100 bool done = false;
101 auto p = packetQueue.begin();
102 // potentially update the packets in our packet queue as well
103 while (!done && p != packetQueue.end()) {
104 done = pkt->trySatisfyFunctional(p->pkt);
105 ++p;
106 }
107
108 pkt->popLabel();
109}
110
111void
113 MemBackdoorPtr &_backdoor)
114{
115 getBackdoor(_backdoor);
116}
117
118bool
120{
121 panic_if(pkt->cacheResponding(), "Should not see packets where cache "
122 "is responding");
123
124 panic_if(!(pkt->isRead() || pkt->isWrite()),
125 "Should only see read and writes at memory controller, "
126 "saw %s to %#llx\n", pkt->cmdString(), pkt->getAddr());
127
128 // we should not get a new request after committing to retry the
129 // current one, but unfortunately the CPU violates this rule, so
130 // simply ignore it for now
131 if (retryReq)
132 return false;
133
134 // if we are busy with a read or write, remember that we have to
135 // retry
136 if (isBusy) {
137 retryReq = true;
138 return false;
139 }
140
141 // technically the packet only reaches us after the header delay,
142 // and since this is a memory controller we also need to
143 // deserialise the payload before performing any write operation
144 Tick receive_delay = pkt->headerDelay + pkt->payloadDelay;
145 pkt->headerDelay = pkt->payloadDelay = 0;
146
147 // update the release time according to the bandwidth limit, and
148 // do so with respect to the time it takes to finish this request
149 // rather than long term as it is the short term data rate that is
150 // limited for any real memory
151
152 // calculate an appropriate tick to release to not exceed
153 // the bandwidth limit
154 Tick duration = pkt->getSize() * bandwidth;
155
156 // only consider ourselves busy if there is any need to wait
157 // to avoid extra events being scheduled for (infinitely) fast
158 // memories
159 if (duration != 0) {
160 schedule(releaseEvent, curTick() + duration);
161 isBusy = true;
162 }
163
164 // go ahead and deal with the packet and put the response in the
165 // queue if there is one
166 bool needsResponse = pkt->needsResponse();
167 recvAtomic(pkt);
168 // turn packet around to go back to requestor if response expected
169 if (needsResponse) {
170 // recvAtomic() should already have turned packet into
171 // atomic response
172 assert(pkt->isResponse());
173
174 Tick when_to_send = curTick() + receive_delay + getLatency();
175
176 // typically this should be added at the end, so start the
177 // insertion sort with the last element, also make sure not to
178 // re-order in front of some existing packet with the same
179 // address, the latter is important as this memory effectively
180 // hands out exclusive copies (shared is not asserted)
181 auto i = packetQueue.end();
182 --i;
183 while (i != packetQueue.begin() && when_to_send < i->tick &&
184 !i->pkt->matchAddr(pkt))
185 --i;
186
187 // emplace inserts the element before the position pointed to by
188 // the iterator, so advance it one step
189 packetQueue.emplace(++i, pkt, when_to_send);
190
192 schedule(dequeueEvent, packetQueue.back().tick);
193 } else {
194 pendingDelete.reset(pkt);
195 }
196
197 return true;
198}
199
200void
202{
203 assert(isBusy);
204 isBusy = false;
205 if (retryReq) {
206 retryReq = false;
208 }
209}
210
211void
213{
214 assert(!packetQueue.empty());
215 DeferredPacket deferred_pkt = packetQueue.front();
216
217 retryResp = !port.sendTimingResp(deferred_pkt.pkt);
218
219 if (!retryResp) {
220 packetQueue.pop_front();
221
222 // if the queue is not empty, schedule the next dequeue event,
223 // otherwise signal that we are drained if we were asked to do so
224 if (!packetQueue.empty()) {
225 // if there were packets that got in-between then we
226 // already have an event scheduled, so use re-schedule
228 std::max(packetQueue.front().tick, curTick()), true);
229 } else if (drainState() == DrainState::Draining) {
230 DPRINTF(Drain, "Draining of SimpleMemory complete\n");
232 }
233 }
234}
235
236Tick
238{
239 return latency +
241}
242
243void
245{
246 assert(retryResp);
247
248 dequeue();
249}
250
251Port &
252SimpleMemory::getPort(const std::string &if_name, PortID idx)
253{
254 if (if_name != "port") {
255 return AbstractMemory::getPort(if_name, idx);
256 } else {
257 return port;
258 }
259}
260
263{
264 if (!packetQueue.empty()) {
265 DPRINTF(Drain, "SimpleMemory Queue has requests, waiting to drain\n");
267 } else {
268 return DrainState::Drained;
269 }
270}
271
273 SimpleMemory& _memory)
274 : ResponsePort(_name), mem(_memory)
275{ }
276
279{
280 AddrRangeList ranges;
281 ranges.push_back(mem.getAddrRange());
282 return ranges;
283}
284
285Tick
287{
288 return mem.recvAtomic(pkt);
289}
290
291Tick
293 PacketPtr pkt, MemBackdoorPtr &_backdoor)
294{
295 return mem.recvAtomicBackdoor(pkt, _backdoor);
296}
297
298void
300{
301 mem.recvFunctional(pkt);
302}
303
304void
307{
308 mem.recvMemBackdoorReq(req, backdoor);
309}
310
311bool
313{
314 return mem.recvTimingReq(pkt);
315}
316
317void
319{
320 mem.recvRespRetry();
321}
322
323} // namespace memory
324} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
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
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
Definition packet.hh:588
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
unsigned getSize() const
Definition packet.hh:817
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.
void functionalAccess(PacketPtr pkt)
Perform an untimed memory read or write without changing anything but the memory itself.
void getBackdoor(MemBackdoorPtr &bd_ptr)
A deferred packet stores a packet along with its scheduled transmission time.
Definition simple_mem.hh:77
Tick recvAtomic(PacketPtr pkt) override
Receive an atomic request packet from the peer.
void recvMemBackdoorReq(const MemBackdoorReq &req, MemBackdoorPtr &backdoor) override
Receive a request for a back door to a range of memory.
AddrRangeList getAddrRanges() const override
Get a list of the non-overlapping address ranges the owner is responsible for.
bool recvTimingReq(PacketPtr pkt) override
Receive a timing request from the peer.
void recvRespRetry() override
Called by the peer if sendTimingResp was called on this protocol (causing recvTimingResp to be called...
MemoryPort(const std::string &_name, SimpleMemory &_memory)
Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &_backdoor) override
Receive an atomic request packet from the peer, and optionally provide a backdoor to the data being a...
void recvFunctional(PacketPtr pkt) override
Receive a functional request packet from the peer.
The simple memory is a basic single-ported memory controller with a configurable throughput and laten...
Definition simple_mem.hh:68
void recvFunctional(PacketPtr pkt)
Definition simple_mem.cc:94
void dequeue()
Dequeue a packet from our internal packet queue and move it to the port where it will be sent as soon...
void release()
Release the memory after being busy and send a retry if a request was rejected in the meanwhile.
const Tick latency
Latency from that a request is accepted until the response is ready to be sent.
std::list< DeferredPacket > packetQueue
Internal (unbounded) storage to mimic the delay caused by the actual memory access.
bool retryResp
Remember if we failed to send a response and are awaiting a retry.
Tick getLatency() const
Detemine the latency.
EventFunctionWrapper dequeueEvent
bool retryReq
Remember if we have to retry an outstanding request that arrived while we were busy.
SimpleMemory(const SimpleMemoryParams &p)
Definition simple_mem.cc:53
Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &_backdoor)
Definition simple_mem.cc:86
const double bandwidth
Bandwidth in ticks per byte.
bool recvTimingReq(PacketPtr pkt)
std::unique_ptr< Packet > pendingDelete
Upstream caches need this packet until true is returned, so hold it for deletion until a subsequent c...
Tick recvAtomic(PacketPtr pkt)
Definition simple_mem.cc:76
DrainState drain() override
Provide a default implementation of the drain interface for objects that don't need draining.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition simple_mem.cc:64
void recvMemBackdoorReq(const MemBackdoorReq &req, MemBackdoorPtr &backdoor)
EventFunctionWrapper releaseEvent
bool isBusy
Track the state of the memory as either idle or busy, no need for an enum with only two states.
const Tick latency_var
Fudge factor added to the latency.
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Random random_mt
Definition random.cc:99
std::enable_if_t< std::is_integral_v< T >, T > random()
Use the SFINAE idiom to choose an implementation based on whether the type is integral or floating po...
Definition random.hh:90
void signalDrainDone() const
Signal that an object is drained.
Definition drain.hh:305
DrainState drainState() const
Return the current drain state of an object.
Definition drain.hh:324
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
void reschedule(Event &event, Tick when, bool always=false)
Definition eventq.hh:1030
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
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
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
SimpleMemory declaration.
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