bf64203bf925fe7428e6c0335f499105ae6e3ddc
[gem5.git] / src / mem / bus.hh
1 /*
2 * Copyright (c) 2011 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) 2002-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 * William Wang
44 */
45
46 /**
47 * @file
48 * Declaration of a bus object.
49 */
50
51 #ifndef __MEM_BUS_HH__
52 #define __MEM_BUS_HH__
53
54 #include <list>
55 #include <set>
56 #include <string>
57
58 #include "base/range.hh"
59 #include "base/range_map.hh"
60 #include "base/types.hh"
61 #include "mem/mem_object.hh"
62 #include "mem/packet.hh"
63 #include "mem/port.hh"
64 #include "params/Bus.hh"
65 #include "sim/eventq.hh"
66
67 class Bus : public MemObject
68 {
69 /**
70 * Declaration of the bus slave port type, one will be
71 * instantiated for each of the master interfaces connecting to
72 * the bus.
73 */
74 class BusSlavePort : public SlavePort
75 {
76 private:
77 /** A pointer to the bus to which this port belongs. */
78 Bus *bus;
79
80 public:
81
82 /** Constructor for the BusSlavePort.*/
83 BusSlavePort(const std::string &_name, Bus *_bus, Port::PortId _id)
84 : SlavePort(_name, _bus, _id), bus(_bus)
85 { }
86
87 protected:
88
89 /**
90 * When receiving a timing request, pass it to the bus.
91 */
92 virtual bool recvTiming(PacketPtr pkt)
93 { pkt->setSrc(id); return bus->recvTiming(pkt); }
94
95 /**
96 * When receiving a timing snoop response, pass it to the bus.
97 */
98 virtual bool recvTimingSnoop(PacketPtr pkt)
99 { pkt->setSrc(id); return bus->recvTimingSnoop(pkt); }
100
101 /**
102 * When receiving an atomic request, pass it to the bus.
103 */
104 virtual Tick recvAtomic(PacketPtr pkt)
105 { pkt->setSrc(id); return bus->recvAtomic(pkt); }
106
107 /**
108 * When receiving a functional request, pass it to the bus.
109 */
110 virtual void recvFunctional(PacketPtr pkt)
111 { pkt->setSrc(id); bus->recvFunctional(pkt); }
112
113 /**
114 * When receiving a retry, pass it to the bus.
115 */
116 virtual void recvRetry()
117 { panic("Bus slave ports always succeed and should never retry.\n"); }
118
119 // This should return all the 'owned' addresses that are
120 // downstream from this bus, yes? That is, the union of all
121 // the 'owned' address ranges of all the other interfaces on
122 // this bus...
123 virtual AddrRangeList getAddrRanges()
124 { return bus->getAddrRanges(id); }
125
126 // Ask the bus to ask everyone on the bus what their block size is and
127 // take the max of it. This might need to be changed a bit if we ever
128 // support multiple block sizes.
129 virtual unsigned deviceBlockSize() const
130 { return bus->findBlockSize(id); }
131
132 };
133
134 /**
135 * Declaration of the bus master port type, one will be
136 * instantiated for each of the slave interfaces connecting to the
137 * bus.
138 */
139 class BusMasterPort : public MasterPort
140 {
141 private:
142 /** A pointer to the bus to which this port belongs. */
143 Bus *bus;
144
145 public:
146
147 /** Constructor for the BusMasterPort.*/
148 BusMasterPort(const std::string &_name, Bus *_bus, Port::PortId _id)
149 : MasterPort(_name, _bus, _id), bus(_bus)
150 { }
151
152 /**
153 * Determine if this port should be considered a snooper. This
154 * is determined by the bus.
155 *
156 * @return a boolean that is true if this port is snooping
157 */
158 virtual bool isSnooping() const
159 { return bus->isSnooping(id); }
160
161 protected:
162
163 /**
164 * When receiving a timing response, pass it to the bus.
165 */
166 virtual bool recvTiming(PacketPtr pkt)
167 { pkt->setSrc(id); return bus->recvTiming(pkt); }
168
169 /**
170 * When receiving a timing snoop request, pass it to the bus.
171 */
172 virtual bool recvTimingSnoop(PacketPtr pkt)
173 { pkt->setSrc(id); return bus->recvTimingSnoop(pkt); }
174
175 /**
176 * When receiving an atomic snoop request, pass it to the bus.
177 */
178 virtual Tick recvAtomicSnoop(PacketPtr pkt)
179 { pkt->setSrc(id); return bus->recvAtomicSnoop(pkt); }
180
181 /**
182 * When receiving a functional snoop request, pass it to the bus.
183 */
184 virtual void recvFunctionalSnoop(PacketPtr pkt)
185 { pkt->setSrc(id); bus->recvFunctionalSnoop(pkt); }
186
187 /** When reciving a range change from the peer port (at id),
188 pass it to the bus. */
189 virtual void recvRangeChange()
190 { bus->recvRangeChange(id); }
191
192 /** When reciving a retry from the peer port (at id),
193 pass it to the bus. */
194 virtual void recvRetry()
195 { bus->recvRetry(id); }
196
197 // Ask the bus to ask everyone on the bus what their block size is and
198 // take the max of it. This might need to be changed a bit if we ever
199 // support multiple block sizes.
200 virtual unsigned deviceBlockSize() const
201 { return bus->findBlockSize(id); }
202
203 };
204
205 /** the clock speed for the bus */
206 int clock;
207 /** cycles of overhead per transaction */
208 int headerCycles;
209 /** the width of the bus in bytes */
210 int width;
211 /** the next tick at which the bus will be idle */
212 Tick tickNextIdle;
213
214 Event * drainEvent;
215
216 typedef range_map<Addr,int>::iterator PortIter;
217 range_map<Addr, int> portMap;
218
219 AddrRangeList defaultRange;
220
221 std::vector<SlavePort*> snoopPorts;
222
223 /**
224 * Store the outstanding requests so we can determine which ones
225 * we generated and which ones were merely forwarded. This is used
226 * in the coherent bus when coherency responses come back.
227 */
228 std::set<RequestPtr> outstandingReq;
229
230 /** Function called by the port when the bus is recieving a Timing
231 transaction.*/
232 bool recvTiming(PacketPtr pkt);
233
234 /** Function called by the port when the bus is recieving a timing
235 snoop transaction.*/
236 bool recvTimingSnoop(PacketPtr pkt);
237
238 /**
239 * Forward a timing packet to our snoopers, potentially excluding
240 * one of the connected coherent masters to avoid sending a packet
241 * back to where it came from.
242 *
243 * @param pkt Packet to forward
244 * @param exclude_slave_port_id Id of slave port to exclude
245 */
246 void forwardTiming(PacketPtr pkt, Port::PortId exclude_slave_port_id);
247
248 /**
249 * Determine if the bus is to be considered occupied when being
250 * presented with a packet from a specific port. If so, the port
251 * in question is also added to the retry list.
252 *
253 * @param pkt Incoming packet
254 * @param port Source port on the bus presenting the packet
255 *
256 * @return True if the bus is to be considered occupied
257 */
258 bool isOccupied(PacketPtr pkt, Port* port);
259
260 /**
261 * Deal with a destination port accepting a packet by potentially
262 * removing the source port from the retry list (if retrying) and
263 * occupying the bus accordingly.
264 *
265 * @param busy_time Time to spend as a result of a successful send
266 */
267 void succeededTiming(Tick busy_time);
268
269 /** Function called by the port when the bus is recieving a Atomic
270 transaction.*/
271 Tick recvAtomic(PacketPtr pkt);
272
273 /** Function called by the port when the bus is recieving an
274 atomic snoop transaction.*/
275 Tick recvAtomicSnoop(PacketPtr pkt);
276
277 /**
278 * Forward an atomic packet to our snoopers, potentially excluding
279 * one of the connected coherent masters to avoid sending a packet
280 * back to where it came from.
281 *
282 * @param pkt Packet to forward
283 * @param exclude_slave_port_id Id of slave port to exclude
284 *
285 * @return a pair containing the snoop response and snoop latency
286 */
287 std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
288 Port::PortId exclude_slave_port_id);
289
290 /** Function called by the port when the bus is recieving a Functional
291 transaction.*/
292 void recvFunctional(PacketPtr pkt);
293
294 /** Function called by the port when the bus is recieving a functional
295 snoop transaction.*/
296 void recvFunctionalSnoop(PacketPtr pkt);
297
298 /**
299 * Forward a functional packet to our snoopers, potentially
300 * excluding one of the connected coherent masters to avoid
301 * sending a packet back to where it came from.
302 *
303 * @param pkt Packet to forward
304 * @param exclude_slave_port_id Id of slave port to exclude
305 */
306 void forwardFunctional(PacketPtr pkt, Port::PortId exclude_slave_port_id);
307
308 /** Timing function called by port when it is once again able to process
309 * requests. */
310 void recvRetry(Port::PortId id);
311
312 /** Function called by the port when the bus is recieving a range change.*/
313 void recvRangeChange(Port::PortId id);
314
315 /** Find which port connected to this bus (if any) should be given a packet
316 * with this address.
317 * @param addr Address to find port for.
318 * @return id of port that the packet should be sent out of.
319 */
320 int findPort(Addr addr);
321
322 // Cache for the findPort function storing recently used ports from portMap
323 struct PortCache {
324 bool valid;
325 Port::PortId id;
326 Addr start;
327 Addr end;
328 };
329
330 PortCache portCache[3];
331
332 // Checks the cache and returns the id of the port that has the requested
333 // address within its range
334 inline int checkPortCache(Addr addr) {
335 if (portCache[0].valid && addr >= portCache[0].start &&
336 addr < portCache[0].end) {
337 return portCache[0].id;
338 }
339 if (portCache[1].valid && addr >= portCache[1].start &&
340 addr < portCache[1].end) {
341 return portCache[1].id;
342 }
343 if (portCache[2].valid && addr >= portCache[2].start &&
344 addr < portCache[2].end) {
345 return portCache[2].id;
346 }
347
348 return Port::INVALID_PORT_ID;
349 }
350
351 // Clears the earliest entry of the cache and inserts a new port entry
352 inline void updatePortCache(short id, Addr start, Addr end) {
353 portCache[2].valid = portCache[1].valid;
354 portCache[2].id = portCache[1].id;
355 portCache[2].start = portCache[1].start;
356 portCache[2].end = portCache[1].end;
357
358 portCache[1].valid = portCache[0].valid;
359 portCache[1].id = portCache[0].id;
360 portCache[1].start = portCache[0].start;
361 portCache[1].end = portCache[0].end;
362
363 portCache[0].valid = true;
364 portCache[0].id = id;
365 portCache[0].start = start;
366 portCache[0].end = end;
367 }
368
369 // Clears the cache. Needs to be called in constructor.
370 inline void clearPortCache() {
371 portCache[2].valid = false;
372 portCache[1].valid = false;
373 portCache[0].valid = false;
374 }
375
376 /**
377 * Return the address ranges this port is responsible for.
378 *
379 * @param id id of the bus port that made the request
380 *
381 * @return a list of non-overlapping address ranges
382 */
383 AddrRangeList getAddrRanges(Port::PortId id);
384
385 /**
386 * Determine if the bus port is snooping or not.
387 *
388 * @param id id of the bus port that made the request
389 *
390 * @return a boolean indicating if this port is snooping or not
391 */
392 bool isSnooping(Port::PortId id) const;
393
394 /** Calculate the timing parameters for the packet. Updates the
395 * firstWordTime and finishTime fields of the packet object.
396 * Returns the tick at which the packet header is completed (which
397 * will be all that is sent if the target rejects the packet).
398 */
399 Tick calcPacketTiming(PacketPtr pkt);
400
401 /** Occupy the bus until until */
402 void occupyBus(Tick until);
403
404 /**
405 * Release the bus after being occupied and return to an idle
406 * state where we proceed to send a retry to any potential waiting
407 * port, or drain if asked to do so.
408 */
409 void releaseBus();
410
411 /**
412 * Send a retry to the port at the head of the retryList. The
413 * caller must ensure that the list is not empty.
414 */
415 void retryWaiting();
416
417 /** Ask everyone on the bus what their size is
418 * @param id id of the busport that made the request
419 * @return the max of all the sizes
420 */
421 unsigned findBlockSize(Port::PortId id);
422
423 // event used to schedule a release of the bus
424 EventWrapper<Bus, &Bus::releaseBus> busIdleEvent;
425
426 bool inRetry;
427 std::set<Port::PortId> inRecvRangeChange;
428
429 /** The master and slave ports of the bus */
430 std::vector<SlavePort*> slavePorts;
431 std::vector<MasterPort*> masterPorts;
432
433 typedef std::vector<SlavePort*>::iterator SlavePortIter;
434 typedef std::vector<SlavePort*>::const_iterator SlavePortConstIter;
435
436 /** An array of pointers to ports that retry should be called on because the
437 * original send failed for whatever reason.*/
438 std::list<Port*> retryList;
439
440 void addToRetryList(Port* port)
441 {
442 if (!inRetry) {
443 // The device wasn't retrying a packet, or wasn't at an
444 // appropriate time.
445 retryList.push_back(port);
446 } else {
447 if (!retryList.empty() && port == retryList.front()) {
448 // The device was retrying a packet. It didn't work,
449 // so we'll leave it at the head of the retry list.
450 inRetry = false;
451 } else {
452 // We are in retry, but not for this port, put it at
453 // the end.
454 retryList.push_back(port);
455 }
456 }
457 }
458
459 /** Port that handles requests that don't match any of the interfaces.*/
460 short defaultPortId;
461
462 /** If true, use address range provided by default device. Any
463 address not handled by another port and not in default device's
464 range will cause a fatal error. If false, just send all
465 addresses not handled by another port to default device. */
466 bool useDefaultRange;
467
468 unsigned defaultBlockSize;
469 unsigned cachedBlockSize;
470 bool cachedBlockSizeValid;
471
472 public:
473
474 /** A function used to return the port associated with this bus object. */
475 virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1);
476 virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1);
477
478 virtual void init();
479 virtual void startup();
480
481 unsigned int drain(Event *de);
482
483 Bus(const BusParams *p);
484 };
485
486 #endif //__MEM_BUS_HH__