xbar.cc revision 3074
12686Sksewell@umich.edu/*
22686Sksewell@umich.edu * Copyright (c) 2006 The Regents of The University of Michigan
35268Sksewell@umich.edu * All rights reserved.
45268Sksewell@umich.edu *
55268Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without
65268Sksewell@umich.edu * modification, are permitted provided that the following conditions are
75268Sksewell@umich.edu * met: redistributions of source code must retain the above copyright
85268Sksewell@umich.edu * notice, this list of conditions and the following disclaimer;
95268Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright
105268Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the
115268Sksewell@umich.edu * documentation and/or other materials provided with the distribution;
125268Sksewell@umich.edu * neither the name of the copyright holders nor the names of its
135268Sksewell@umich.edu * contributors may be used to endorse or promote products derived from
145268Sksewell@umich.edu * this software without specific prior written permission.
155268Sksewell@umich.edu *
165268Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175268Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185268Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195268Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205268Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215268Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225268Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235268Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245268Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255268Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265268Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275268Sksewell@umich.edu *
285268Sksewell@umich.edu * Authors: Ali Saidi
295268Sksewell@umich.edu */
305268Sksewell@umich.edu
312706Sksewell@umich.edu/**
322022SN/A * @file
332022SN/A * Definition of a bus object.
342022SN/A */
352022SN/A
362022SN/A
372022SN/A#include "base/misc.hh"
382022SN/A#include "base/trace.hh"
392022SN/A#include "mem/bus.hh"
402022SN/A#include "sim/builder.hh"
412028SN/A
422022SN/APort *
432022SN/ABus::getPort(const std::string &if_name, int idx)
442022SN/A{
452022SN/A    if (if_name == "default")
462028SN/A        if (defaultPort == NULL) {
472022SN/A            defaultPort = new BusPort(csprintf("%s-default",name()), this,
482022SN/A                    defaultId);
492022SN/A            return defaultPort;
502022SN/A        } else
512022SN/A            fatal("Default port already set\n");
525222Sksewell@umich.edu
535222Sksewell@umich.edu    // if_name ignored?  forced to be empty?
545222Sksewell@umich.edu    int id = interfaces.size();
555222Sksewell@umich.edu    BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
565222Sksewell@umich.edu    interfaces.push_back(bp);
575222Sksewell@umich.edu    return bp;
585222Sksewell@umich.edu}
595222Sksewell@umich.edu
605222Sksewell@umich.edu/** Get the ranges of anyone other buses that we are connected to. */
615222Sksewell@umich.eduvoid
625222Sksewell@umich.eduBus::init()
635222Sksewell@umich.edu{
645222Sksewell@umich.edu    std::vector<Port*>::iterator intIter;
655222Sksewell@umich.edu
665222Sksewell@umich.edu    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
675222Sksewell@umich.edu        (*intIter)->sendStatusChange(Port::RangeChange);
685222Sksewell@umich.edu}
692022SN/A
702022SN/A
712022SN/A/** Function called by the port when the bus is receiving a Timing
722022SN/A * transaction.*/
732022SN/Abool
742686Sksewell@umich.eduBus::recvTiming(Packet *pkt)
752022SN/A{
765222Sksewell@umich.edu    Port *port;
775222Sksewell@umich.edu    DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
785222Sksewell@umich.edu            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
795222Sksewell@umich.edu
802022SN/A    short dest = pkt->getDest();
812022SN/A    if (dest == Packet::Broadcast) {
822022SN/A        if ( timingSnoopPhase1(pkt) )
832686Sksewell@umich.edu        {
8410196SCurtis.Dunham@arm.com            timingSnoopPhase2(pkt);
852022SN/A            port = findPort(pkt->getAddr(), pkt->getSrc());
862022SN/A        }
872022SN/A        else
882022SN/A        {
892686Sksewell@umich.edu            //Snoop didn't succeed
902022SN/A            retryList.push_back(interfaces[pkt->getSrc()]);
912022SN/A            return false;
922022SN/A        }
935222Sksewell@umich.edu    } else {
942022SN/A        assert(dest >= 0 && dest < interfaces.size());
955222Sksewell@umich.edu        assert(dest != pkt->getSrc()); // catch infinite loops
965222Sksewell@umich.edu        port = interfaces[dest];
9710474Sandreas.hansson@arm.com    }
985222Sksewell@umich.edu    if (port->sendTiming(pkt))  {
993951Sgblack@eecs.umich.edu        // packet was successfully sent, just return true.
1002022SN/A        return true;
1012022SN/A    }
1022239SN/A
1032239SN/A    // packet not successfully sent
1042022SN/A    retryList.push_back(interfaces[pkt->getSrc()]);
1055222Sksewell@umich.edu    return false;
1065222Sksewell@umich.edu}
1075222Sksewell@umich.edu
1085222Sksewell@umich.eduvoid
10910474Sandreas.hansson@arm.comBus::recvRetry(int id)
1105222Sksewell@umich.edu{
1115222Sksewell@umich.edu    // Go through all the elements on the list calling sendRetry on each
1125222Sksewell@umich.edu    // This is not very efficient at all but it works. Ultimately we should end
1135222Sksewell@umich.edu    // up with something that is more intelligent.
1145222Sksewell@umich.edu    int initialSize = retryList.size();
1155222Sksewell@umich.edu    int i;
116    Port *p;
117
118    for (i = 0; i < initialSize; i++) {
119        assert(retryList.size() > 0);
120        p = retryList.front();
121        retryList.pop_front();
122        p->sendRetry();
123    }
124}
125
126
127Port *
128Bus::findPort(Addr addr, int id)
129{
130    /* An interval tree would be a better way to do this. --ali. */
131    int dest_id = -1;
132    int i = 0;
133    bool found = false;
134    AddrRangeIter iter;
135
136    while (i < portList.size() && !found)
137    {
138        if (portList[i].range == addr) {
139            dest_id = portList[i].portId;
140            found = true;
141            DPRINTF(Bus, "  found addr 0x%llx on device %d\n", addr, dest_id);
142        }
143        i++;
144    }
145
146    // Check if this matches the default range
147    if (dest_id == -1) {
148        for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) {
149            if (*iter == addr) {
150                DPRINTF(Bus, "  found addr 0x%llx on default\n", addr);
151                return defaultPort;
152            }
153        }
154        panic("Unable to find destination for addr: %llx", addr);
155    }
156
157
158    // we shouldn't be sending this back to where it came from
159    assert(dest_id != id);
160
161    return interfaces[dest_id];
162}
163
164std::vector<int>
165Bus::findSnoopPorts(Addr addr, int id)
166{
167    int i = 0;
168    AddrRangeIter iter;
169    std::vector<int> ports;
170
171    while (i < portSnoopList.size())
172    {
173        if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) {
174            //Careful  to not overlap ranges
175            //or snoop will be called more than once on the port
176            ports.push_back(portSnoopList[i].portId);
177            DPRINTF(Bus, "  found snoop addr 0x%llx on device%d\n", addr,
178                    portSnoopList[i].portId);
179        }
180        i++;
181    }
182    return ports;
183}
184
185void
186Bus::atomicSnoop(Packet *pkt)
187{
188    std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
189
190    while (!ports.empty())
191    {
192        interfaces[ports.back()]->sendAtomic(pkt);
193        ports.pop_back();
194    }
195}
196
197bool
198Bus::timingSnoopPhase1(Packet *pkt)
199{
200    std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
201    bool success = true;
202
203    while (!ports.empty() && success)
204    {
205        snoopCallbacks.push_back(ports.back());
206        success = interfaces[ports.back()]->sendTiming(pkt);
207        ports.pop_back();
208    }
209    if (!success)
210    {
211        while (!snoopCallbacks.empty())
212        {
213            interfaces[snoopCallbacks.back()]->sendStatusChange(Port::SnoopSquash);
214            snoopCallbacks.pop_back();
215        }
216        return false;
217    }
218    return true;
219}
220
221void
222Bus::timingSnoopPhase2(Packet *pkt)
223{
224    bool success;
225    pkt->flags |= SNOOP_COMMIT;
226    while (!snoopCallbacks.empty())
227    {
228        success = interfaces[snoopCallbacks.back()]->sendTiming(pkt);
229        //We should not fail on snoop callbacks
230        assert(success);
231        snoopCallbacks.pop_back();
232    }
233}
234
235/** Function called by the port when the bus is receiving a Atomic
236 * transaction.*/
237Tick
238Bus::recvAtomic(Packet *pkt)
239{
240    DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
241            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
242    assert(pkt->getDest() == Packet::Broadcast);
243    atomicSnoop(pkt);
244    return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt);
245}
246
247/** Function called by the port when the bus is receiving a Functional
248 * transaction.*/
249void
250Bus::recvFunctional(Packet *pkt)
251{
252    DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
253            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
254    assert(pkt->getDest() == Packet::Broadcast);
255    findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt);
256}
257
258/** Function called by the port when the bus is receiving a status change.*/
259void
260Bus::recvStatusChange(Port::Status status, int id)
261{
262    AddrRangeList ranges;
263    AddrRangeList snoops;
264    int x;
265    AddrRangeIter iter;
266
267    assert(status == Port::RangeChange &&
268           "The other statuses need to be implemented.");
269
270    DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
271
272    if (id == defaultId) {
273        defaultRange.clear();
274        defaultPort->getPeerAddressRanges(ranges, snoops);
275        assert(snoops.size() == 0);
276        for(iter = ranges.begin(); iter != ranges.end(); iter++) {
277            defaultRange.push_back(*iter);
278            DPRINTF(BusAddrRanges, "Adding range %llx - %llx for default range\n",
279                    iter->start, iter->end);
280        }
281    } else {
282
283        assert((id < interfaces.size() && id >= 0) || id == -1);
284        Port *port = interfaces[id];
285        std::vector<DevMap>::iterator portIter;
286        std::vector<DevMap>::iterator snoopIter;
287
288        // Clean out any previously existent ids
289        for (portIter = portList.begin(); portIter != portList.end(); ) {
290            if (portIter->portId == id)
291                portIter = portList.erase(portIter);
292            else
293                portIter++;
294        }
295
296        for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) {
297            if (snoopIter->portId == id)
298                snoopIter = portSnoopList.erase(snoopIter);
299            else
300                snoopIter++;
301        }
302
303        port->getPeerAddressRanges(ranges, snoops);
304
305        for(iter = snoops.begin(); iter != snoops.end(); iter++) {
306            DevMap dm;
307            dm.portId = id;
308            dm.range = *iter;
309
310            DPRINTF(BusAddrRanges, "Adding snoop range %llx - %llx for id %d\n",
311                    dm.range.start, dm.range.end, id);
312            portSnoopList.push_back(dm);
313        }
314
315        for(iter = ranges.begin(); iter != ranges.end(); iter++) {
316            DevMap dm;
317            dm.portId = id;
318            dm.range = *iter;
319
320            DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n",
321                    dm.range.start, dm.range.end, id);
322            portList.push_back(dm);
323        }
324    }
325    DPRINTF(MMU, "port list has %d entries\n", portList.size());
326
327    // tell all our peers that our address range has changed.
328    // Don't tell the device that caused this change, it already knows
329    for (x = 0; x < interfaces.size(); x++)
330        if (x != id)
331            interfaces[x]->sendStatusChange(Port::RangeChange);
332
333    if (id != defaultId && defaultPort)
334        defaultPort->sendStatusChange(Port::RangeChange);
335}
336
337void
338Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
339{
340    std::vector<DevMap>::iterator portIter;
341    AddrRangeIter dflt_iter;
342    bool subset;
343
344    resp.clear();
345    snoop.clear();
346
347    DPRINTF(BusAddrRanges, "received address range request, returning:\n");
348
349    for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
350            dflt_iter++) {
351        resp.push_back(*dflt_iter);
352        DPRINTF(BusAddrRanges, "  -- %#llX : %#llX\n",dflt_iter->start,
353                dflt_iter->end);
354    }
355    for (portIter = portList.begin(); portIter != portList.end(); portIter++) {
356        subset = false;
357        for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
358                dflt_iter++) {
359            if ((portIter->range.start < dflt_iter->start &&
360                portIter->range.end >= dflt_iter->start) ||
361               (portIter->range.start < dflt_iter->end &&
362                portIter->range.end >= dflt_iter->end))
363                fatal("Devices can not set ranges that itersect the default set\
364                        but are not a subset of the default set.\n");
365            if (portIter->range.start >= dflt_iter->start &&
366                portIter->range.end <= dflt_iter->end) {
367                subset = true;
368                DPRINTF(BusAddrRanges, "  -- %#llX : %#llX is a SUBSET\n",
369                    portIter->range.start, portIter->range.end);
370            }
371        }
372        if (portIter->portId != id && !subset) {
373            resp.push_back(portIter->range);
374            DPRINTF(BusAddrRanges, "  -- %#llX : %#llX\n",
375                    portIter->range.start, portIter->range.end);
376        }
377    }
378}
379
380BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
381
382    Param<int> bus_id;
383
384END_DECLARE_SIM_OBJECT_PARAMS(Bus)
385
386BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
387    INIT_PARAM(bus_id, "a globally unique bus id")
388END_INIT_SIM_OBJECT_PARAMS(Bus)
389
390CREATE_SIM_OBJECT(Bus)
391{
392    return new Bus(getInstanceName(), bus_id);
393}
394
395REGISTER_SIM_OBJECT("Bus", Bus)
396