xbar.hh revision 8966
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 *          William Wang
44 */
45
46/**
47 * @file
48 * Declaration of a bus object.
49 */
50
51#ifndef __MEM_BUS_HH__
52#define __MEM_BUS_HH__
53
54#include <list>
55#include <set>
56#include <string>
57
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 "params/Bus.hh"
65#include "sim/eventq.hh"
66
67class Bus : public MemObject
68{
69    /**
70     * Declaration of the bus slave port type, one will be
71     * instantiated for each of the master interfaces connecting to
72     * the bus.
73     */
74    class BusSlavePort : public SlavePort
75    {
76      private:
77        /** A pointer to the bus to which this port belongs. */
78        Bus *bus;
79
80      public:
81
82        /** Constructor for the BusSlavePort.*/
83        BusSlavePort(const std::string &_name, Bus *_bus, Port::PortId _id)
84            : SlavePort(_name, _bus, _id), bus(_bus)
85        { }
86
87      protected:
88
89        /**
90         * When receiving a timing request, pass it to the bus.
91         */
92        virtual bool recvTiming(PacketPtr pkt)
93        { pkt->setSrc(id); return bus->recvTiming(pkt); }
94
95        /**
96         * When receiving a timing snoop response, pass it to the bus.
97         */
98        virtual bool recvTimingSnoop(PacketPtr pkt)
99        { pkt->setSrc(id); return bus->recvTimingSnoop(pkt); }
100
101        /**
102         * When receiving an atomic request, pass it to the bus.
103         */
104        virtual Tick recvAtomic(PacketPtr pkt)
105        { pkt->setSrc(id); return bus->recvAtomic(pkt); }
106
107        /**
108         * When receiving a functional request, pass it to the bus.
109         */
110        virtual void recvFunctional(PacketPtr pkt)
111        { pkt->setSrc(id); bus->recvFunctional(pkt); }
112
113        /**
114         * When receiving a retry, pass it to the bus.
115         */
116        virtual void recvRetry()
117        { panic("Bus slave ports always succeed and should never retry.\n"); }
118
119        // This should return all the 'owned' addresses that are
120        // downstream from this bus, yes?  That is, the union of all
121        // the 'owned' address ranges of all the other interfaces on
122        // this bus...
123        virtual AddrRangeList getAddrRanges()
124        { return bus->getAddrRanges(id); }
125
126        // Ask the bus to ask everyone on the bus what their block size is and
127        // take the max of it. This might need to be changed a bit if we ever
128        // support multiple block sizes.
129        virtual unsigned deviceBlockSize() const
130        { return bus->findBlockSize(id); }
131
132    };
133
134    /**
135     * Declaration of the bus master port type, one will be
136     * instantiated for each of the slave interfaces connecting to the
137     * bus.
138     */
139    class BusMasterPort : public MasterPort
140    {
141      private:
142        /** A pointer to the bus to which this port belongs. */
143        Bus *bus;
144
145      public:
146
147        /** Constructor for the BusMasterPort.*/
148        BusMasterPort(const std::string &_name, Bus *_bus, Port::PortId _id)
149            : MasterPort(_name, _bus, _id), bus(_bus)
150        { }
151
152        /**
153         * Determine if this port should be considered a snooper. This
154         * is determined by the bus.
155         *
156         * @return a boolean that is true if this port is snooping
157         */
158        virtual bool isSnooping() const
159        { return bus->isSnooping(id); }
160
161      protected:
162
163        /**
164         * When receiving a timing response, pass it to the bus.
165         */
166        virtual bool recvTiming(PacketPtr pkt)
167        { pkt->setSrc(id); return bus->recvTiming(pkt); }
168
169        /**
170         * When receiving a timing snoop request, pass it to the bus.
171         */
172        virtual bool recvTimingSnoop(PacketPtr pkt)
173        { pkt->setSrc(id); return bus->recvTimingSnoop(pkt); }
174
175        /**
176         * When receiving an atomic snoop request, pass it to the bus.
177         */
178        virtual Tick recvAtomicSnoop(PacketPtr pkt)
179        { pkt->setSrc(id); return bus->recvAtomicSnoop(pkt); }
180
181        /**
182         * When receiving a functional snoop request, pass it to the bus.
183         */
184        virtual void recvFunctionalSnoop(PacketPtr pkt)
185        { pkt->setSrc(id); bus->recvFunctionalSnoop(pkt); }
186
187        /** When reciving a range change from the peer port (at id),
188            pass it to the bus. */
189        virtual void recvRangeChange()
190        { bus->recvRangeChange(id); }
191
192        /** When reciving a retry from the peer port (at id),
193            pass it to the bus. */
194        virtual void recvRetry()
195        { bus->recvRetry(id); }
196
197        // Ask the bus to ask everyone on the bus what their block size is and
198        // take the max of it. This might need to be changed a bit if we ever
199        // support multiple block sizes.
200        virtual unsigned deviceBlockSize() const
201        { return bus->findBlockSize(id); }
202
203    };
204
205    /** the clock speed for the bus */
206    int clock;
207    /** cycles of overhead per transaction */
208    int headerCycles;
209    /** the width of the bus in bytes */
210    int width;
211    /** the next tick at which the bus will be idle */
212    Tick tickNextIdle;
213
214    Event * drainEvent;
215
216    typedef range_map<Addr,int>::iterator PortIter;
217    range_map<Addr, int> portMap;
218
219    AddrRangeList defaultRange;
220
221    std::vector<SlavePort*> snoopPorts;
222
223    /**
224     * Store the outstanding requests so we can determine which ones
225     * we generated and which ones were merely forwarded. This is used
226     * in the coherent bus when coherency responses come back.
227     */
228    std::set<RequestPtr> outstandingReq;
229
230    /** Function called by the port when the bus is recieving a Timing
231      transaction.*/
232    bool recvTiming(PacketPtr pkt);
233
234    /** Function called by the port when the bus is recieving a timing
235        snoop transaction.*/
236    bool recvTimingSnoop(PacketPtr pkt);
237
238    /**
239     * Forward a timing packet to our snoopers, potentially excluding
240     * one of the connected coherent masters to avoid sending a packet
241     * back to where it came from.
242     *
243     * @param pkt Packet to forward
244     * @param exclude_slave_port_id Id of slave port to exclude
245     */
246    void forwardTiming(PacketPtr pkt, Port::PortId exclude_slave_port_id);
247
248    /**
249     * Determine if the bus is to be considered occupied when being
250     * presented with a packet from a specific port. If so, the port
251     * in question is also added to the retry list.
252     *
253     * @param pkt Incoming packet
254     * @param port Source port on the bus presenting the packet
255     *
256     * @return True if the bus is to be considered occupied
257     */
258    bool isOccupied(PacketPtr pkt, Port* port);
259
260    /**
261     * Deal with a destination port accepting a packet by potentially
262     * removing the source port from the retry list (if retrying) and
263     * occupying the bus accordingly.
264     *
265     * @param busy_time Time to spend as a result of a successful send
266     */
267    void succeededTiming(Tick busy_time);
268
269    /** Function called by the port when the bus is recieving a Atomic
270      transaction.*/
271    Tick recvAtomic(PacketPtr pkt);
272
273    /** Function called by the port when the bus is recieving an
274        atomic snoop transaction.*/
275    Tick recvAtomicSnoop(PacketPtr pkt);
276
277    /**
278     * Forward an atomic packet to our snoopers, potentially excluding
279     * one of the connected coherent masters to avoid sending a packet
280     * back to where it came from.
281     *
282     * @param pkt Packet to forward
283     * @param exclude_slave_port_id Id of slave port to exclude
284     *
285     * @return a pair containing the snoop response and snoop latency
286     */
287    std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
288                                          Port::PortId exclude_slave_port_id);
289
290    /** Function called by the port when the bus is recieving a Functional
291        transaction.*/
292    void recvFunctional(PacketPtr pkt);
293
294    /** Function called by the port when the bus is recieving a functional
295        snoop transaction.*/
296    void recvFunctionalSnoop(PacketPtr pkt);
297
298    /**
299     * Forward a functional packet to our snoopers, potentially
300     * excluding one of the connected coherent masters to avoid
301     * sending a packet back to where it came from.
302     *
303     * @param pkt Packet to forward
304     * @param exclude_slave_port_id Id of slave port to exclude
305     */
306    void forwardFunctional(PacketPtr pkt, Port::PortId exclude_slave_port_id);
307
308    /** Timing function called by port when it is once again able to process
309     * requests. */
310    void recvRetry(Port::PortId id);
311
312    /** Function called by the port when the bus is recieving a range change.*/
313    void recvRangeChange(Port::PortId id);
314
315    /** Find which port connected to this bus (if any) should be given a packet
316     * with this address.
317     * @param addr Address to find port for.
318     * @return id of port that the packet should be sent out of.
319     */
320    int findPort(Addr addr);
321
322    // Cache for the findPort function storing recently used ports from portMap
323    struct PortCache {
324        bool valid;
325        Port::PortId id;
326        Addr start;
327        Addr end;
328    };
329
330    PortCache portCache[3];
331
332    // Checks the cache and returns the id of the port that has the requested
333    // address within its range
334    inline int checkPortCache(Addr addr) {
335        if (portCache[0].valid && addr >= portCache[0].start &&
336            addr < portCache[0].end) {
337            return portCache[0].id;
338        }
339        if (portCache[1].valid && addr >= portCache[1].start &&
340                   addr < portCache[1].end) {
341            return portCache[1].id;
342        }
343        if (portCache[2].valid && addr >= portCache[2].start &&
344            addr < portCache[2].end) {
345            return portCache[2].id;
346        }
347
348        return Port::INVALID_PORT_ID;
349    }
350
351    // Clears the earliest entry of the cache and inserts a new port entry
352    inline void updatePortCache(short id, Addr start, Addr end) {
353        portCache[2].valid = portCache[1].valid;
354        portCache[2].id    = portCache[1].id;
355        portCache[2].start = portCache[1].start;
356        portCache[2].end   = portCache[1].end;
357
358        portCache[1].valid = portCache[0].valid;
359        portCache[1].id    = portCache[0].id;
360        portCache[1].start = portCache[0].start;
361        portCache[1].end   = portCache[0].end;
362
363        portCache[0].valid = true;
364        portCache[0].id    = id;
365        portCache[0].start = start;
366        portCache[0].end   = end;
367    }
368
369    // Clears the cache. Needs to be called in constructor.
370    inline void clearPortCache() {
371        portCache[2].valid = false;
372        portCache[1].valid = false;
373        portCache[0].valid = false;
374    }
375
376    /**
377     * Return the address ranges this port is responsible for.
378     *
379     * @param id id of the bus port that made the request
380     *
381     * @return a list of non-overlapping address ranges
382     */
383    AddrRangeList getAddrRanges(Port::PortId id);
384
385    /**
386     * Determine if the bus port is snooping or not.
387     *
388     * @param id id of the bus port that made the request
389     *
390     * @return a boolean indicating if this port is snooping or not
391     */
392    bool isSnooping(Port::PortId id) const;
393
394    /** Calculate the timing parameters for the packet.  Updates the
395     * firstWordTime and finishTime fields of the packet object.
396     * Returns the tick at which the packet header is completed (which
397     * will be all that is sent if the target rejects the packet).
398     */
399    Tick calcPacketTiming(PacketPtr pkt);
400
401    /** Occupy the bus until until */
402    void occupyBus(Tick until);
403
404    /**
405     * Release the bus after being occupied and return to an idle
406     * state where we proceed to send a retry to any potential waiting
407     * port, or drain if asked to do so.
408     */
409    void releaseBus();
410
411    /**
412     * Send a retry to the port at the head of the retryList. The
413     * caller must ensure that the list is not empty.
414     */
415    void retryWaiting();
416
417    /** Ask everyone on the bus what their size is
418     * @param id id of the busport that made the request
419     * @return the max of all the sizes
420     */
421    unsigned findBlockSize(Port::PortId id);
422
423    // event used to schedule a release of the bus
424    EventWrapper<Bus, &Bus::releaseBus> busIdleEvent;
425
426    bool inRetry;
427    std::set<Port::PortId> inRecvRangeChange;
428
429    /** The master and slave ports of the bus */
430    std::vector<SlavePort*> slavePorts;
431    std::vector<MasterPort*> masterPorts;
432
433    typedef std::vector<SlavePort*>::iterator SlavePortIter;
434    typedef std::vector<SlavePort*>::const_iterator SlavePortConstIter;
435
436    /** An array of pointers to ports that retry should be called on because the
437     * original send failed for whatever reason.*/
438    std::list<Port*> retryList;
439
440    void addToRetryList(Port* port)
441    {
442        if (!inRetry) {
443            // The device wasn't retrying a packet, or wasn't at an
444            // appropriate time.
445            retryList.push_back(port);
446        } else {
447            if (!retryList.empty() && port == retryList.front()) {
448                // The device was retrying a packet. It didn't work,
449                // so we'll leave it at the head of the retry list.
450                inRetry = false;
451            } else {
452                // We are in retry, but not for this port, put it at
453                // the end.
454                retryList.push_back(port);
455            }
456        }
457    }
458
459    /** Port that handles requests that don't match any of the interfaces.*/
460    short defaultPortId;
461
462    /** If true, use address range provided by default device.  Any
463       address not handled by another port and not in default device's
464       range will cause a fatal error.  If false, just send all
465       addresses not handled by another port to default device. */
466    bool useDefaultRange;
467
468    unsigned defaultBlockSize;
469    unsigned cachedBlockSize;
470    bool cachedBlockSizeValid;
471
472  public:
473
474    /** A function used to return the port associated with this bus object. */
475    virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1);
476    virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1);
477
478    virtual void init();
479    virtual void startup();
480
481    unsigned int drain(Event *de);
482
483    Bus(const BusParams *p);
484};
485
486#endif //__MEM_BUS_HH__
487