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