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