Update statistics to use cycles properly instead of ticks
[gem5.git] / src / mem / bus.hh
1 /*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Ron Dreslinski
29 * Ali Saidi
30 */
31
32 /**
33 * @file
34 * Declaration of a bus object.
35 */
36
37 #ifndef __MEM_BUS_HH__
38 #define __MEM_BUS_HH__
39
40 #include <string>
41 #include <set>
42 #include <list>
43 #include <inttypes.h>
44
45 #include "base/range.hh"
46 #include "base/hashmap.hh"
47 #include "base/range_map.hh"
48 #include "mem/mem_object.hh"
49 #include "mem/packet.hh"
50 #include "mem/port.hh"
51 #include "mem/request.hh"
52 #include "sim/eventq.hh"
53 #include "params/Bus.hh"
54
55 class Bus : public MemObject
56 {
57 /** Declaration of the buses port type, one will be instantiated for each
58 of the interfaces connecting to the bus. */
59 class BusPort : public Port
60 {
61 bool _onRetryList;
62
63 /** A pointer to the bus to which this port belongs. */
64 Bus *bus;
65
66 /** A id to keep track of the intercafe ID this port is connected to. */
67 int id;
68
69 public:
70
71 /** Constructor for the BusPort.*/
72 BusPort(const std::string &_name, Bus *_bus, int _id)
73 : Port(_name, _bus), _onRetryList(false), bus(_bus), id(_id)
74 { }
75
76 bool onRetryList()
77 { return _onRetryList; }
78
79 void onRetryList(bool newVal)
80 { _onRetryList = newVal; }
81
82 int getId() { return id; }
83
84 protected:
85
86 /** When reciving a timing request from the peer port (at id),
87 pass it to the bus. */
88 virtual bool recvTiming(PacketPtr pkt)
89 { pkt->setSrc(id); return bus->recvTiming(pkt); }
90
91 /** When reciving a Atomic requestfrom the peer port (at id),
92 pass it to the bus. */
93 virtual Tick recvAtomic(PacketPtr pkt)
94 { pkt->setSrc(id); return bus->recvAtomic(pkt); }
95
96 /** When reciving a Functional requestfrom the peer port (at id),
97 pass it to the bus. */
98 virtual void recvFunctional(PacketPtr pkt)
99 { pkt->setSrc(id); bus->recvFunctional(pkt); }
100
101 /** When reciving a status changefrom the peer port (at id),
102 pass it to the bus. */
103 virtual void recvStatusChange(Status status)
104 { bus->recvStatusChange(status, id); }
105
106 /** When reciving a retry from the peer port (at id),
107 pass it to the bus. */
108 virtual void recvRetry()
109 { bus->recvRetry(id); }
110
111 // This should return all the 'owned' addresses that are
112 // downstream from this bus, yes? That is, the union of all
113 // the 'owned' address ranges of all the other interfaces on
114 // this bus...
115 virtual void getDeviceAddressRanges(AddrRangeList &resp,
116 bool &snoop)
117 { bus->addressRanges(resp, snoop, id); }
118
119 // Ask the bus to ask everyone on the bus what their block size is and
120 // take the max of it. This might need to be changed a bit if we ever
121 // support multiple block sizes.
122 virtual int deviceBlockSize()
123 { return bus->findBlockSize(id); }
124
125 };
126
127 class BusFreeEvent : public Event
128 {
129 Bus * bus;
130
131 public:
132 BusFreeEvent(Bus * _bus);
133 void process();
134 const char *description();
135 };
136
137 /** a globally unique id for this bus. */
138 int busId;
139 /** the clock speed for the bus */
140 int clock;
141 /** the width of the bus in bytes */
142 int width;
143 /** the next tick at which the bus will be idle */
144 Tick tickNextIdle;
145
146 Event * drainEvent;
147
148
149 static const int defaultId = -3; //Make it unique from Broadcast
150
151 typedef range_map<Addr,int>::iterator PortIter;
152 range_map<Addr, int> portMap;
153
154 AddrRangeList defaultRange;
155
156 typedef std::vector<BusPort*>::iterator SnoopIter;
157 std::vector<BusPort*> snoopPorts;
158
159 /** Function called by the port when the bus is recieving a Timing
160 transaction.*/
161 bool recvTiming(PacketPtr pkt);
162
163 /** Function called by the port when the bus is recieving a Atomic
164 transaction.*/
165 Tick recvAtomic(PacketPtr pkt);
166
167 /** Function called by the port when the bus is recieving a Functional
168 transaction.*/
169 void recvFunctional(PacketPtr pkt);
170
171 /** Timing function called by port when it is once again able to process
172 * requests. */
173 void recvRetry(int id);
174
175 /** Function called by the port when the bus is recieving a status change.*/
176 void recvStatusChange(Port::Status status, int id);
177
178 /** Find which port connected to this bus (if any) should be given a packet
179 * with this address.
180 * @param addr Address to find port for.
181 * @return id of port that the packet should be sent out of.
182 */
183 int findPort(Addr addr);
184
185 // Cache for the findPort function storing recently used ports from portMap
186 struct PortCache {
187 bool valid;
188 int id;
189 Addr start;
190 Addr end;
191 };
192
193 PortCache portCache[3];
194
195 // Checks the cache and returns the id of the port that has the requested
196 // address within its range
197 inline int checkPortCache(Addr addr) {
198 if (portCache[0].valid && addr >= portCache[0].start &&
199 addr < portCache[0].end) {
200 return portCache[0].id;
201 }
202 if (portCache[1].valid && addr >= portCache[1].start &&
203 addr < portCache[1].end) {
204 return portCache[1].id;
205 }
206 if (portCache[2].valid && addr >= portCache[2].start &&
207 addr < portCache[2].end) {
208 return portCache[2].id;
209 }
210
211 return -1;
212 }
213
214 // Clears the earliest entry of the cache and inserts a new port entry
215 inline void updatePortCache(short id, Addr start, Addr end) {
216 portCache[2].valid = portCache[1].valid;
217 portCache[2].id = portCache[1].id;
218 portCache[2].start = portCache[1].start;
219 portCache[2].end = portCache[1].end;
220
221 portCache[1].valid = portCache[0].valid;
222 portCache[1].id = portCache[0].id;
223 portCache[1].start = portCache[0].start;
224 portCache[1].end = portCache[0].end;
225
226 portCache[0].valid = true;
227 portCache[0].id = id;
228 portCache[0].start = start;
229 portCache[0].end = end;
230 }
231
232 // Clears the cache. Needs to be called in constructor.
233 inline void clearPortCache() {
234 portCache[2].valid = false;
235 portCache[1].valid = false;
236 portCache[0].valid = false;
237 }
238
239 /** Process address range request.
240 * @param resp addresses that we can respond to
241 * @param snoop addresses that we would like to snoop
242 * @param id ide of the busport that made the request.
243 */
244 void addressRanges(AddrRangeList &resp, bool &snoop, int id);
245
246 /** Occupy the bus with transmitting the packet pkt */
247 void occupyBus(PacketPtr pkt);
248
249 /** Ask everyone on the bus what their size is
250 * @param id id of the busport that made the request
251 * @return the max of all the sizes
252 */
253 int findBlockSize(int id);
254
255 BusFreeEvent busIdle;
256
257 bool inRetry;
258 std::set<int> inRecvStatusChange;
259
260 /** max number of bus ids we've handed out so far */
261 short maxId;
262
263 /** An array of pointers to the peer port interfaces
264 connected to this bus.*/
265 m5::hash_map<short,BusPort*> interfaces;
266
267 /** An array of pointers to ports that retry should be called on because the
268 * original send failed for whatever reason.*/
269 std::list<BusPort*> retryList;
270
271 void addToRetryList(BusPort * port)
272 {
273 if (!inRetry) {
274 // The device wasn't retrying a packet, or wasn't at an appropriate
275 // time.
276 assert(!port->onRetryList());
277 port->onRetryList(true);
278 retryList.push_back(port);
279 } else {
280 if (port->onRetryList()) {
281 // The device was retrying a packet. It didn't work, so we'll leave
282 // it at the head of the retry list.
283 assert(port == retryList.front());
284 inRetry = false;
285 }
286 else {
287 port->onRetryList(true);
288 retryList.push_back(port);
289 }
290 }
291 }
292
293 /** Port that handles requests that don't match any of the interfaces.*/
294 BusPort *defaultPort;
295
296 BusPort *funcPort;
297 int funcPortId;
298
299 /** Has the user specified their own default responder? */
300 bool responderSet;
301
302 int defaultBlockSize;
303 int cachedBlockSize;
304 bool cachedBlockSizeValid;
305
306 // Cache for the peer port interfaces
307 struct BusCache {
308 bool valid;
309 short id;
310 BusPort *port;
311 };
312
313 BusCache busCache[3];
314
315 // Checks the peer port interfaces cache for the port id and returns
316 // a pointer to the matching port
317 inline BusPort* checkBusCache(short id) {
318 if (busCache[0].valid && id == busCache[0].id) {
319 return busCache[0].port;
320 }
321 if (busCache[1].valid && id == busCache[1].id) {
322 return busCache[1].port;
323 }
324 if (busCache[2].valid && id == busCache[2].id) {
325 return busCache[2].port;
326 }
327
328 return NULL;
329 }
330
331 // Replaces the earliest entry in the cache with a new entry
332 inline void updateBusCache(short id, BusPort *port) {
333 busCache[2].valid = busCache[1].valid;
334 busCache[2].id = busCache[1].id;
335 busCache[2].port = busCache[1].port;
336
337 busCache[1].valid = busCache[0].valid;
338 busCache[1].id = busCache[0].id;
339 busCache[1].port = busCache[0].port;
340
341 busCache[0].valid = true;
342 busCache[0].id = id;
343 busCache[0].port = port;
344 }
345
346 // Invalidates the cache. Needs to be called in constructor.
347 inline void clearBusCache() {
348 busCache[2].valid = false;
349 busCache[1].valid = false;
350 busCache[0].valid = false;
351 }
352
353
354 public:
355
356 /** A function used to return the port associated with this bus object. */
357 virtual Port *getPort(const std::string &if_name, int idx = -1);
358 virtual void deletePortRefs(Port *p);
359
360 virtual void init();
361 virtual void startup();
362
363 unsigned int drain(Event *de);
364
365 Bus(const BusParams *p)
366 : MemObject(p), busId(p->bus_id), clock(p->clock), width(p->width),
367 tickNextIdle(0), drainEvent(NULL), busIdle(this), inRetry(false),
368 maxId(0), defaultPort(NULL), funcPort(NULL), funcPortId(-4),
369 responderSet(p->responder_set), defaultBlockSize(p->block_size),
370 cachedBlockSize(0), cachedBlockSizeValid(false)
371 {
372 //Both the width and clock period must be positive
373 if (width <= 0)
374 fatal("Bus width must be positive\n");
375 if (clock <= 0)
376 fatal("Bus clock period must be positive\n");
377 clearBusCache();
378 clearPortCache();
379 }
380
381 };
382
383 #endif //__MEM_BUS_HH__