xbar.hh revision 3470
1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Ron Dreslinski
29 *          Ali Saidi
30 */
31
32/**
33 * @file
34 * Declaration of a bus object.
35 */
36
37#ifndef __MEM_BUS_HH__
38#define __MEM_BUS_HH__
39
40#include <string>
41#include <list>
42#include <inttypes.h>
43
44#include "base/range.hh"
45#include "mem/mem_object.hh"
46#include "mem/packet.hh"
47#include "mem/port.hh"
48#include "mem/request.hh"
49#include "sim/eventq.hh"
50
51class Bus : public MemObject
52{
53    /** a globally unique id for this bus. */
54    int busId;
55    /** the clock speed for the bus */
56    int clock;
57    /** the width of the bus in bytes */
58    int width;
59    /** the next tick at which the bus will be idle */
60    Tick tickNextIdle;
61
62    Event * drainEvent;
63
64    static const int defaultId = -3; //Make it unique from Broadcast
65
66    struct DevMap {
67        int portId;
68        Range<Addr> range;
69    };
70    std::vector<DevMap> portList;
71    AddrRangeList defaultRange;
72    std::vector<DevMap> portSnoopList;
73
74    /** Function called by the port when the bus is recieving a Timing
75      transaction.*/
76    bool recvTiming(PacketPtr pkt);
77
78    /** Function called by the port when the bus is recieving a Atomic
79      transaction.*/
80    Tick recvAtomic(PacketPtr pkt);
81
82    /** Function called by the port when the bus is recieving a Functional
83        transaction.*/
84    void recvFunctional(PacketPtr pkt);
85
86    /** Timing function called by port when it is once again able to process
87     * requests. */
88    void recvRetry(int id);
89
90    /** Function called by the port when the bus is recieving a status change.*/
91    void recvStatusChange(Port::Status status, int id);
92
93    /** Find which port connected to this bus (if any) should be given a packet
94     * with this address.
95     * @param addr Address to find port for.
96     * @param id Id of the port this packet was received from (to prevent
97     *             loops)
98     * @return pointer to port that the packet should be sent out of.
99     */
100    Port *findPort(Addr addr, int id);
101
102    /** Find all ports with a matching snoop range, except src port.  Keep in mind
103     * that the ranges shouldn't overlap or you will get a double snoop to the same
104     * interface.and the cache will assert out.
105     * @param addr Address to find snoop prts for.
106     * @param id Id of the src port of the request to avoid calling snoop on src
107     * @return vector of IDs to snoop on
108     */
109    std::vector<int> findSnoopPorts(Addr addr, int id);
110
111    /** Snoop all relevant ports atomicly. */
112    Tick atomicSnoop(PacketPtr pkt);
113
114    /** Snoop all relevant ports functionally. */
115    void functionalSnoop(PacketPtr pkt);
116
117    /** Call snoop on caches, be sure to set SNOOP_COMMIT bit if you want
118     * the snoop to happen
119     * @return True if succeds.
120     */
121    bool timingSnoop(PacketPtr pkt);
122
123    /** Process address range request.
124     * @param resp addresses that we can respond to
125     * @param snoop addresses that we would like to snoop
126     * @param id ide of the busport that made the request.
127     */
128    void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id);
129
130    /** Occupy the bus with transmitting the packet pkt */
131    void occupyBus(PacketPtr pkt);
132
133    /** Declaration of the buses port type, one will be instantiated for each
134        of the interfaces connecting to the bus. */
135    class BusPort : public Port
136    {
137        bool _onRetryList;
138
139        /** A pointer to the bus to which this port belongs. */
140        Bus *bus;
141
142        /** A id to keep track of the intercafe ID this port is connected to. */
143        int id;
144
145      public:
146
147        /** Constructor for the BusPort.*/
148        BusPort(const std::string &_name, Bus *_bus, int _id)
149            : Port(_name), _onRetryList(false), bus(_bus), id(_id)
150        { }
151
152        bool onRetryList()
153        { return _onRetryList; }
154
155        void onRetryList(bool newVal)
156        { _onRetryList = newVal; }
157
158      protected:
159
160        /** When reciving a timing request from the peer port (at id),
161            pass it to the bus. */
162        virtual bool recvTiming(PacketPtr pkt)
163        { pkt->setSrc(id); return bus->recvTiming(pkt); }
164
165        /** When reciving a Atomic requestfrom the peer port (at id),
166            pass it to the bus. */
167        virtual Tick recvAtomic(PacketPtr pkt)
168        { pkt->setSrc(id); return bus->recvAtomic(pkt); }
169
170        /** When reciving a Functional requestfrom the peer port (at id),
171            pass it to the bus. */
172        virtual void recvFunctional(PacketPtr pkt)
173        { pkt->setSrc(id); bus->recvFunctional(pkt); }
174
175        /** When reciving a status changefrom the peer port (at id),
176            pass it to the bus. */
177        virtual void recvStatusChange(Status status)
178        { bus->recvStatusChange(status, id); }
179
180        /** When reciving a retry from the peer port (at id),
181            pass it to the bus. */
182        virtual void recvRetry()
183        { bus->recvRetry(id); }
184
185        // This should return all the 'owned' addresses that are
186        // downstream from this bus, yes?  That is, the union of all
187        // the 'owned' address ranges of all the other interfaces on
188        // this bus...
189        virtual void getDeviceAddressRanges(AddrRangeList &resp,
190                                            AddrRangeList &snoop)
191        { bus->addressRanges(resp, snoop, id); }
192
193        // Hack to make translating port work without changes
194        virtual int deviceBlockSize() { return 32; }
195
196    };
197
198    class BusFreeEvent : public Event
199    {
200        Bus * bus;
201
202      public:
203        BusFreeEvent(Bus * _bus);
204        void process();
205        const char *description();
206    };
207
208    BusFreeEvent busIdle;
209
210    bool inRetry;
211
212    /** An array of pointers to the peer port interfaces
213        connected to this bus.*/
214    std::vector<BusPort*> interfaces;
215
216    /** An array of pointers to ports that retry should be called on because the
217     * original send failed for whatever reason.*/
218    std::list<BusPort*> retryList;
219
220    void addToRetryList(BusPort * port)
221    {
222        if (!inRetry) {
223            // The device wasn't retrying a packet, or wasn't at an appropriate
224            // time.
225            assert(!port->onRetryList());
226            port->onRetryList(true);
227            retryList.push_back(port);
228        } else {
229            if (port->onRetryList()) {
230                // The device was retrying a packet. It didn't work, so we'll leave
231                // it at the head of the retry list.
232                assert(port == retryList.front());
233                inRetry = false;
234            }
235            else {
236                port->onRetryList(true);
237                retryList.push_back(port);
238            }
239        }
240    }
241
242    /** Port that handles requests that don't match any of the interfaces.*/
243    BusPort *defaultPort;
244
245  public:
246
247    /** A function used to return the port associated with this bus object. */
248    virtual Port *getPort(const std::string &if_name, int idx = -1);
249
250    virtual void init();
251
252    unsigned int drain(Event *de);
253
254    Bus(const std::string &n, int bus_id, int _clock, int _width)
255        : MemObject(n), busId(bus_id), clock(_clock), width(_width),
256        tickNextIdle(0), busIdle(this), inRetry(false), defaultPort(NULL)
257    {
258        //Both the width and clock period must be positive
259        if (width <= 0)
260            fatal("Bus width must be positive\n");
261        if (clock <= 0)
262            fatal("Bus clock period must be positive\n");
263    }
264
265};
266
267#endif //__MEM_BUS_HH__
268