xbar.hh revision 9032
12207SN/A/*
22207SN/A * Copyright (c) 2011-2012 ARM Limited
32207SN/A * All rights reserved
42207SN/A *
52207SN/A * The license below extends only to copyright in the software and shall
62207SN/A * not be construed as granting a license to any other intellectual
72207SN/A * property including but not limited to intellectual property relating
82207SN/A * to a hardware implementation of the functionality of the software
92207SN/A * licensed hereunder.  You may use the software subject to the license
102207SN/A * terms below provided that you ensure that this notice is replicated
112207SN/A * unmodified and in its entirety in all distributions of the software,
122207SN/A * modified or unmodified, in source code or in binary form.
132207SN/A *
142207SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
152207SN/A * All rights reserved.
162207SN/A *
172207SN/A * Redistribution and use in source and binary forms, with or without
182207SN/A * modification, are permitted provided that the following conditions are
192207SN/A * met: redistributions of source code must retain the above copyright
202207SN/A * notice, this list of conditions and the following disclaimer;
212207SN/A * redistributions in binary form must reproduce the above copyright
222207SN/A * notice, this list of conditions and the following disclaimer in the
232207SN/A * documentation and/or other materials provided with the distribution;
242207SN/A * neither the name of the copyright holders nor the names of its
252207SN/A * contributors may be used to endorse or promote products derived from
262207SN/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
302207SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312207SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322972Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332207SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342454SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352454SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362680Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372474SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382207SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392207SN/A *
402474SN/A * Authors: Ron Dreslinski
412474SN/A *          Ali Saidi
422474SN/A *          Andreas Hansson
435154Sgblack@eecs.umich.edu *          William Wang
445154Sgblack@eecs.umich.edu */
455154Sgblack@eecs.umich.edu
462474SN/A/**
472474SN/A * @file
482474SN/A * Declaration of a bus object.
492474SN/A */
502474SN/A
512474SN/A#ifndef __MEM_BUS_HH__
522474SN/A#define __MEM_BUS_HH__
532474SN/A
542474SN/A#include <list>
552474SN/A#include <set>
562474SN/A#include <string>
572474SN/A
582474SN/A#include "base/range.hh"
592474SN/A#include "base/range_map.hh"
602474SN/A#include "base/types.hh"
612474SN/A#include "mem/mem_object.hh"
622474SN/A#include "mem/packet.hh"
632474SN/A#include "mem/port.hh"
642474SN/A#include "params/Bus.hh"
652474SN/A#include "sim/eventq.hh"
665183Ssaidi@eecs.umich.edu
675183Ssaidi@eecs.umich.educlass Bus : public MemObject
685183Ssaidi@eecs.umich.edu{
692474SN/A
702474SN/A    /**
712680Sktlim@umich.edu     * Declaration of the bus slave port type, one will be
724997Sgblack@eecs.umich.edu     * instantiated for each of the master interfaces connecting to
734997Sgblack@eecs.umich.edu     * the bus.
744997Sgblack@eecs.umich.edu     */
754997Sgblack@eecs.umich.edu    class BusSlavePort : public SlavePort
764997Sgblack@eecs.umich.edu    {
774997Sgblack@eecs.umich.edu      private:
782474SN/A        /** A pointer to the bus to which this port belongs. */
792474SN/A        Bus *bus;
802474SN/A
81      public:
82
83        /** Constructor for the BusSlavePort.*/
84        BusSlavePort(const std::string &_name, Bus *_bus, PortID _id)
85            : SlavePort(_name, _bus, _id), bus(_bus)
86        { }
87
88      protected:
89
90        /**
91         * When receiving a timing request, pass it to the bus.
92         */
93        virtual bool recvTimingReq(PacketPtr pkt)
94        { return bus->recvTimingReq(pkt, id); }
95
96        /**
97         * When receiving a timing snoop response, pass it to the bus.
98         */
99        virtual bool recvTimingSnoopResp(PacketPtr pkt)
100        { return bus->recvTimingSnoopResp(pkt, id); }
101
102        /**
103         * When receiving an atomic request, pass it to the bus.
104         */
105        virtual Tick recvAtomic(PacketPtr pkt)
106        { return bus->recvAtomic(pkt, id); }
107
108        /**
109         * When receiving a functional request, pass it to the bus.
110         */
111        virtual void recvFunctional(PacketPtr pkt)
112        { bus->recvFunctional(pkt, id); }
113
114        /**
115         * When receiving a retry, pass it to the bus.
116         */
117        virtual void recvRetry()
118        { panic("Bus slave ports always succeed and should never retry.\n"); }
119
120        // This should return all the 'owned' addresses that are
121        // downstream from this bus, yes?  That is, the union of all
122        // the 'owned' address ranges of all the other interfaces on
123        // this bus...
124        virtual AddrRangeList getAddrRanges()
125        { return bus->getAddrRanges(); }
126
127        // Ask the bus to ask everyone on the bus what their block size is and
128        // take the max of it. This might need to be changed a bit if we ever
129        // support multiple block sizes.
130        virtual unsigned deviceBlockSize() const
131        { return bus->findBlockSize(); }
132
133    };
134
135    /**
136     * Declaration of the bus master port type, one will be
137     * instantiated for each of the slave interfaces connecting to the
138     * bus.
139     */
140    class BusMasterPort : public MasterPort
141    {
142      private:
143        /** A pointer to the bus to which this port belongs. */
144        Bus *bus;
145
146      public:
147
148        /** Constructor for the BusMasterPort.*/
149        BusMasterPort(const std::string &_name, Bus *_bus, PortID _id)
150            : MasterPort(_name, _bus, _id), bus(_bus)
151        { }
152
153        /**
154         * Determine if this port should be considered a snooper. This
155         * is determined by the bus.
156         *
157         * @return a boolean that is true if this port is snooping
158         */
159        virtual bool isSnooping() const
160        { return bus->isSnooping(); }
161
162      protected:
163
164        /**
165         * When receiving a timing response, pass it to the bus.
166         */
167        virtual bool recvTimingResp(PacketPtr pkt)
168        { return bus->recvTimingResp(pkt, id); }
169
170        /**
171         * When receiving a timing snoop request, pass it to the bus.
172         */
173        virtual void recvTimingSnoopReq(PacketPtr pkt)
174        { return bus->recvTimingSnoopReq(pkt, id); }
175
176        /**
177         * When receiving an atomic snoop request, pass it to the bus.
178         */
179        virtual Tick recvAtomicSnoop(PacketPtr pkt)
180        { return bus->recvAtomicSnoop(pkt, id); }
181
182        /**
183         * When receiving a functional snoop request, pass it to the bus.
184         */
185        virtual void recvFunctionalSnoop(PacketPtr pkt)
186        { bus->recvFunctionalSnoop(pkt, id); }
187
188        /** When reciving a range change from the peer port (at id),
189            pass it to the bus. */
190        virtual void recvRangeChange()
191        { bus->recvRangeChange(id); }
192
193        /** When reciving a retry from the peer port (at id),
194            pass it to the bus. */
195        virtual void recvRetry()
196        { bus->recvRetry(); }
197
198        // Ask the bus to ask everyone on the bus what their block size is and
199        // take the max of it. This might need to be changed a bit if we ever
200        // support multiple block sizes.
201        virtual unsigned deviceBlockSize() const
202        { return bus->findBlockSize(); }
203
204    };
205
206    /** the clock speed for the bus */
207    int clock;
208    /** cycles of overhead per transaction */
209    int headerCycles;
210    /** the width of the bus in bytes */
211    int width;
212    /** the next tick at which the bus will be idle */
213    Tick tickNextIdle;
214
215    Event * drainEvent;
216
217    typedef range_map<Addr, PortID>::iterator PortIter;
218    range_map<Addr, PortID> portMap;
219
220    AddrRangeList defaultRange;
221
222    std::vector<SlavePort*> snoopPorts;
223
224    /**
225     * Store the outstanding requests so we can determine which ones
226     * we generated and which ones were merely forwarded. This is used
227     * in the coherent bus when coherency responses come back.
228     */
229    std::set<RequestPtr> outstandingReq;
230
231    /** Function called by the port when the bus is recieving a Timing
232      request packet.*/
233    bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
234
235    /** Function called by the port when the bus is recieving a Timing
236      response packet.*/
237    bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
238
239    /** Function called by the port when the bus is recieving a timing
240        snoop request.*/
241    void recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id);
242
243    /** Function called by the port when the bus is recieving a timing
244        snoop response.*/
245    bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id);
246
247    /**
248     * Forward a timing packet to our snoopers, potentially excluding
249     * one of the connected coherent masters to avoid sending a packet
250     * back to where it came from.
251     *
252     * @param pkt Packet to forward
253     * @param exclude_slave_port_id Id of slave port to exclude
254     */
255    void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id);
256
257    /**
258     * Determine if the bus is to be considered occupied when being
259     * presented with a packet from a specific port. If so, the port
260     * in question is also added to the retry list.
261     *
262     * @param pkt Incoming packet
263     * @param port Source port on the bus presenting the packet
264     *
265     * @return True if the bus is to be considered occupied
266     */
267    bool isOccupied(PacketPtr pkt, Port* port);
268
269    /**
270     * Deal with a destination port accepting a packet by potentially
271     * removing the source port from the retry list (if retrying) and
272     * occupying the bus accordingly.
273     *
274     * @param busy_time Time to spend as a result of a successful send
275     */
276    void succeededTiming(Tick busy_time);
277
278    /** Function called by the port when the bus is recieving a Atomic
279      transaction.*/
280    Tick recvAtomic(PacketPtr pkt, PortID slave_port_id);
281
282    /** Function called by the port when the bus is recieving an
283        atomic snoop transaction.*/
284    Tick recvAtomicSnoop(PacketPtr pkt, PortID master_port_id);
285
286    /**
287     * Forward an atomic packet to our snoopers, potentially excluding
288     * one of the connected coherent masters to avoid sending a packet
289     * back to where it came from.
290     *
291     * @param pkt Packet to forward
292     * @param exclude_slave_port_id Id of slave port to exclude
293     *
294     * @return a pair containing the snoop response and snoop latency
295     */
296    std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
297                                          PortID exclude_slave_port_id);
298
299    /** Function called by the port when the bus is recieving a Functional
300        transaction.*/
301    void recvFunctional(PacketPtr pkt, PortID slave_port_id);
302
303    /** Function called by the port when the bus is recieving a functional
304        snoop transaction.*/
305    void recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id);
306
307    /**
308     * Forward a functional packet to our snoopers, potentially
309     * excluding one of the connected coherent masters to avoid
310     * sending a packet back to where it came from.
311     *
312     * @param pkt Packet to forward
313     * @param exclude_slave_port_id Id of slave port to exclude
314     */
315    void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id);
316
317    /** Timing function called by port when it is once again able to process
318     * requests. */
319    void recvRetry();
320
321    /**
322     * Function called by the port when the bus is recieving a range change.
323     *
324     * @param master_port_id id of the port that received the change
325     */
326    void recvRangeChange(PortID master_port_id);
327
328    /** Find which port connected to this bus (if any) should be given a packet
329     * with this address.
330     * @param addr Address to find port for.
331     * @return id of port that the packet should be sent out of.
332     */
333    PortID findPort(Addr addr);
334
335    // Cache for the findPort function storing recently used ports from portMap
336    struct PortCache {
337        bool valid;
338        PortID id;
339        Addr start;
340        Addr end;
341    };
342
343    PortCache portCache[3];
344
345    // Checks the cache and returns the id of the port that has the requested
346    // address within its range
347    inline PortID checkPortCache(Addr addr) {
348        if (portCache[0].valid && addr >= portCache[0].start &&
349            addr < portCache[0].end) {
350            return portCache[0].id;
351        }
352        if (portCache[1].valid && addr >= portCache[1].start &&
353                   addr < portCache[1].end) {
354            return portCache[1].id;
355        }
356        if (portCache[2].valid && addr >= portCache[2].start &&
357            addr < portCache[2].end) {
358            return portCache[2].id;
359        }
360
361        return InvalidPortID;
362    }
363
364    // Clears the earliest entry of the cache and inserts a new port entry
365    inline void updatePortCache(short id, Addr start, Addr end) {
366        portCache[2].valid = portCache[1].valid;
367        portCache[2].id    = portCache[1].id;
368        portCache[2].start = portCache[1].start;
369        portCache[2].end   = portCache[1].end;
370
371        portCache[1].valid = portCache[0].valid;
372        portCache[1].id    = portCache[0].id;
373        portCache[1].start = portCache[0].start;
374        portCache[1].end   = portCache[0].end;
375
376        portCache[0].valid = true;
377        portCache[0].id    = id;
378        portCache[0].start = start;
379        portCache[0].end   = end;
380    }
381
382    // Clears the cache. Needs to be called in constructor.
383    inline void clearPortCache() {
384        portCache[2].valid = false;
385        portCache[1].valid = false;
386        portCache[0].valid = false;
387    }
388
389    /**
390     * Return the address ranges the bus is responsible for.
391     *
392     * @return a list of non-overlapping address ranges
393     */
394    AddrRangeList getAddrRanges();
395
396    /**
397     * Determine if the bus port is snooping or not.
398     *
399     * @return a boolean indicating if this port is snooping or not
400     */
401    bool isSnooping() const;
402
403    /** Calculate the timing parameters for the packet.  Updates the
404     * firstWordTime and finishTime fields of the packet object.
405     * Returns the tick at which the packet header is completed (which
406     * will be all that is sent if the target rejects the packet).
407     */
408    Tick calcPacketTiming(PacketPtr pkt);
409
410    /** Occupy the bus until until */
411    void occupyBus(Tick until);
412
413    /**
414     * Release the bus after being occupied and return to an idle
415     * state where we proceed to send a retry to any potential waiting
416     * port, or drain if asked to do so.
417     */
418    void releaseBus();
419
420    /**
421     * Send a retry to the port at the head of the retryList. The
422     * caller must ensure that the list is not empty.
423     */
424    void retryWaiting();
425
426    /**
427     * Ask everyone on the bus what their size is
428     *
429     * @return the max of all the sizes
430     */
431    unsigned findBlockSize();
432
433    // event used to schedule a release of the bus
434    EventWrapper<Bus, &Bus::releaseBus> busIdleEvent;
435
436    bool inRetry;
437    std::set<PortID> inRecvRangeChange;
438
439    /** The master and slave ports of the bus */
440    std::vector<SlavePort*> slavePorts;
441    std::vector<MasterPort*> masterPorts;
442
443    typedef std::vector<SlavePort*>::iterator SlavePortIter;
444    typedef std::vector<SlavePort*>::const_iterator SlavePortConstIter;
445
446    /** An array of pointers to ports that retry should be called on because the
447     * original send failed for whatever reason.*/
448    std::list<Port*> retryList;
449
450    void addToRetryList(Port* port)
451    {
452        if (!inRetry) {
453            // The device wasn't retrying a packet, or wasn't at an
454            // appropriate time.
455            retryList.push_back(port);
456        } else {
457            if (!retryList.empty() && port == retryList.front()) {
458                // The device was retrying a packet. It didn't work,
459                // so we'll leave it at the head of the retry list.
460                inRetry = false;
461            } else {
462                // We are in retry, but not for this port, put it at
463                // the end.
464                retryList.push_back(port);
465            }
466        }
467    }
468
469    /** Port that handles requests that don't match any of the interfaces.*/
470    PortID defaultPortID;
471
472    /** If true, use address range provided by default device.  Any
473       address not handled by another port and not in default device's
474       range will cause a fatal error.  If false, just send all
475       addresses not handled by another port to default device. */
476    bool useDefaultRange;
477
478    unsigned defaultBlockSize;
479    unsigned cachedBlockSize;
480    bool cachedBlockSizeValid;
481
482  public:
483
484    /** A function used to return the port associated with this bus object. */
485    virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1);
486    virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1);
487
488    virtual void init();
489    virtual void startup();
490
491    unsigned int drain(Event *de);
492
493    Bus(const BusParams *p);
494};
495
496#endif //__MEM_BUS_HH__
497