coherent_xbar.hh revision 8922
1545SN/A/*
22512SN/A * Copyright (c) 2011 ARM Limited
3545SN/A * All rights reserved
4545SN/A *
5545SN/A * The license below extends only to copyright in the software and shall
6545SN/A * not be construed as granting a license to any other intellectual
7545SN/A * property including but not limited to intellectual property relating
8545SN/A * to a hardware implementation of the functionality of the software
9545SN/A * licensed hereunder.  You may use the software subject to the license
10545SN/A * terms below provided that you ensure that this notice is replicated
11545SN/A * unmodified and in its entirety in all distributions of the software,
12545SN/A * modified or unmodified, in source code or in binary form.
13545SN/A *
14545SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
15545SN/A * All rights reserved.
16545SN/A *
17545SN/A * Redistribution and use in source and binary forms, with or without
18545SN/A * modification, are permitted provided that the following conditions are
19545SN/A * met: redistributions of source code must retain the above copyright
20545SN/A * notice, this list of conditions and the following disclaimer;
21545SN/A * redistributions in binary form must reproduce the above copyright
22545SN/A * notice, this list of conditions and the following disclaimer in the
23545SN/A * documentation and/or other materials provided with the distribution;
24545SN/A * neither the name of the copyright holders nor the names of its
25545SN/A * contributors may be used to endorse or promote products derived from
26545SN/A * this software without specific prior written permission.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30545SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31545SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
323090Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332657Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34545SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35679SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362901Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37545SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382489SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392901Ssaidi@eecs.umich.edu *
403091Sstever@eecs.umich.edu * Authors: Ron Dreslinski
412489SN/A *          Ali Saidi
422489SN/A *          Andreas Hansson
432489SN/A *          William Wang
442489SN/A */
453349Sbinkertn@umich.edu
462489SN/A/**
473091Sstever@eecs.umich.edu * @file
482489SN/A * Declaration of a bus object.
492489SN/A */
502489SN/A
512521SN/A#ifndef __MEM_BUS_HH__
522489SN/A#define __MEM_BUS_HH__
532521SN/A
542521SN/A#include <list>
552489SN/A#include <set>
562489SN/A#include <string>
572489SN/A
58545SN/A#include "base/range.hh"
59545SN/A#include "base/range_map.hh"
602384SN/A#include "base/types.hh"
612489SN/A#include "mem/mem_object.hh"
62545SN/A#include "mem/packet.hh"
63545SN/A#include "mem/port.hh"
642542SN/A#include "params/Bus.hh"
652541SN/A#include "sim/eventq.hh"
662541SN/A
672541SN/Aclass Bus : public MemObject
682541SN/A{
692541SN/A    /**
702541SN/A     * Declaration of the bus slave port type, one will be
712541SN/A     * instantiated for each of the master interfaces connecting to
722901Ssaidi@eecs.umich.edu     * the bus.
732901Ssaidi@eecs.umich.edu     */
742901Ssaidi@eecs.umich.edu    class BusSlavePort : public SlavePort
752901Ssaidi@eecs.umich.edu    {
762901Ssaidi@eecs.umich.edu      private:
772901Ssaidi@eecs.umich.edu        /** A pointer to the bus to which this port belongs. */
782901Ssaidi@eecs.umich.edu        Bus *bus;
792901Ssaidi@eecs.umich.edu
802901Ssaidi@eecs.umich.edu        /** A id to keep track of the interface ID of this port. */
812901Ssaidi@eecs.umich.edu        int id;
822901Ssaidi@eecs.umich.edu
832901Ssaidi@eecs.umich.edu      public:
842901Ssaidi@eecs.umich.edu
852539SN/A        /** Constructor for the BusSlavePort.*/
862539SN/A        BusSlavePort(const std::string &_name, Bus *_bus, int _id)
872539SN/A            : SlavePort(_name, _bus), bus(_bus), id(_id)
882539SN/A        { }
892539SN/A
902539SN/A        int getId() const { return id; }
912539SN/A
922539SN/A      protected:
932489SN/A
942901Ssaidi@eecs.umich.edu        /** When reciving a timing request from the peer port (at id),
952901Ssaidi@eecs.umich.edu            pass it to the bus. */
962901Ssaidi@eecs.umich.edu        virtual bool recvTiming(PacketPtr pkt)
972489SN/A        { pkt->setSrc(id); return bus->recvTiming(pkt); }
982489SN/A
992489SN/A        /** When reciving a Atomic requestfrom the peer port (at id),
1003349Sbinkertn@umich.edu            pass it to the bus. */
1012384SN/A        virtual Tick recvAtomic(PacketPtr pkt)
1022685Ssaidi@eecs.umich.edu        { pkt->setSrc(id); return bus->recvAtomic(pkt); }
1032685Ssaidi@eecs.umich.edu
1042685Ssaidi@eecs.umich.edu        /** When reciving a Functional requestfrom the peer port (at id),
1052685Ssaidi@eecs.umich.edu            pass it to the bus. */
1062685Ssaidi@eecs.umich.edu        virtual void recvFunctional(PacketPtr pkt)
1072685Ssaidi@eecs.umich.edu        { pkt->setSrc(id); bus->recvFunctional(pkt); }
1082685Ssaidi@eecs.umich.edu
1092685Ssaidi@eecs.umich.edu        /** When reciving a retry from the peer port (at id),
1102565SN/A            pass it to the bus. */
1112685Ssaidi@eecs.umich.edu        virtual void recvRetry()
1122685Ssaidi@eecs.umich.edu        { bus->recvRetry(id); }
1132641Sstever@eecs.umich.edu
1142685Ssaidi@eecs.umich.edu        // This should return all the 'owned' addresses that are
1152685Ssaidi@eecs.umich.edu        // downstream from this bus, yes?  That is, the union of all
1162685Ssaidi@eecs.umich.edu        // the 'owned' address ranges of all the other interfaces on
1172657Ssaidi@eecs.umich.edu        // this bus...
1182685Ssaidi@eecs.umich.edu        virtual AddrRangeList getAddrRanges()
1192685Ssaidi@eecs.umich.edu        { return bus->getAddrRanges(id); }
1202685Ssaidi@eecs.umich.edu
1212685Ssaidi@eecs.umich.edu        // Ask the bus to ask everyone on the bus what their block size is and
1222685Ssaidi@eecs.umich.edu        // take the max of it. This might need to be changed a bit if we ever
1232685Ssaidi@eecs.umich.edu        // support multiple block sizes.
1242630SN/A        virtual unsigned deviceBlockSize() const
1252630SN/A        { return bus->findBlockSize(id); }
1262901Ssaidi@eecs.umich.edu
1272901Ssaidi@eecs.umich.edu    };
1282901Ssaidi@eecs.umich.edu
1292901Ssaidi@eecs.umich.edu    /**
1302901Ssaidi@eecs.umich.edu     * Declaration of the bus master port type, one will be
1312569SN/A     * instantiated for each of the slave interfaces connecting to the
1322685Ssaidi@eecs.umich.edu     * bus.
1332565SN/A     */
1342569SN/A    class BusMasterPort : public MasterPort
1352657Ssaidi@eecs.umich.edu    {
1362384SN/A      private:
137679SN/A        /** A pointer to the bus to which this port belongs. */
1382521SN/A        Bus *bus;
1392565SN/A
1402565SN/A        /** A id to keep track of the interface ID of this port. */
1412384SN/A        int id;
1422901Ssaidi@eecs.umich.edu
1432901Ssaidi@eecs.umich.edu      public:
1442901Ssaidi@eecs.umich.edu
1452901Ssaidi@eecs.umich.edu        /** Constructor for the BusMasterPort.*/
1462901Ssaidi@eecs.umich.edu        BusMasterPort(const std::string &_name, Bus *_bus, int _id)
1472901Ssaidi@eecs.umich.edu            : MasterPort(_name, _bus), bus(_bus), id(_id)
1482901Ssaidi@eecs.umich.edu        { }
1492901Ssaidi@eecs.umich.edu
1502901Ssaidi@eecs.umich.edu        int getId() const { return id; }
1512901Ssaidi@eecs.umich.edu
1522901Ssaidi@eecs.umich.edu        /**
1532901Ssaidi@eecs.umich.edu         * Determine if this port should be considered a snooper. This
1542901Ssaidi@eecs.umich.edu         * is determined by the bus.
1552901Ssaidi@eecs.umich.edu         *
1562901Ssaidi@eecs.umich.edu         * @return a boolean that is true if this port is snooping
1572901Ssaidi@eecs.umich.edu         */
1582901Ssaidi@eecs.umich.edu        virtual bool isSnooping() const
1592901Ssaidi@eecs.umich.edu        { return bus->isSnooping(id); }
1602901Ssaidi@eecs.umich.edu
1612901Ssaidi@eecs.umich.edu      protected:
1622901Ssaidi@eecs.umich.edu
1632901Ssaidi@eecs.umich.edu        /** When reciving a timing request from the peer port (at id),
1642901Ssaidi@eecs.umich.edu            pass it to the bus. */
1652384SN/A        virtual bool recvTiming(PacketPtr pkt)
1662489SN/A        { pkt->setSrc(id); return bus->recvTiming(pkt); }
1672489SN/A
1683349Sbinkertn@umich.edu        /** When reciving a Atomic requestfrom the peer port (at id),
1692659Ssaidi@eecs.umich.edu            pass it to the bus. */
1702659Ssaidi@eecs.umich.edu        virtual Tick recvAtomic(PacketPtr pkt)
1712659Ssaidi@eecs.umich.edu        { pkt->setSrc(id); return bus->recvAtomic(pkt); }
1722659Ssaidi@eecs.umich.edu
1732659Ssaidi@eecs.umich.edu        /** When reciving a Functional requestfrom the peer port (at id),
1742659Ssaidi@eecs.umich.edu            pass it to the bus. */
1752659Ssaidi@eecs.umich.edu        virtual void recvFunctional(PacketPtr pkt)
1762659Ssaidi@eecs.umich.edu        { pkt->setSrc(id); bus->recvFunctional(pkt); }
1772659Ssaidi@eecs.umich.edu
1782659Ssaidi@eecs.umich.edu        /** When reciving a range change from the peer port (at id),
1792659Ssaidi@eecs.umich.edu            pass it to the bus. */
1802657Ssaidi@eecs.umich.edu        virtual void recvRangeChange()
1812489SN/A        { bus->recvRangeChange(id); }
1822641Sstever@eecs.umich.edu
1832641Sstever@eecs.umich.edu        /** When reciving a retry from the peer port (at id),
1842489SN/A            pass it to the bus. */
1852641Sstever@eecs.umich.edu        virtual void recvRetry()
1862641Sstever@eecs.umich.edu        { bus->recvRetry(id); }
1872384SN/A
1882384SN/A        // Ask the bus to ask everyone on the bus what their block size is and
1892384SN/A        // take the max of it. This might need to be changed a bit if we ever
1902901Ssaidi@eecs.umich.edu        // support multiple block sizes.
1912901Ssaidi@eecs.umich.edu        virtual unsigned deviceBlockSize() const
1922685Ssaidi@eecs.umich.edu        { return bus->findBlockSize(id); }
1932384SN/A
1942406SN/A    };
1952406SN/A
1962663Sstever@eecs.umich.edu    /** the clock speed for the bus */
1973349Sbinkertn@umich.edu    int clock;
1982641Sstever@eecs.umich.edu    /** cycles of overhead per transaction */
1992384SN/A    int headerCycles;
2002566SN/A    /** the width of the bus in bytes */
2012685Ssaidi@eecs.umich.edu    int width;
2022641Sstever@eecs.umich.edu    /** the next tick at which the bus will be idle */
2032685Ssaidi@eecs.umich.edu    Tick tickNextIdle;
2042641Sstever@eecs.umich.edu
2052565SN/A    Event * drainEvent;
2062565SN/A
2072566SN/A    typedef range_map<Addr,int>::iterator PortIter;
2082384SN/A    range_map<Addr, int> portMap;
2092901Ssaidi@eecs.umich.edu
2102384SN/A    AddrRangeList defaultRange;
2112384SN/A
2122384SN/A    typedef std::vector<BusSlavePort*>::iterator SnoopIter;
2132384SN/A    std::vector<BusSlavePort*> snoopPorts;
2143349Sbinkertn@umich.edu
2152384SN/A    /** Function called by the port when the bus is recieving a Timing
2162901Ssaidi@eecs.umich.edu      transaction.*/
2172901Ssaidi@eecs.umich.edu    bool recvTiming(PacketPtr pkt);
2182901Ssaidi@eecs.umich.edu
2192902Ssaidi@eecs.umich.edu    /** Function called by the port when the bus is recieving a Atomic
2202901Ssaidi@eecs.umich.edu      transaction.*/
2212901Ssaidi@eecs.umich.edu    Tick recvAtomic(PacketPtr pkt);
2222901Ssaidi@eecs.umich.edu
2232901Ssaidi@eecs.umich.edu    /** Function called by the port when the bus is recieving a Functional
2242901Ssaidi@eecs.umich.edu        transaction.*/
2252901Ssaidi@eecs.umich.edu    void recvFunctional(PacketPtr pkt);
2262901Ssaidi@eecs.umich.edu
2272901Ssaidi@eecs.umich.edu    /** Timing function called by port when it is once again able to process
2282901Ssaidi@eecs.umich.edu     * requests. */
2292901Ssaidi@eecs.umich.edu    void recvRetry(int id);
2302901Ssaidi@eecs.umich.edu
2312901Ssaidi@eecs.umich.edu    /** Function called by the port when the bus is recieving a range change.*/
2322901Ssaidi@eecs.umich.edu    void recvRangeChange(int id);
2332901Ssaidi@eecs.umich.edu
2342902Ssaidi@eecs.umich.edu    /** Find which port connected to this bus (if any) should be given a packet
2352902Ssaidi@eecs.umich.edu     * with this address.
2362901Ssaidi@eecs.umich.edu     * @param addr Address to find port for.
2372901Ssaidi@eecs.umich.edu     * @return id of port that the packet should be sent out of.
2382901Ssaidi@eecs.umich.edu     */
2392384SN/A    int findPort(Addr addr);
2402901Ssaidi@eecs.umich.edu
2412901Ssaidi@eecs.umich.edu    // Cache for the findPort function storing recently used ports from portMap
2422902Ssaidi@eecs.umich.edu    struct PortCache {
2432901Ssaidi@eecs.umich.edu        bool valid;
2442901Ssaidi@eecs.umich.edu        int  id;
2452901Ssaidi@eecs.umich.edu        Addr start;
2462901Ssaidi@eecs.umich.edu        Addr end;
2472901Ssaidi@eecs.umich.edu    };
2482901Ssaidi@eecs.umich.edu
2492566SN/A    PortCache portCache[3];
2502901Ssaidi@eecs.umich.edu
2512901Ssaidi@eecs.umich.edu    // Checks the cache and returns the id of the port that has the requested
2522901Ssaidi@eecs.umich.edu    // address within its range
2532901Ssaidi@eecs.umich.edu    inline int checkPortCache(Addr addr) {
2542901Ssaidi@eecs.umich.edu        if (portCache[0].valid && addr >= portCache[0].start &&
2552384SN/A            addr < portCache[0].end) {
2562384SN/A            return portCache[0].id;
2572384SN/A        }
258545SN/A        if (portCache[1].valid && addr >= portCache[1].start &&
259545SN/A                   addr < portCache[1].end) {
260545SN/A            return portCache[1].id;
2612489SN/A        }
2622489SN/A        if (portCache[2].valid && addr >= portCache[2].start &&
263545SN/A            addr < portCache[2].end) {
264545SN/A            return portCache[2].id;
265679SN/A        }
266
267        return INVALID_PORT_ID;
268    }
269
270    // Clears the earliest entry of the cache and inserts a new port entry
271    inline void updatePortCache(short id, Addr start, Addr end) {
272        portCache[2].valid = portCache[1].valid;
273        portCache[2].id    = portCache[1].id;
274        portCache[2].start = portCache[1].start;
275        portCache[2].end   = portCache[1].end;
276
277        portCache[1].valid = portCache[0].valid;
278        portCache[1].id    = portCache[0].id;
279        portCache[1].start = portCache[0].start;
280        portCache[1].end   = portCache[0].end;
281
282        portCache[0].valid = true;
283        portCache[0].id    = id;
284        portCache[0].start = start;
285        portCache[0].end   = end;
286    }
287
288    // Clears the cache. Needs to be called in constructor.
289    inline void clearPortCache() {
290        portCache[2].valid = false;
291        portCache[1].valid = false;
292        portCache[0].valid = false;
293    }
294
295    /**
296     * Return the address ranges this port is responsible for.
297     *
298     * @param id id of the bus port that made the request
299     *
300     * @return a list of non-overlapping address ranges
301     */
302    AddrRangeList getAddrRanges(int id);
303
304    /**
305     * Determine if the bus port is snooping or not.
306     *
307     * @param id id of the bus port that made the request
308     *
309     * @return a boolean indicating if this port is snooping or not
310     */
311    bool isSnooping(int id) const;
312
313    /** Calculate the timing parameters for the packet.  Updates the
314     * firstWordTime and finishTime fields of the packet object.
315     * Returns the tick at which the packet header is completed (which
316     * will be all that is sent if the target rejects the packet).
317     */
318    Tick calcPacketTiming(PacketPtr pkt);
319
320    /** Occupy the bus until until */
321    void occupyBus(Tick until);
322
323    /**
324     * Release the bus after being occupied and return to an idle
325     * state where we proceed to send a retry to any potential waiting
326     * port, or drain if asked to do so.
327     */
328    void releaseBus();
329
330    /**
331     * Send a retry to the port at the head of the retryList. The
332     * caller must ensure that the list is not empty.
333     */
334    void retryWaiting();
335
336    /** Ask everyone on the bus what their size is
337     * @param id id of the busport that made the request
338     * @return the max of all the sizes
339     */
340    unsigned findBlockSize(int id);
341
342    // event used to schedule a release of the bus
343    EventWrapper<Bus, &Bus::releaseBus> busIdleEvent;
344
345    bool inRetry;
346    std::set<int> inRecvRangeChange;
347
348    // keep track of the number of master ports (not counting the
349    // default master) since we need this as an offset into the
350    // interfaces vector
351    unsigned int nbrMasterPorts;
352
353    /** The master and slave ports of the bus */
354    std::vector<BusSlavePort*> slavePorts;
355    std::vector<BusMasterPort*> masterPorts;
356
357    /** An array of pointers to ports that retry should be called on because the
358     * original send failed for whatever reason.*/
359    std::list<Port*> retryList;
360
361    void addToRetryList(Port* port)
362    {
363        if (!inRetry) {
364            // The device wasn't retrying a packet, or wasn't at an
365            // appropriate time.
366            retryList.push_back(port);
367        } else {
368            if (!retryList.empty() && port == retryList.front()) {
369                // The device was retrying a packet. It didn't work,
370                // so we'll leave it at the head of the retry list.
371                inRetry = false;
372            } else {
373                // We are in retry, but not for this port, put it at
374                // the end.
375                retryList.push_back(port);
376            }
377        }
378    }
379
380    /** Port that handles requests that don't match any of the interfaces.*/
381    short defaultPortId;
382
383    /** A symbolic name for a port id that denotes no port. */
384    static const short INVALID_PORT_ID = -1;
385
386    /** If true, use address range provided by default device.  Any
387       address not handled by another port and not in default device's
388       range will cause a fatal error.  If false, just send all
389       addresses not handled by another port to default device. */
390    bool useDefaultRange;
391
392    unsigned defaultBlockSize;
393    unsigned cachedBlockSize;
394    bool cachedBlockSizeValid;
395
396  public:
397
398    /** A function used to return the port associated with this bus object. */
399    virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1);
400    virtual SlavePort& getSlavePort(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