coherent_xbar.hh revision 8975
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 recvTimingReq(PacketPtr pkt)
93        { pkt->setSrc(id); return bus->recvTimingReq(pkt); }
94
95        /**
96         * When receiving a timing snoop response, pass it to the bus.
97         */
98        virtual bool recvTimingSnoopResp(PacketPtr pkt)
99        { pkt->setSrc(id); return bus->recvTimingSnoopResp(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 recvTimingResp(PacketPtr pkt)
167        { pkt->setSrc(id); return bus->recvTimingResp(pkt); }
168
169        /**
170         * When receiving a timing snoop request, pass it to the bus.
171         */
172        virtual void recvTimingSnoopReq(PacketPtr pkt)
173        { pkt->setSrc(id); return bus->recvTimingSnoopReq(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      request packet.*/
232    bool recvTimingReq(PacketPtr pkt);
233
234    /** Function called by the port when the bus is recieving a Timing
235      response packet.*/
236    bool recvTimingResp(PacketPtr pkt);
237
238    /** Function called by the port when the bus is recieving a timing
239        snoop request.*/
240    void recvTimingSnoopReq(PacketPtr pkt);
241
242    /** Function called by the port when the bus is recieving a timing
243        snoop response.*/
244    bool recvTimingSnoopResp(PacketPtr pkt);
245
246    /**
247     * Forward a timing packet to our snoopers, potentially excluding
248     * one of the connected coherent masters to avoid sending a packet
249     * back to where it came from.
250     *
251     * @param pkt Packet to forward
252     * @param exclude_slave_port_id Id of slave port to exclude
253     */
254    void forwardTiming(PacketPtr pkt, Port::PortId exclude_slave_port_id);
255
256    /**
257     * Determine if the bus is to be considered occupied when being
258     * presented with a packet from a specific port. If so, the port
259     * in question is also added to the retry list.
260     *
261     * @param pkt Incoming packet
262     * @param port Source port on the bus presenting the packet
263     *
264     * @return True if the bus is to be considered occupied
265     */
266    bool isOccupied(PacketPtr pkt, Port* port);
267
268    /**
269     * Deal with a destination port accepting a packet by potentially
270     * removing the source port from the retry list (if retrying) and
271     * occupying the bus accordingly.
272     *
273     * @param busy_time Time to spend as a result of a successful send
274     */
275    void succeededTiming(Tick busy_time);
276
277    /** Function called by the port when the bus is recieving a Atomic
278      transaction.*/
279    Tick recvAtomic(PacketPtr pkt);
280
281    /** Function called by the port when the bus is recieving an
282        atomic snoop transaction.*/
283    Tick recvAtomicSnoop(PacketPtr pkt);
284
285    /**
286     * Forward an atomic packet to our snoopers, potentially excluding
287     * one of the connected coherent masters to avoid sending a packet
288     * back to where it came from.
289     *
290     * @param pkt Packet to forward
291     * @param exclude_slave_port_id Id of slave port to exclude
292     *
293     * @return a pair containing the snoop response and snoop latency
294     */
295    std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
296                                          Port::PortId exclude_slave_port_id);
297
298    /** Function called by the port when the bus is recieving a Functional
299        transaction.*/
300    void recvFunctional(PacketPtr pkt);
301
302    /** Function called by the port when the bus is recieving a functional
303        snoop transaction.*/
304    void recvFunctionalSnoop(PacketPtr pkt);
305
306    /**
307     * Forward a functional packet to our snoopers, potentially
308     * excluding one of the connected coherent masters to avoid
309     * sending a packet back to where it came from.
310     *
311     * @param pkt Packet to forward
312     * @param exclude_slave_port_id Id of slave port to exclude
313     */
314    void forwardFunctional(PacketPtr pkt, Port::PortId exclude_slave_port_id);
315
316    /** Timing function called by port when it is once again able to process
317     * requests. */
318    void recvRetry(Port::PortId id);
319
320    /** Function called by the port when the bus is recieving a range change.*/
321    void recvRangeChange(Port::PortId id);
322
323    /** Find which port connected to this bus (if any) should be given a packet
324     * with this address.
325     * @param addr Address to find port for.
326     * @return id of port that the packet should be sent out of.
327     */
328    int findPort(Addr addr);
329
330    // Cache for the findPort function storing recently used ports from portMap
331    struct PortCache {
332        bool valid;
333        Port::PortId id;
334        Addr start;
335        Addr end;
336    };
337
338    PortCache portCache[3];
339
340    // Checks the cache and returns the id of the port that has the requested
341    // address within its range
342    inline int checkPortCache(Addr addr) {
343        if (portCache[0].valid && addr >= portCache[0].start &&
344            addr < portCache[0].end) {
345            return portCache[0].id;
346        }
347        if (portCache[1].valid && addr >= portCache[1].start &&
348                   addr < portCache[1].end) {
349            return portCache[1].id;
350        }
351        if (portCache[2].valid && addr >= portCache[2].start &&
352            addr < portCache[2].end) {
353            return portCache[2].id;
354        }
355
356        return Port::INVALID_PORT_ID;
357    }
358
359    // Clears the earliest entry of the cache and inserts a new port entry
360    inline void updatePortCache(short id, Addr start, Addr end) {
361        portCache[2].valid = portCache[1].valid;
362        portCache[2].id    = portCache[1].id;
363        portCache[2].start = portCache[1].start;
364        portCache[2].end   = portCache[1].end;
365
366        portCache[1].valid = portCache[0].valid;
367        portCache[1].id    = portCache[0].id;
368        portCache[1].start = portCache[0].start;
369        portCache[1].end   = portCache[0].end;
370
371        portCache[0].valid = true;
372        portCache[0].id    = id;
373        portCache[0].start = start;
374        portCache[0].end   = end;
375    }
376
377    // Clears the cache. Needs to be called in constructor.
378    inline void clearPortCache() {
379        portCache[2].valid = false;
380        portCache[1].valid = false;
381        portCache[0].valid = false;
382    }
383
384    /**
385     * Return the address ranges this port is responsible for.
386     *
387     * @param id id of the bus port that made the request
388     *
389     * @return a list of non-overlapping address ranges
390     */
391    AddrRangeList getAddrRanges(Port::PortId id);
392
393    /**
394     * Determine if the bus port is snooping or not.
395     *
396     * @param id id of the bus port that made the request
397     *
398     * @return a boolean indicating if this port is snooping or not
399     */
400    bool isSnooping(Port::PortId id) const;
401
402    /** Calculate the timing parameters for the packet.  Updates the
403     * firstWordTime and finishTime fields of the packet object.
404     * Returns the tick at which the packet header is completed (which
405     * will be all that is sent if the target rejects the packet).
406     */
407    Tick calcPacketTiming(PacketPtr pkt);
408
409    /** Occupy the bus until until */
410    void occupyBus(Tick until);
411
412    /**
413     * Release the bus after being occupied and return to an idle
414     * state where we proceed to send a retry to any potential waiting
415     * port, or drain if asked to do so.
416     */
417    void releaseBus();
418
419    /**
420     * Send a retry to the port at the head of the retryList. The
421     * caller must ensure that the list is not empty.
422     */
423    void retryWaiting();
424
425    /** Ask everyone on the bus what their size is
426     * @param id id of the busport that made the request
427     * @return the max of all the sizes
428     */
429    unsigned findBlockSize(Port::PortId id);
430
431    // event used to schedule a release of the bus
432    EventWrapper<Bus, &Bus::releaseBus> busIdleEvent;
433
434    bool inRetry;
435    std::set<Port::PortId> inRecvRangeChange;
436
437    /** The master and slave ports of the bus */
438    std::vector<SlavePort*> slavePorts;
439    std::vector<MasterPort*> masterPorts;
440
441    typedef std::vector<SlavePort*>::iterator SlavePortIter;
442    typedef std::vector<SlavePort*>::const_iterator SlavePortConstIter;
443
444    /** An array of pointers to ports that retry should be called on because the
445     * original send failed for whatever reason.*/
446    std::list<Port*> retryList;
447
448    void addToRetryList(Port* port)
449    {
450        if (!inRetry) {
451            // The device wasn't retrying a packet, or wasn't at an
452            // appropriate time.
453            retryList.push_back(port);
454        } else {
455            if (!retryList.empty() && port == retryList.front()) {
456                // The device was retrying a packet. It didn't work,
457                // so we'll leave it at the head of the retry list.
458                inRetry = false;
459            } else {
460                // We are in retry, but not for this port, put it at
461                // the end.
462                retryList.push_back(port);
463            }
464        }
465    }
466
467    /** Port that handles requests that don't match any of the interfaces.*/
468    short defaultPortId;
469
470    /** If true, use address range provided by default device.  Any
471       address not handled by another port and not in default device's
472       range will cause a fatal error.  If false, just send all
473       addresses not handled by another port to default device. */
474    bool useDefaultRange;
475
476    unsigned defaultBlockSize;
477    unsigned cachedBlockSize;
478    bool cachedBlockSizeValid;
479
480  public:
481
482    /** A function used to return the port associated with this bus object. */
483    virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1);
484    virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1);
485
486    virtual void init();
487    virtual void startup();
488
489    unsigned int drain(Event *de);
490
491    Bus(const BusParams *p);
492};
493
494#endif //__MEM_BUS_HH__
495