gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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  * Authors: Ron Dreslinski
41  * Ali Saidi
42  * Andreas Hansson
43  */
44 
45 #include "mem/simple_mem.hh"
46 
47 #include "base/random.hh"
48 #include "base/trace.hh"
49 #include "debug/Drain.hh"
50 
51 using namespace std;
52 
53 SimpleMemory::SimpleMemory(const SimpleMemoryParams* p) :
54  AbstractMemory(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), dequeueEvent(this)
59 {
60 }
61 
62 void
64 {
66 
67  // allow unconnected memories as this is used in several ruby
68  // systems at the moment
69  if (port.isConnected()) {
71  }
72 }
73 
74 Tick
76 {
77  panic_if(pkt->cacheResponding(), "Should not see packets where cache "
78  "is responding");
79 
80  access(pkt);
81  return getLatency();
82 }
83 
84 void
86 {
87  pkt->pushLabel(name());
88 
89  functionalAccess(pkt);
90 
91  bool done = false;
92  auto p = packetQueue.begin();
93  // potentially update the packets in our packet queue as well
94  while (!done && p != packetQueue.end()) {
95  done = pkt->checkFunctional(p->pkt);
96  ++p;
97  }
98 
99  pkt->popLabel();
100 }
101 
102 bool
104 {
105  panic_if(pkt->cacheResponding(), "Should not see packets where cache "
106  "is responding");
107 
108  panic_if(!(pkt->isRead() || pkt->isWrite()),
109  "Should only see read and writes at memory controller, "
110  "saw %s to %#llx\n", pkt->cmdString(), pkt->getAddr());
111 
112  // we should not get a new request after committing to retry the
113  // current one, but unfortunately the CPU violates this rule, so
114  // simply ignore it for now
115  if (retryReq)
116  return false;
117 
118  // if we are busy with a read or write, remember that we have to
119  // retry
120  if (isBusy) {
121  retryReq = true;
122  return false;
123  }
124 
125  // technically the packet only reaches us after the header delay,
126  // and since this is a memory controller we also need to
127  // deserialise the payload before performing any write operation
128  Tick receive_delay = pkt->headerDelay + pkt->payloadDelay;
129  pkt->headerDelay = pkt->payloadDelay = 0;
130 
131  // update the release time according to the bandwidth limit, and
132  // do so with respect to the time it takes to finish this request
133  // rather than long term as it is the short term data rate that is
134  // limited for any real memory
135 
136  // calculate an appropriate tick to release to not exceed
137  // the bandwidth limit
138  Tick duration = pkt->getSize() * bandwidth;
139 
140  // only consider ourselves busy if there is any need to wait
141  // to avoid extra events being scheduled for (infinitely) fast
142  // memories
143  if (duration != 0) {
144  schedule(releaseEvent, curTick() + duration);
145  isBusy = true;
146  }
147 
148  // go ahead and deal with the packet and put the response in the
149  // queue if there is one
150  bool needsResponse = pkt->needsResponse();
151  recvAtomic(pkt);
152  // turn packet around to go back to requester if response expected
153  if (needsResponse) {
154  // recvAtomic() should already have turned packet into
155  // atomic response
156  assert(pkt->isResponse());
157 
158  Tick when_to_send = curTick() + receive_delay + getLatency();
159 
160  // typically this should be added at the end, so start the
161  // insertion sort with the last element, also make sure not to
162  // re-order in front of some existing packet with the same
163  // address, the latter is important as this memory effectively
164  // hands out exclusive copies (shared is not asserted)
165  auto i = packetQueue.end();
166  --i;
167  while (i != packetQueue.begin() && when_to_send < i->tick &&
168  i->pkt->getAddr() != pkt->getAddr())
169  --i;
170 
171  // emplace inserts the element before the position pointed to by
172  // the iterator, so advance it one step
173  packetQueue.emplace(++i, pkt, when_to_send);
174 
175  if (!retryResp && !dequeueEvent.scheduled())
176  schedule(dequeueEvent, packetQueue.back().tick);
177  } else {
178  pendingDelete.reset(pkt);
179  }
180 
181  return true;
182 }
183 
184 void
186 {
187  assert(isBusy);
188  isBusy = false;
189  if (retryReq) {
190  retryReq = false;
191  port.sendRetryReq();
192  }
193 }
194 
195 void
197 {
198  assert(!packetQueue.empty());
199  DeferredPacket deferred_pkt = packetQueue.front();
200 
201  retryResp = !port.sendTimingResp(deferred_pkt.pkt);
202 
203  if (!retryResp) {
204  packetQueue.pop_front();
205 
206  // if the queue is not empty, schedule the next dequeue event,
207  // otherwise signal that we are drained if we were asked to do so
208  if (!packetQueue.empty()) {
209  // if there were packets that got in-between then we
210  // already have an event scheduled, so use re-schedule
212  std::max(packetQueue.front().tick, curTick()), true);
213  } else if (drainState() == DrainState::Draining) {
214  DPRINTF(Drain, "Draining of SimpleMemory complete\n");
215  signalDrainDone();
216  }
217  }
218 }
219 
220 Tick
222 {
223  return latency +
225 }
226 
227 void
229 {
230  assert(retryResp);
231 
232  dequeue();
233 }
234 
236 SimpleMemory::getSlavePort(const std::string &if_name, PortID idx)
237 {
238  if (if_name != "port") {
239  return MemObject::getSlavePort(if_name, idx);
240  } else {
241  return port;
242  }
243 }
244 
247 {
248  if (!packetQueue.empty()) {
249  DPRINTF(Drain, "SimpleMemory Queue has requests, waiting to drain\n");
250  return DrainState::Draining;
251  } else {
252  return DrainState::Drained;
253  }
254 }
255 
256 SimpleMemory::MemoryPort::MemoryPort(const std::string& _name,
257  SimpleMemory& _memory)
258  : SlavePort(_name, &_memory), memory(_memory)
259 { }
260 
263 {
264  AddrRangeList ranges;
265  ranges.push_back(memory.getAddrRange());
266  return ranges;
267 }
268 
269 Tick
271 {
272  return memory.recvAtomic(pkt);
273 }
274 
275 void
277 {
278  memory.recvFunctional(pkt);
279 }
280 
281 bool
283 {
284  return memory.recvTimingReq(pkt);
285 }
286 
287 void
289 {
290  memory.recvRespRetry();
291 }
292 
294 SimpleMemoryParams::create()
295 {
296  return new SimpleMemory(this);
297 }
EventWrapper< SimpleMemory,&SimpleMemory::dequeue > dequeueEvent
Definition: simple_mem.hh:169
#define DPRINTF(x,...)
Definition: trace.hh:212
void functionalAccess(PacketPtr pkt)
Perform an untimed memory read or write without changing anything but the memory itself.
bool isBusy
Track the state of the memory as either idle or busy, no need for an enum with only two states...
Definition: simple_mem.hh:141
const std::string & name()
Definition: trace.cc:49
Bitfield< 7 > i
Definition: miscregs.hh:1378
DrainState
Object drain/handover states.
Definition: drain.hh:71
Running normally.
EventWrapper< SimpleMemory,&SimpleMemory::release > releaseEvent
Definition: simple_mem.hh:161
BaseSlavePort & getSlavePort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a slave port with a given name and index.
Definition: simple_mem.cc:236
bool isWrite() const
Definition: packet.hh:503
panic_if(!root,"Invalid expression\n")
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:381
MemoryPort port
Definition: simple_mem.hh:110
std::unique_ptr< Packet > pendingDelete
Upstream caches need this packet until true is returned, so hold it for deletion until a subsequent c...
Definition: simple_mem.hh:182
A SlavePort is a specialisation of a port.
Definition: port.hh:331
virtual BaseSlavePort & getSlavePort(const std::string &if_name, PortID idx=InvalidPortID)
Get a slave port with a given name and index.
Definition: mem_object.cc:58
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1160
A BaseSlavePort is a protocol-agnostic slave port, responsible only for the structural connection to ...
Definition: port.hh:139
SimpleMemory declaration.
std::enable_if< std::is_integral< T >::value, T >::type random()
Use the SFINAE idiom to choose an implementation based on whether the type is integral or floating po...
Definition: random.hh:83
A deferred packet stores a packet along with its scheduled transmission time.
Definition: simple_mem.hh:73
const Tick latency_var
Fudge factor added to the latency.
Definition: simple_mem.hh:121
bool recvTimingReq(PacketPtr pkt)
Definition: simple_mem.cc:103
bool retryResp
Remember if we failed to send a response and are awaiting a retry.
Definition: simple_mem.hh:153
bool retryReq
Remember if we have to retry an outstanding request that arrived while we were busy.
Definition: simple_mem.hh:147
bool sendTimingResp(PacketPtr pkt)
Attempt to send a timing response to the master port by calling its corresponding receive function...
Definition: port.cc:251
Tick curTick()
The current simulated tick.
Definition: core.hh:47
void init() override
Initialise this memory.
Definition: simple_mem.cc:63
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition: packet.hh:340
The simple memory is a basic single-ported memory controller with a configurable throughput and laten...
Definition: simple_mem.hh:64
uint64_t Tick
Tick count type.
Definition: types.hh:63
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition: packet.hh:1170
Tick getLatency() const
Detemine the latency.
Definition: simple_mem.cc:221
void access(PacketPtr pkt)
Perform an untimed memory access and update all the state (e.g.
const double bandwidth
Bandwidth in ticks per byte.
Definition: simple_mem.hh:135
void release()
Release the memory after being busy and send a retry if a request was rejected in the meanwhile...
Definition: simple_mem.cc:185
bool needsResponse() const
Definition: packet.hh:516
AddrRangeList getAddrRanges() const
Get a list of the non-overlapping address ranges the owner is responsible for.
Definition: simple_mem.cc:262
SimpleMemory(const SimpleMemoryParams *p)
Definition: simple_mem.cc:53
bool isRead() const
Definition: packet.hh:502
std::list< DeferredPacket > packetQueue
Internal (unbounded) storage to mimic the delay caused by the actual memory access.
Definition: simple_mem.hh:128
bool cacheResponding() const
Definition: packet.hh:558
Draining buffers pending serialization/handover.
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition: packet.hh:358
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:245
void recvRespRetry()
Definition: simple_mem.cc:228
void recvFunctional(PacketPtr pkt)
Definition: simple_mem.cc:85
void sendRangeChange() const
Called by the owner to send a range change.
Definition: port.hh:410
bool checkFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
Definition: packet.hh:1115
Tick recvAtomic(PacketPtr pkt)
Receive an atomic request packet from the master port.
Definition: simple_mem.cc:270
void recvFunctional(PacketPtr pkt)
Receive a functional request packet from the master port.
Definition: simple_mem.cc:276
Tick recvAtomic(PacketPtr pkt)
Definition: simple_mem.cc:75
MemoryPort(const std::string &_name, SimpleMemory &_memory)
Definition: simple_mem.cc:256
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:740
void init() override
Initialise this memory.
Definition: abstract_mem.cc:66
virtual const std::string name() const
Definition: sim_object.hh:117
void sendRetryReq()
Send a retry to the master port that previously attempted a sendTimingReq to this slave port and fail...
Definition: port.cc:265
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
Definition: packet.hh:497
void recvRespRetry()
Called by the master port if sendTimingResp was called on this slave port (causing recvTimingResp to ...
Definition: simple_mem.cc:288
bool isConnected() const
Definition: port.cc:110
Random random_mt
Definition: random.cc:100
void signalDrainDone() const
Signal that an object is drained.
Definition: drain.hh:267
void schedule(Event &event, Tick when)
Definition: eventq.hh:728
DrainState drain() override
Notify an object that it needs to drain its state.
Definition: simple_mem.cc:246
An abstract memory represents a contiguous block of physical memory, with an associated address range...
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:282
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:181
const Tick latency
Latency from that a request is accepted until the response is ready to be sent.
Definition: simple_mem.hh:116
bool recvTimingReq(PacketPtr pkt)
Receive a timing request from the master port.
Definition: simple_mem.cc:282
unsigned getSize() const
Definition: packet.hh:649
Bitfield< 0 > p
void dequeue()
Dequeue a packet from our internal packet queue and move it to the port where it will be sent as soon...
Definition: simple_mem.cc:196
bool isResponse() const
Definition: packet.hh:506
Addr getAddr() const
Definition: packet.hh:639

Generated on Fri Jun 9 2017 13:03:50 for gem5 by doxygen 1.8.6