xbar.hh revision 8715
114039Sstacze01@arm.com/*
214039Sstacze01@arm.com * Copyright (c) 2011 ARM Limited
314039Sstacze01@arm.com * All rights reserved
414039Sstacze01@arm.com *
514039Sstacze01@arm.com * The license below extends only to copyright in the software and shall
614039Sstacze01@arm.com * not be construed as granting a license to any other intellectual
714039Sstacze01@arm.com * property including but not limited to intellectual property relating
814039Sstacze01@arm.com * to a hardware implementation of the functionality of the software
914039Sstacze01@arm.com * licensed hereunder.  You may use the software subject to the license
1014039Sstacze01@arm.com * terms below provided that you ensure that this notice is replicated
1114039Sstacze01@arm.com * unmodified and in its entirety in all distributions of the software,
1214039Sstacze01@arm.com * modified or unmodified, in source code or in binary form.
1314039Sstacze01@arm.com *
1414039Sstacze01@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
1514039Sstacze01@arm.com * All rights reserved.
1614039Sstacze01@arm.com *
1714039Sstacze01@arm.com * Redistribution and use in source and binary forms, with or without
1814039Sstacze01@arm.com * modification, are permitted provided that the following conditions are
1914039Sstacze01@arm.com * met: redistributions of source code must retain the above copyright
2014039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer;
2114039Sstacze01@arm.com * redistributions in binary form must reproduce the above copyright
2214039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer in the
2314039Sstacze01@arm.com * documentation and/or other materials provided with the distribution;
2414039Sstacze01@arm.com * neither the name of the copyright holders nor the names of its
2514039Sstacze01@arm.com * contributors may be used to endorse or promote products derived from
2614039Sstacze01@arm.com * this software without specific prior written permission.
2714039Sstacze01@arm.com *
2814039Sstacze01@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2914039Sstacze01@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3014039Sstacze01@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3114039Sstacze01@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3214039Sstacze01@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3314039Sstacze01@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3414039Sstacze01@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3514039Sstacze01@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3614039Sstacze01@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3714039Sstacze01@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3814039Sstacze01@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3914039Sstacze01@arm.com *
4014039Sstacze01@arm.com * Authors: Ron Dreslinski
4114039Sstacze01@arm.com *          Ali Saidi
4214039Sstacze01@arm.com *          Andreas Hansson
4314039Sstacze01@arm.com */
4414039Sstacze01@arm.com
4514039Sstacze01@arm.com/**
4614039Sstacze01@arm.com * @file
4714039Sstacze01@arm.com * Declaration of a bus object.
4814039Sstacze01@arm.com */
4914039Sstacze01@arm.com
5014039Sstacze01@arm.com#ifndef __MEM_BUS_HH__
5114039Sstacze01@arm.com#define __MEM_BUS_HH__
5214039Sstacze01@arm.com
5314039Sstacze01@arm.com#include <list>
5414039Sstacze01@arm.com#include <set>
5514039Sstacze01@arm.com#include <string>
5614039Sstacze01@arm.com
5714039Sstacze01@arm.com#include "base/hashmap.hh"
5814039Sstacze01@arm.com#include "base/range.hh"
5914039Sstacze01@arm.com#include "base/range_map.hh"
6014039Sstacze01@arm.com#include "base/types.hh"
6114039Sstacze01@arm.com#include "mem/mem_object.hh"
6214039Sstacze01@arm.com#include "mem/packet.hh"
6314039Sstacze01@arm.com#include "mem/port.hh"
6414039Sstacze01@arm.com#include "mem/request.hh"
6514039Sstacze01@arm.com#include "params/Bus.hh"
6614039Sstacze01@arm.com#include "sim/eventq.hh"
6714039Sstacze01@arm.com
6814039Sstacze01@arm.comclass Bus : public MemObject
6914039Sstacze01@arm.com{
7014039Sstacze01@arm.com    /** Declaration of the buses port type, one will be instantiated for each
7114039Sstacze01@arm.com        of the interfaces connecting to the bus. */
7214039Sstacze01@arm.com    class BusPort : public Port
7314039Sstacze01@arm.com    {
7414039Sstacze01@arm.com        bool _onRetryList;
7514039Sstacze01@arm.com
7614039Sstacze01@arm.com        /** A pointer to the bus to which this port belongs. */
7714039Sstacze01@arm.com        Bus *bus;
7814039Sstacze01@arm.com
7914039Sstacze01@arm.com        /** A id to keep track of the intercafe ID this port is connected to. */
8014039Sstacze01@arm.com        int id;
8114039Sstacze01@arm.com
8214039Sstacze01@arm.com      public:
8314039Sstacze01@arm.com
8414039Sstacze01@arm.com        /** Constructor for the BusPort.*/
8514039Sstacze01@arm.com        BusPort(const std::string &_name, Bus *_bus, int _id)
8614039Sstacze01@arm.com            : Port(_name, _bus), _onRetryList(false), bus(_bus), id(_id)
8714039Sstacze01@arm.com        { }
8814039Sstacze01@arm.com
8914039Sstacze01@arm.com        bool onRetryList()
9014039Sstacze01@arm.com        { return _onRetryList; }
9114039Sstacze01@arm.com
9214039Sstacze01@arm.com        void onRetryList(bool newVal)
9314039Sstacze01@arm.com        { _onRetryList = newVal; }
9414039Sstacze01@arm.com
9514039Sstacze01@arm.com        int getId() const { return id; }
9614039Sstacze01@arm.com
9714039Sstacze01@arm.com        /**
9814039Sstacze01@arm.com         * Determine if this port should be considered a snooper. This
9914039Sstacze01@arm.com         * is determined by the bus.
10014039Sstacze01@arm.com         *
10114039Sstacze01@arm.com         * @return a boolean that is true if this port is snooping
10214039Sstacze01@arm.com         */
10314039Sstacze01@arm.com        virtual bool isSnooping()
10414039Sstacze01@arm.com        { return bus->isSnooping(id); }
10514039Sstacze01@arm.com
10614039Sstacze01@arm.com      protected:
10714039Sstacze01@arm.com
10814039Sstacze01@arm.com        /** When reciving a timing request from the peer port (at id),
10914039Sstacze01@arm.com            pass it to the bus. */
11014039Sstacze01@arm.com        virtual bool recvTiming(PacketPtr pkt)
11114039Sstacze01@arm.com        { pkt->setSrc(id); return bus->recvTiming(pkt); }
11214039Sstacze01@arm.com
11314039Sstacze01@arm.com        /** When reciving a Atomic requestfrom the peer port (at id),
11414039Sstacze01@arm.com            pass it to the bus. */
11514039Sstacze01@arm.com        virtual Tick recvAtomic(PacketPtr pkt)
11614039Sstacze01@arm.com        { pkt->setSrc(id); return bus->recvAtomic(pkt); }
11714039Sstacze01@arm.com
11814039Sstacze01@arm.com        /** When reciving a Functional requestfrom the peer port (at id),
11914039Sstacze01@arm.com            pass it to the bus. */
12014039Sstacze01@arm.com        virtual void recvFunctional(PacketPtr pkt)
12114039Sstacze01@arm.com        { pkt->setSrc(id); bus->recvFunctional(pkt); }
12214039Sstacze01@arm.com
12314039Sstacze01@arm.com        /** When reciving a range change from the peer port (at id),
12414039Sstacze01@arm.com            pass it to the bus. */
12514039Sstacze01@arm.com        virtual void recvRangeChange()
12614039Sstacze01@arm.com        { bus->recvRangeChange(id); }
12714039Sstacze01@arm.com
12814039Sstacze01@arm.com        /** When reciving a retry from the peer port (at id),
12914039Sstacze01@arm.com            pass it to the bus. */
13014039Sstacze01@arm.com        virtual void recvRetry()
13114039Sstacze01@arm.com        { bus->recvRetry(id); }
13214039Sstacze01@arm.com
13314039Sstacze01@arm.com        // This should return all the 'owned' addresses that are
13414039Sstacze01@arm.com        // downstream from this bus, yes?  That is, the union of all
13514039Sstacze01@arm.com        // the 'owned' address ranges of all the other interfaces on
13614039Sstacze01@arm.com        // this bus...
13714039Sstacze01@arm.com        virtual AddrRangeList getAddrRanges()
13814039Sstacze01@arm.com        { return bus->getAddrRanges(id); }
13914039Sstacze01@arm.com
14014039Sstacze01@arm.com        // Ask the bus to ask everyone on the bus what their block size is and
14114039Sstacze01@arm.com        // take the max of it. This might need to be changed a bit if we ever
14214039Sstacze01@arm.com        // support multiple block sizes.
14314039Sstacze01@arm.com        virtual unsigned deviceBlockSize() const
14414039Sstacze01@arm.com        { return bus->findBlockSize(id); }
14514039Sstacze01@arm.com
14614039Sstacze01@arm.com    };
14714039Sstacze01@arm.com
14814039Sstacze01@arm.com    class BusFreeEvent : public Event
14914039Sstacze01@arm.com    {
15014039Sstacze01@arm.com        Bus * bus;
15114039Sstacze01@arm.com
15214039Sstacze01@arm.com      public:
15314039Sstacze01@arm.com        BusFreeEvent(Bus * _bus);
15414039Sstacze01@arm.com        void process();
15514039Sstacze01@arm.com        const char *description() const;
15614039Sstacze01@arm.com    };
15714039Sstacze01@arm.com
15814039Sstacze01@arm.com    /** a globally unique id for this bus. */
15914039Sstacze01@arm.com    int busId;
16014039Sstacze01@arm.com    /** the clock speed for the bus */
16114039Sstacze01@arm.com    int clock;
16214039Sstacze01@arm.com    /** cycles of overhead per transaction */
16314039Sstacze01@arm.com    int headerCycles;
16414039Sstacze01@arm.com    /** the width of the bus in bytes */
16514039Sstacze01@arm.com    int width;
16614039Sstacze01@arm.com    /** the next tick at which the bus will be idle */
16714039Sstacze01@arm.com    Tick tickNextIdle;
16814039Sstacze01@arm.com
16914039Sstacze01@arm.com    Event * drainEvent;
17014039Sstacze01@arm.com
17114039Sstacze01@arm.com    typedef range_map<Addr,int>::iterator PortIter;
17214039Sstacze01@arm.com    range_map<Addr, int> portMap;
17314039Sstacze01@arm.com
17414039Sstacze01@arm.com    AddrRangeList defaultRange;
17514039Sstacze01@arm.com
17614039Sstacze01@arm.com    typedef std::vector<BusPort*>::iterator SnoopIter;
17714039Sstacze01@arm.com    std::vector<BusPort*> snoopPorts;
17814039Sstacze01@arm.com
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