xbar.hh revision 4958
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 <list>
42#include <inttypes.h>
43
44#include "base/range.hh"
45#include "base/hashmap.hh"
46#include "base/range_map.hh"
47#include "mem/mem_object.hh"
48#include "mem/packet.hh"
49#include "mem/port.hh"
50#include "mem/request.hh"
51#include "sim/eventq.hh"
52
53class Bus : public MemObject
54{
55    /** Declaration of the buses port type, one will be instantiated for each
56        of the interfaces connecting to the bus. */
57    class BusPort : public Port
58    {
59        bool _onRetryList;
60
61        /** A pointer to the bus to which this port belongs. */
62        Bus *bus;
63
64        /** A id to keep track of the intercafe ID this port is connected to. */
65        int id;
66
67      public:
68
69        /** Constructor for the BusPort.*/
70        BusPort(const std::string &_name, Bus *_bus, int _id)
71            : Port(_name, _bus), _onRetryList(false), bus(_bus), id(_id)
72        { }
73
74        bool onRetryList()
75        { return _onRetryList; }
76
77        void onRetryList(bool newVal)
78        { _onRetryList = newVal; }
79
80        int getId() { return id; }
81
82      protected:
83
84        /** When reciving a timing request from the peer port (at id),
85            pass it to the bus. */
86        virtual bool recvTiming(PacketPtr pkt)
87        { pkt->setSrc(id); return bus->recvTiming(pkt); }
88
89        /** When reciving a Atomic requestfrom the peer port (at id),
90            pass it to the bus. */
91        virtual Tick recvAtomic(PacketPtr pkt)
92        { pkt->setSrc(id); return bus->recvAtomic(pkt); }
93
94        /** When reciving a Functional requestfrom the peer port (at id),
95            pass it to the bus. */
96        virtual void recvFunctional(PacketPtr pkt)
97        { pkt->setSrc(id); bus->recvFunctional(pkt); }
98
99        /** When reciving a status changefrom the peer port (at id),
100            pass it to the bus. */
101        virtual void recvStatusChange(Status status)
102        { bus->recvStatusChange(status, id); }
103
104        /** When reciving a retry from the peer port (at id),
105            pass it to the bus. */
106        virtual void recvRetry()
107        { bus->recvRetry(id); }
108
109        // This should return all the 'owned' addresses that are
110        // downstream from this bus, yes?  That is, the union of all
111        // the 'owned' address ranges of all the other interfaces on
112        // this bus...
113        virtual void getDeviceAddressRanges(AddrRangeList &resp,
114                                            bool &snoop)
115        { bus->addressRanges(resp, snoop, id); }
116
117        // Ask the bus to ask everyone on the bus what their block size is and
118        // take the max of it. This might need to be changed a bit if we ever
119        // support multiple block sizes.
120        virtual int deviceBlockSize()
121        { return bus->findBlockSize(id); }
122
123    };
124
125    class BusFreeEvent : public Event
126    {
127        Bus * bus;
128
129      public:
130        BusFreeEvent(Bus * _bus);
131        void process();
132        const char *description();
133    };
134
135    /** a globally unique id for this bus. */
136    int busId;
137    /** the clock speed for the bus */
138    int clock;
139    /** the width of the bus in bytes */
140    int width;
141    /** the next tick at which the bus will be idle */
142    Tick tickNextIdle;
143
144    Event * drainEvent;
145
146
147    static const int defaultId = -3; //Make it unique from Broadcast
148
149    typedef range_map<Addr,int>::iterator PortIter;
150    range_map<Addr, int> portMap;
151
152    AddrRangeList defaultRange;
153
154    typedef std::vector<BusPort*>::iterator SnoopIter;
155    std::vector<BusPort*> snoopPorts;
156
157    /** Function called by the port when the bus is recieving a Timing
158      transaction.*/
159    bool recvTiming(PacketPtr pkt);
160
161    /** Function called by the port when the bus is recieving a Atomic
162      transaction.*/
163    Tick recvAtomic(PacketPtr pkt);
164
165    /** Function called by the port when the bus is recieving a Functional
166        transaction.*/
167    void recvFunctional(PacketPtr pkt);
168
169    /** Timing function called by port when it is once again able to process
170     * requests. */
171    void recvRetry(int id);
172
173    /** Function called by the port when the bus is recieving a status change.*/
174    void recvStatusChange(Port::Status status, int id);
175
176    /** Find which port connected to this bus (if any) should be given a packet
177     * with this address.
178     * @param addr Address to find port for.
179     * @return id of port that the packet should be sent out of.
180     */
181    int findPort(Addr addr);
182
183    // Cache for the findPort function storing recently used ports from portMap
184    struct PortCache {
185        bool valid;
186        int  id;
187        Addr start;
188        Addr end;
189    };
190
191    PortCache portCache[3];
192
193    // Checks the cache and returns the id of the port that has the requested
194    // address within its range
195    inline int checkPortCache(Addr addr) {
196        if (portCache[0].valid && addr >= portCache[0].start &&
197            addr < portCache[0].end) {
198            return portCache[0].id;
199        } else if (portCache[1].valid && addr >= portCache[1].start &&
200                   addr < portCache[1].end) {
201            return portCache[1].id;
202        } else if (portCache[2].valid && addr >= portCache[2].start &&
203                   addr < portCache[2].end) {
204            return portCache[2].id;
205        }
206
207        return -1;
208    }
209
210    // Clears the earliest entry of the cache and inserts a new port entry
211    inline void updatePortCache(short id, Addr start, Addr end) {
212        portCache[2].valid = portCache[1].valid;
213        portCache[2].id    = portCache[1].id;
214        portCache[2].start = portCache[1].start;
215        portCache[2].end   = portCache[1].end;
216
217        portCache[1].valid = portCache[0].valid;
218        portCache[1].id    = portCache[0].id;
219        portCache[1].start = portCache[0].start;
220        portCache[1].end   = portCache[0].end;
221
222        portCache[0].valid = true;
223        portCache[0].id    = id;
224        portCache[0].start = start;
225        portCache[0].end   = end;
226    }
227
228    // Clears the cache. Needs to be called in constructor.
229    inline void clearPortCache() {
230        portCache[2].valid = false;
231        portCache[1].valid = false;
232        portCache[0].valid = false;
233    }
234
235    /** Process address range request.
236     * @param resp addresses that we can respond to
237     * @param snoop addresses that we would like to snoop
238     * @param id ide of the busport that made the request.
239     */
240    void addressRanges(AddrRangeList &resp, bool &snoop, int id);
241
242    /** Occupy the bus with transmitting the packet pkt */
243    void occupyBus(PacketPtr pkt);
244
245    /** Ask everyone on the bus what their size is
246     * @param id id of the busport that made the request
247     * @return the max of all the sizes
248     */
249    int findBlockSize(int id);
250
251    BusFreeEvent busIdle;
252
253    bool inRetry;
254
255    /** max number of bus ids we've handed out so far */
256    short maxId;
257
258    /** An array of pointers to the peer port interfaces
259        connected to this bus.*/
260    m5::hash_map<short,BusPort*> interfaces;
261
262    /** An array of pointers to ports that retry should be called on because the
263     * original send failed for whatever reason.*/
264    std::list<BusPort*> retryList;
265
266    void addToRetryList(BusPort * port)
267    {
268        if (!inRetry) {
269            // The device wasn't retrying a packet, or wasn't at an appropriate
270            // time.
271            assert(!port->onRetryList());
272            port->onRetryList(true);
273            retryList.push_back(port);
274        } else {
275            if (port->onRetryList()) {
276                // The device was retrying a packet. It didn't work, so we'll leave
277                // it at the head of the retry list.
278                assert(port == retryList.front());
279                inRetry = false;
280            }
281            else {
282                port->onRetryList(true);
283                retryList.push_back(port);
284            }
285        }
286    }
287
288    /** Port that handles requests that don't match any of the interfaces.*/
289    BusPort *defaultPort;
290
291    BusPort *funcPort;
292    int funcPortId;
293
294    /** Has the user specified their own default responder? */
295    bool responderSet;
296
297    int defaultBlockSize;
298    int cachedBlockSize;
299    bool cachedBlockSizeValid;
300
301   // Cache for the peer port interfaces
302    struct BusCache {
303        bool  valid;
304        short id;
305        BusPort  *port;
306    };
307
308    BusCache busCache[3];
309
310    // Checks the peer port interfaces cache for the port id and returns
311    // a pointer to the matching port
312    inline BusPort* checkBusCache(short id) {
313        if (busCache[0].valid && id == busCache[0].id) {
314            return busCache[0].port;
315        } else if (busCache[1].valid && id == busCache[1].id) {
316            return busCache[1].port;
317        } else if (busCache[2].valid && id == busCache[2].id) {
318            return busCache[2].port;
319        }
320
321        return NULL;
322    }
323
324    // Replaces the earliest entry in the cache with a new entry
325    inline void updateBusCache(short id, BusPort *port) {
326        busCache[2].valid = busCache[1].valid;
327        busCache[2].id    = busCache[1].id;
328        busCache[2].port  = busCache[1].port;
329
330        busCache[1].valid = busCache[0].valid;
331        busCache[1].id    = busCache[0].id;
332        busCache[1].port  = busCache[0].port;
333
334        busCache[0].valid = true;
335        busCache[0].id    = id;
336        busCache[0].port  = port;
337    }
338
339    // Invalidates the cache. Needs to be called in constructor.
340    inline void clearBusCache() {
341        // memset(busCache, 0, 3 * sizeof(BusCache));
342        busCache[2].valid = false;
343        busCache[1].valid = false;
344        busCache[0].valid = false;
345    }
346
347
348  public:
349
350    /** A function used to return the port associated with this bus object. */
351    virtual Port *getPort(const std::string &if_name, int idx = -1);
352    virtual void deletePortRefs(Port *p);
353
354    virtual void init();
355    virtual void startup();
356
357    unsigned int drain(Event *de);
358
359    Bus(const std::string &n, int bus_id, int _clock, int _width,
360        bool responder_set, int dflt_blk_size)
361        : MemObject(n), busId(bus_id), clock(_clock), width(_width),
362          tickNextIdle(0), drainEvent(NULL), busIdle(this), inRetry(false),
363          maxId(0), defaultPort(NULL), funcPort(NULL), funcPortId(-4),
364          responderSet(responder_set), defaultBlockSize(dflt_blk_size),
365          cachedBlockSize(0), cachedBlockSizeValid(false)
366    {
367        //Both the width and clock period must be positive
368        if (width <= 0)
369            fatal("Bus width must be positive\n");
370        if (clock <= 0)
371            fatal("Bus clock period must be positive\n");
372        clearBusCache();
373        clearPortCache();
374    }
375
376};
377
378#endif //__MEM_BUS_HH__
379