xbar.hh revision 7523
1865SN/A/*
21762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
3865SN/A * All rights reserved.
4865SN/A *
5865SN/A * Redistribution and use in source and binary forms, with or without
6865SN/A * modification, are permitted provided that the following conditions are
7865SN/A * met: redistributions of source code must retain the above copyright
8865SN/A * notice, this list of conditions and the following disclaimer;
9865SN/A * redistributions in binary form must reproduce the above copyright
10865SN/A * notice, this list of conditions and the following disclaimer in the
11865SN/A * documentation and/or other materials provided with the distribution;
12865SN/A * neither the name of the copyright holders nor the names of its
13865SN/A * contributors may be used to endorse or promote products derived from
14865SN/A * this software without specific prior written permission.
15865SN/A *
16865SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17865SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18865SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19865SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20865SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21865SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22865SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23865SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24865SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25865SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26865SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Ron Dreslinski
292665Ssaidi@eecs.umich.edu *          Ali Saidi
30865SN/A */
31865SN/A
32865SN/A/**
33865SN/A * @file
34865SN/A * Declaration of a bus object.
35865SN/A */
36865SN/A
372107SN/A#ifndef __MEM_BUS_HH__
38865SN/A#define __MEM_BUS_HH__
392542SN/A
402542SN/A#include <string>
411634SN/A#include <set>
421634SN/A#include <list>
431634SN/A
441634SN/A#include "base/hashmap.hh"
451634SN/A#include "base/range.hh"
461634SN/A#include "base/range_map.hh"
471634SN/A#include "base/types.hh"
481149SN/A#include "mem/mem_object.hh"
491149SN/A#include "mem/packet.hh"
501149SN/A#include "mem/port.hh"
511149SN/A#include "mem/request.hh"
521149SN/A#include "params/Bus.hh"
531149SN/A#include "sim/eventq.hh"
541149SN/A
551149SN/Aclass Bus : public MemObject
561149SN/A{
571149SN/A    /** Declaration of the buses port type, one will be instantiated for each
581149SN/A        of the interfaces connecting to the bus. */
591149SN/A    class BusPort : public Port
601149SN/A    {
611149SN/A        bool _onRetryList;
621149SN/A
631149SN/A        /** A pointer to the bus to which this port belongs. */
641149SN/A        Bus *bus;
651149SN/A
66865SN/A        /** A id to keep track of the intercafe ID this port is connected to. */
67865SN/A        int id;
68
69      public:
70
71        /** Constructor for the BusPort.*/
72        BusPort(const std::string &_name, Bus *_bus, int _id)
73            : Port(_name, _bus), _onRetryList(false), bus(_bus), id(_id)
74        { }
75
76        bool onRetryList()
77        { return _onRetryList; }
78
79        void onRetryList(bool newVal)
80        { _onRetryList = newVal; }
81
82        int getId() { return id; }
83
84      protected:
85
86        /** When reciving a timing request from the peer port (at id),
87            pass it to the bus. */
88        virtual bool recvTiming(PacketPtr pkt)
89        { pkt->setSrc(id); return bus->recvTiming(pkt); }
90
91        /** When reciving a Atomic requestfrom the peer port (at id),
92            pass it to the bus. */
93        virtual Tick recvAtomic(PacketPtr pkt)
94        { pkt->setSrc(id); return bus->recvAtomic(pkt); }
95
96        /** When reciving a Functional requestfrom the peer port (at id),
97            pass it to the bus. */
98        virtual void recvFunctional(PacketPtr pkt)
99        { pkt->setSrc(id); bus->recvFunctional(pkt); }
100
101        /** When reciving a status changefrom the peer port (at id),
102            pass it to the bus. */
103        virtual void recvStatusChange(Status status)
104        { bus->recvStatusChange(status, id); }
105
106        /** When reciving a retry from the peer port (at id),
107            pass it to the bus. */
108        virtual void recvRetry()
109        { bus->recvRetry(id); }
110
111        // This should return all the 'owned' addresses that are
112        // downstream from this bus, yes?  That is, the union of all
113        // the 'owned' address ranges of all the other interfaces on
114        // this bus...
115        virtual void getDeviceAddressRanges(AddrRangeList &resp,
116                                            bool &snoop)
117        { bus->addressRanges(resp, snoop, id); }
118
119        // Ask the bus to ask everyone on the bus what their block size is and
120        // take the max of it. This might need to be changed a bit if we ever
121        // support multiple block sizes.
122        virtual unsigned deviceBlockSize() const
123        { return bus->findBlockSize(id); }
124
125    };
126
127    class BusFreeEvent : public Event
128    {
129        Bus * bus;
130
131      public:
132        BusFreeEvent(Bus * _bus);
133        void process();
134        const char *description() const;
135    };
136
137    /** a globally unique id for this bus. */
138    int busId;
139    /** the clock speed for the bus */
140    int clock;
141    /** cycles of overhead per transaction */
142    int headerCycles;
143    /** the width of the bus in bytes */
144    int width;
145    /** the next tick at which the bus will be idle */
146    Tick tickNextIdle;
147
148    Event * drainEvent;
149
150
151    static const int defaultId = -3; //Make it unique from Broadcast
152
153    typedef range_map<Addr,int>::iterator PortIter;
154    range_map<Addr, int> portMap;
155
156    AddrRangeList defaultRange;
157
158    typedef std::vector<BusPort*>::iterator SnoopIter;
159    std::vector<BusPort*> snoopPorts;
160
161    /** Function called by the port when the bus is recieving a Timing
162      transaction.*/
163    bool recvTiming(PacketPtr pkt);
164
165    /** Function called by the port when the bus is recieving a Atomic
166      transaction.*/
167    Tick recvAtomic(PacketPtr pkt);
168
169    /** Function called by the port when the bus is recieving a Functional
170        transaction.*/
171    void recvFunctional(PacketPtr pkt);
172
173    /** Timing function called by port when it is once again able to process
174     * requests. */
175    void recvRetry(int id);
176
177    /** Function called by the port when the bus is recieving a status change.*/
178    void recvStatusChange(Port::Status status, int id);
179
180    /** Find which port connected to this bus (if any) should be given a packet
181     * with this address.
182     * @param addr Address to find port for.
183     * @return id of port that the packet should be sent out of.
184     */
185    int findPort(Addr addr);
186
187    // Cache for the findPort function storing recently used ports from portMap
188    struct PortCache {
189        bool valid;
190        int  id;
191        Addr start;
192        Addr end;
193    };
194
195    PortCache portCache[3];
196
197    // Checks the cache and returns the id of the port that has the requested
198    // address within its range
199    inline int checkPortCache(Addr addr) {
200        if (portCache[0].valid && addr >= portCache[0].start &&
201            addr < portCache[0].end) {
202            return portCache[0].id;
203        }
204        if (portCache[1].valid && addr >= portCache[1].start &&
205                   addr < portCache[1].end) {
206            return portCache[1].id;
207        }
208        if (portCache[2].valid && addr >= portCache[2].start &&
209            addr < portCache[2].end) {
210            return portCache[2].id;
211        }
212
213        return -1;
214    }
215
216    // Clears the earliest entry of the cache and inserts a new port entry
217    inline void updatePortCache(short id, Addr start, Addr end) {
218        portCache[2].valid = portCache[1].valid;
219        portCache[2].id    = portCache[1].id;
220        portCache[2].start = portCache[1].start;
221        portCache[2].end   = portCache[1].end;
222
223        portCache[1].valid = portCache[0].valid;
224        portCache[1].id    = portCache[0].id;
225        portCache[1].start = portCache[0].start;
226        portCache[1].end   = portCache[0].end;
227
228        portCache[0].valid = true;
229        portCache[0].id    = id;
230        portCache[0].start = start;
231        portCache[0].end   = end;
232    }
233
234    // Clears the cache. Needs to be called in constructor.
235    inline void clearPortCache() {
236        portCache[2].valid = false;
237        portCache[1].valid = false;
238        portCache[0].valid = false;
239    }
240
241    /** Process address range request.
242     * @param resp addresses that we can respond to
243     * @param snoop addresses that we would like to snoop
244     * @param id ide of the busport that made the request.
245     */
246    void addressRanges(AddrRangeList &resp, bool &snoop, int id);
247
248    /** Calculate the timing parameters for the packet.  Updates the
249     * firstWordTime and finishTime fields of the packet object.
250     * Returns the tick at which the packet header is completed (which
251     * will be all that is sent if the target rejects the packet).
252     */
253    Tick calcPacketTiming(PacketPtr pkt);
254
255    /** Occupy the bus until until */
256    void occupyBus(Tick until);
257
258    /** Ask everyone on the bus what their size is
259     * @param id id of the busport that made the request
260     * @return the max of all the sizes
261     */
262    unsigned findBlockSize(int id);
263
264    BusFreeEvent busIdle;
265
266    bool inRetry;
267    std::set<int> inRecvStatusChange;
268
269    /** max number of bus ids we've handed out so far */
270    short maxId;
271
272    /** An array of pointers to the peer port interfaces
273        connected to this bus.*/
274    m5::hash_map<short,BusPort*> interfaces;
275
276    /** An array of pointers to ports that retry should be called on because the
277     * original send failed for whatever reason.*/
278    std::list<BusPort*> retryList;
279
280    void addToRetryList(BusPort * port)
281    {
282        if (!inRetry) {
283            // The device wasn't retrying a packet, or wasn't at an appropriate
284            // time.
285            assert(!port->onRetryList());
286            port->onRetryList(true);
287            retryList.push_back(port);
288        } else {
289            if (port->onRetryList()) {
290                // The device was retrying a packet. It didn't work, so we'll leave
291                // it at the head of the retry list.
292                assert(port == retryList.front());
293                inRetry = false;
294            }
295            else {
296                port->onRetryList(true);
297                retryList.push_back(port);
298            }
299        }
300    }
301
302    /** Port that handles requests that don't match any of the interfaces.*/
303    BusPort *defaultPort;
304
305    BusPort *funcPort;
306    int funcPortId;
307
308    /** If true, use address range provided by default device.  Any
309       address not handled by another port and not in default device's
310       range will cause a fatal error.  If false, just send all
311       addresses not handled by another port to default device. */
312    bool useDefaultRange;
313
314    unsigned defaultBlockSize;
315    unsigned cachedBlockSize;
316    bool cachedBlockSizeValid;
317
318   // Cache for the peer port interfaces
319    struct BusCache {
320        bool  valid;
321        short id;
322        BusPort  *port;
323    };
324
325    BusCache busCache[3];
326
327    // Checks the peer port interfaces cache for the port id and returns
328    // a pointer to the matching port
329    inline BusPort* checkBusCache(short id) {
330        if (busCache[0].valid && id == busCache[0].id) {
331            return busCache[0].port;
332        }
333        if (busCache[1].valid && id == busCache[1].id) {
334            return busCache[1].port;
335        }
336        if (busCache[2].valid && id == busCache[2].id) {
337            return busCache[2].port;
338        }
339
340        return NULL;
341    }
342
343    // Replaces the earliest entry in the cache with a new entry
344    inline void updateBusCache(short id, BusPort *port) {
345        busCache[2].valid = busCache[1].valid;
346        busCache[2].id    = busCache[1].id;
347        busCache[2].port  = busCache[1].port;
348
349        busCache[1].valid = busCache[0].valid;
350        busCache[1].id    = busCache[0].id;
351        busCache[1].port  = busCache[0].port;
352
353        busCache[0].valid = true;
354        busCache[0].id    = id;
355        busCache[0].port  = port;
356    }
357
358    // Invalidates the cache. Needs to be called in constructor.
359    inline void clearBusCache() {
360        busCache[2].valid = false;
361        busCache[1].valid = false;
362        busCache[0].valid = false;
363    }
364
365
366  public:
367
368    /** A function used to return the port associated with this bus object. */
369    virtual Port *getPort(const std::string &if_name, int idx = -1);
370    virtual void deletePortRefs(Port *p);
371
372    virtual void init();
373    virtual void startup();
374
375    unsigned int drain(Event *de);
376
377    Bus(const BusParams *p);
378};
379
380#endif //__MEM_BUS_HH__
381