xbar.hh revision 6215
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
44#include "base/range.hh"
45#include "base/hashmap.hh"
46#include "base/range_map.hh"
47#include "base/types.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
55class 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() const;
135    };
136
137    /** a globally unique id for this bus. */
138    int busId;
139    /** the clock speed for the bus */
140    int clock;
141    /** cycles of overhead per transaction */
142    int headerCycles;
143    /** the width of the bus in bytes */
144    int width;
145    /** the next tick at which the bus will be idle */
146    Tick tickNextIdle;
147
148    Event * drainEvent;
149
150
151    static const int defaultId = -3; //Make it unique from Broadcast
152
153    typedef range_map<Addr,int>::iterator PortIter;
154    range_map<Addr, int> portMap;
155
156    AddrRangeList defaultRange;
157
158    typedef std::vector<BusPort*>::iterator SnoopIter;
159    std::vector<BusPort*> snoopPorts;
160
161    /** Function called by the port when the bus is recieving a Timing
162      transaction.*/
163    bool recvTiming(PacketPtr pkt);
164
165    /** Function called by the port when the bus is recieving a Atomic
166      transaction.*/
167    Tick recvAtomic(PacketPtr pkt);
168
169    /** Function called by the port when the bus is recieving a Functional
170        transaction.*/
171    void recvFunctional(PacketPtr pkt);
172
173    /** Timing function called by port when it is once again able to process
174     * requests. */
175    void recvRetry(int id);
176
177    /** Function called by the port when the bus is recieving a status change.*/
178    void recvStatusChange(Port::Status status, int id);
179
180    /** Find which port connected to this bus (if any) should be given a packet
181     * with this address.
182     * @param addr Address to find port for.
183     * @return id of port that the packet should be sent out of.
184     */
185    int findPort(Addr addr);
186
187    // Cache for the findPort function storing recently used ports from portMap
188    struct PortCache {
189        bool valid;
190        int  id;
191        Addr start;
192        Addr end;
193    };
194
195    PortCache portCache[3];
196
197    // Checks the cache and returns the id of the port that has the requested
198    // address within its range
199    inline int checkPortCache(Addr addr) {
200        if (portCache[0].valid && addr >= portCache[0].start &&
201            addr < portCache[0].end) {
202            return portCache[0].id;
203        }
204        if (portCache[1].valid && addr >= portCache[1].start &&
205                   addr < portCache[1].end) {
206            return portCache[1].id;
207        }
208        if (portCache[2].valid && addr >= portCache[2].start &&
209            addr < portCache[2].end) {
210            return portCache[2].id;
211        }
212
213        return -1;
214    }
215
216    // Clears the earliest entry of the cache and inserts a new port entry
217    inline void updatePortCache(short id, Addr start, Addr end) {
218        portCache[2].valid = portCache[1].valid;
219        portCache[2].id    = portCache[1].id;
220        portCache[2].start = portCache[1].start;
221        portCache[2].end   = portCache[1].end;
222
223        portCache[1].valid = portCache[0].valid;
224        portCache[1].id    = portCache[0].id;
225        portCache[1].start = portCache[0].start;
226        portCache[1].end   = portCache[0].end;
227
228        portCache[0].valid = true;
229        portCache[0].id    = id;
230        portCache[0].start = start;
231        portCache[0].end   = end;
232    }
233
234    // Clears the cache. Needs to be called in constructor.
235    inline void clearPortCache() {
236        portCache[2].valid = false;
237        portCache[1].valid = false;
238        portCache[0].valid = false;
239    }
240
241    /** Process address range request.
242     * @param resp addresses that we can respond to
243     * @param snoop addresses that we would like to snoop
244     * @param id ide of the busport that made the request.
245     */
246    void addressRanges(AddrRangeList &resp, bool &snoop, int id);
247
248    /** Calculate the timing parameters for the packet.  Updates the
249     * firstWordTime and finishTime fields of the packet object.
250     * Returns the tick at which the packet header is completed (which
251     * will be all that is sent if the target rejects the packet).
252     */
253    Tick calcPacketTiming(PacketPtr pkt);
254
255    /** Occupy the bus until until */
256    void occupyBus(Tick until);
257
258    /** Ask everyone on the bus what their size is
259     * @param id id of the busport that made the request
260     * @return the max of all the sizes
261     */
262    int findBlockSize(int id);
263
264    BusFreeEvent busIdle;
265
266    bool inRetry;
267    std::set<int> inRecvStatusChange;
268
269    /** max number of bus ids we've handed out so far */
270    short maxId;
271
272    /** An array of pointers to the peer port interfaces
273        connected to this bus.*/
274    m5::hash_map<short,BusPort*> interfaces;
275
276    /** An array of pointers to ports that retry should be called on because the
277     * original send failed for whatever reason.*/
278    std::list<BusPort*> retryList;
279
280    void addToRetryList(BusPort * port)
281    {
282        if (!inRetry) {
283            // The device wasn't retrying a packet, or wasn't at an appropriate
284            // time.
285            assert(!port->onRetryList());
286            port->onRetryList(true);
287            retryList.push_back(port);
288        } else {
289            if (port->onRetryList()) {
290                // The device was retrying a packet. It didn't work, so we'll leave
291                // it at the head of the retry list.
292                assert(port == retryList.front());
293                inRetry = false;
294            }
295            else {
296                port->onRetryList(true);
297                retryList.push_back(port);
298            }
299        }
300    }
301
302    /** Port that handles requests that don't match any of the interfaces.*/
303    BusPort *defaultPort;
304
305    BusPort *funcPort;
306    int funcPortId;
307
308    /** Has the user specified their own default responder? */
309    bool responderSet;
310
311    int defaultBlockSize;
312    int cachedBlockSize;
313    bool cachedBlockSizeValid;
314
315   // Cache for the peer port interfaces
316    struct BusCache {
317        bool  valid;
318        short id;
319        BusPort  *port;
320    };
321
322    BusCache busCache[3];
323
324    // Checks the peer port interfaces cache for the port id and returns
325    // a pointer to the matching port
326    inline BusPort* checkBusCache(short id) {
327        if (busCache[0].valid && id == busCache[0].id) {
328            return busCache[0].port;
329        }
330        if (busCache[1].valid && id == busCache[1].id) {
331            return busCache[1].port;
332        }
333        if (busCache[2].valid && id == busCache[2].id) {
334            return busCache[2].port;
335        }
336
337        return NULL;
338    }
339
340    // Replaces the earliest entry in the cache with a new entry
341    inline void updateBusCache(short id, BusPort *port) {
342        busCache[2].valid = busCache[1].valid;
343        busCache[2].id    = busCache[1].id;
344        busCache[2].port  = busCache[1].port;
345
346        busCache[1].valid = busCache[0].valid;
347        busCache[1].id    = busCache[0].id;
348        busCache[1].port  = busCache[0].port;
349
350        busCache[0].valid = true;
351        busCache[0].id    = id;
352        busCache[0].port  = port;
353    }
354
355    // Invalidates the cache. Needs to be called in constructor.
356    inline void clearBusCache() {
357        busCache[2].valid = false;
358        busCache[1].valid = false;
359        busCache[0].valid = false;
360    }
361
362
363  public:
364
365    /** A function used to return the port associated with this bus object. */
366    virtual Port *getPort(const std::string &if_name, int idx = -1);
367    virtual void deletePortRefs(Port *p);
368
369    virtual void init();
370    virtual void startup();
371
372    unsigned int drain(Event *de);
373
374    Bus(const BusParams *p)
375        : MemObject(p), busId(p->bus_id), clock(p->clock),
376          headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
377          drainEvent(NULL), busIdle(this), inRetry(false), maxId(0),
378          defaultPort(NULL), funcPort(NULL), funcPortId(-4),
379          responderSet(p->responder_set), defaultBlockSize(p->block_size),
380          cachedBlockSize(0), cachedBlockSizeValid(false)
381    {
382        //width, clock period, and header cycles must be positive
383        if (width <= 0)
384            fatal("Bus width must be positive\n");
385        if (clock <= 0)
386            fatal("Bus clock period must be positive\n");
387        if (headerCycles <= 0)
388            fatal("Number of header cycles must be positive\n");
389        clearBusCache();
390        clearPortCache();
391    }
392
393};
394
395#endif //__MEM_BUS_HH__
396