xbar.cc revision 9547
14120Sgblack@eecs.umich.edu/*
24120Sgblack@eecs.umich.edu * Copyright (c) 2011-2013 ARM Limited
37087Snate@binkert.org * All rights reserved
47087Snate@binkert.org *
57087Snate@binkert.org * The license below extends only to copyright in the software and shall
67087Snate@binkert.org * not be construed as granting a license to any other intellectual
77087Snate@binkert.org * property including but not limited to intellectual property relating
87087Snate@binkert.org * to a hardware implementation of the functionality of the software
97087Snate@binkert.org * licensed hereunder.  You may use the software subject to the license
107087Snate@binkert.org * terms below provided that you ensure that this notice is replicated
117087Snate@binkert.org * unmodified and in its entirety in all distributions of the software,
127087Snate@binkert.org * modified or unmodified, in source code or in binary form.
137087Snate@binkert.org *
147087Snate@binkert.org * Copyright (c) 2006 The Regents of The University of Michigan
154120Sgblack@eecs.umich.edu * All rights reserved.
164120Sgblack@eecs.umich.edu *
174120Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
184120Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
194120Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
204120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
214120Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
224120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
234120Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
244120Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
254120Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
264120Sgblack@eecs.umich.edu * this software without specific prior written permission.
274120Sgblack@eecs.umich.edu *
284120Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
294120Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
304120Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
314120Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
324120Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
334120Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
344120Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
354120Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
364120Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
374120Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
384120Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
394120Sgblack@eecs.umich.edu *
404120Sgblack@eecs.umich.edu * Authors: Ali Saidi
414120Sgblack@eecs.umich.edu *          Andreas Hansson
424120Sgblack@eecs.umich.edu *          William Wang
434202Sbinkertn@umich.edu */
445069Sgblack@eecs.umich.edu
454202Sbinkertn@umich.edu/**
465659Sgblack@eecs.umich.edu * @file
479022Sgblack@eecs.umich.edu * Definition of a bus object.
489023Sgblack@eecs.umich.edu */
494601Sgblack@eecs.umich.edu
505124Sgblack@eecs.umich.edu#include "base/misc.hh"
517966Sgblack@eecs.umich.edu#include "base/trace.hh"
525083Sgblack@eecs.umich.edu#include "debug/Bus.hh"
534679Sgblack@eecs.umich.edu#include "debug/BusAddrRanges.hh"
546515Sgblack@eecs.umich.edu#include "debug/Drain.hh"
555083Sgblack@eecs.umich.edu#include "mem/bus.hh"
564679Sgblack@eecs.umich.edu
574679Sgblack@eecs.umich.eduBaseBus::BaseBus(const BaseBusParams *p)
588745Sgblack@eecs.umich.edu    : MemObject(p),
596313Sgblack@eecs.umich.edu      headerCycles(p->header_cycles), width(p->width),
608771Sgblack@eecs.umich.edu      gotAddrRanges(p->port_default_connection_count +
618771Sgblack@eecs.umich.edu                          p->port_master_connection_count, false),
628771Sgblack@eecs.umich.edu      gotAllAddrRanges(false), defaultPortID(InvalidPortID),
638771Sgblack@eecs.umich.edu      useDefaultRange(p->use_default_range),
646365Sgblack@eecs.umich.edu      blockSize(p->block_size)
655124Sgblack@eecs.umich.edu{}
668752Sgblack@eecs.umich.edu
678771Sgblack@eecs.umich.eduBaseBus::~BaseBus()
684202Sbinkertn@umich.edu{
698771Sgblack@eecs.umich.edu    for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end();
708771Sgblack@eecs.umich.edu         ++m) {
714997Sgblack@eecs.umich.edu        delete *m;
727624Sgblack@eecs.umich.edu    }
735135Sgblack@eecs.umich.edu
748753Sgblack@eecs.umich.edu    for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end();
754997Sgblack@eecs.umich.edu         ++s) {
769384SAndreas.Sandberg@arm.com        delete *s;
778745Sgblack@eecs.umich.edu    }
786365Sgblack@eecs.umich.edu}
798771Sgblack@eecs.umich.edu
808740Sgblack@eecs.umich.eduvoid
816365Sgblack@eecs.umich.eduBaseBus::init()
828740Sgblack@eecs.umich.edu{
838745Sgblack@eecs.umich.edu    // determine the maximum peer block size, look at both the
848752Sgblack@eecs.umich.edu    // connected master and slave modules
858752Sgblack@eecs.umich.edu    uint32_t peer_block_size = 0;
869023Sgblack@eecs.umich.edu
878335Snate@binkert.org    for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end();
884120Sgblack@eecs.umich.edu         ++m) {
895069Sgblack@eecs.umich.edu        peer_block_size = std::max((*m)->peerBlockSize(), peer_block_size);
905081Sgblack@eecs.umich.edu    }
915081Sgblack@eecs.umich.edu
925081Sgblack@eecs.umich.edu    for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end();
935081Sgblack@eecs.umich.edu         ++s) {
945081Sgblack@eecs.umich.edu        peer_block_size = std::max((*s)->peerBlockSize(), peer_block_size);
955081Sgblack@eecs.umich.edu    }
965081Sgblack@eecs.umich.edu
975081Sgblack@eecs.umich.edu    // if the peers do not have a block size, use the default value
985081Sgblack@eecs.umich.edu    // set through the bus parameters
995081Sgblack@eecs.umich.edu    if (peer_block_size != 0)
1005081Sgblack@eecs.umich.edu        blockSize = peer_block_size;
1015081Sgblack@eecs.umich.edu
1025081Sgblack@eecs.umich.edu    // check if the block size is a value known to work
1035081Sgblack@eecs.umich.edu    if (!(blockSize == 16 || blockSize == 32 || blockSize == 64 ||
1045081Sgblack@eecs.umich.edu          blockSize == 128))
1055081Sgblack@eecs.umich.edu        warn_once("Block size is neither 16, 32, 64 or 128 bytes.\n");
1065081Sgblack@eecs.umich.edu}
1075081Sgblack@eecs.umich.edu
1085081Sgblack@eecs.umich.eduBaseMasterPort &
1095081Sgblack@eecs.umich.eduBaseBus::getMasterPort(const std::string &if_name, PortID idx)
1105081Sgblack@eecs.umich.edu{
1115081Sgblack@eecs.umich.edu    if (if_name == "master" && idx < masterPorts.size()) {
1125081Sgblack@eecs.umich.edu        // the master port index translates directly to the vector position
1135081Sgblack@eecs.umich.edu        return *masterPorts[idx];
1145081Sgblack@eecs.umich.edu    } else  if (if_name == "default") {
1155081Sgblack@eecs.umich.edu        return *masterPorts[defaultPortID];
1165081Sgblack@eecs.umich.edu    } else {
1175081Sgblack@eecs.umich.edu        return MemObject::getMasterPort(if_name, idx);
1185081Sgblack@eecs.umich.edu    }
1195081Sgblack@eecs.umich.edu}
1205081Sgblack@eecs.umich.edu
1215081Sgblack@eecs.umich.eduBaseSlavePort &
1225081Sgblack@eecs.umich.eduBaseBus::getSlavePort(const std::string &if_name, PortID idx)
1235081Sgblack@eecs.umich.edu{
1245081Sgblack@eecs.umich.edu    if (if_name == "slave" && idx < slavePorts.size()) {
1255081Sgblack@eecs.umich.edu        // the slave port index translates directly to the vector position
1265081Sgblack@eecs.umich.edu        return *slavePorts[idx];
1275081Sgblack@eecs.umich.edu    } else {
1285081Sgblack@eecs.umich.edu        return MemObject::getSlavePort(if_name, idx);
1295081Sgblack@eecs.umich.edu    }
1305081Sgblack@eecs.umich.edu}
1315081Sgblack@eecs.umich.edu
1325081Sgblack@eecs.umich.eduvoid
1335081Sgblack@eecs.umich.eduBaseBus::calcPacketTiming(PacketPtr pkt)
1345081Sgblack@eecs.umich.edu{
1355081Sgblack@eecs.umich.edu    // the bus will be called at a time that is not necessarily
1365081Sgblack@eecs.umich.edu    // coinciding with its own clock, so start by determining how long
1375081Sgblack@eecs.umich.edu    // until the next clock edge (could be zero)
1385081Sgblack@eecs.umich.edu    Tick offset = nextCycle() - curTick();
1395081Sgblack@eecs.umich.edu
1405081Sgblack@eecs.umich.edu    // determine how many cycles are needed to send the data
1415081Sgblack@eecs.umich.edu    unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0;
1425081Sgblack@eecs.umich.edu
1435081Sgblack@eecs.umich.edu    // The first word will be delivered on the cycle after the header.
1445081Sgblack@eecs.umich.edu    pkt->busFirstWordDelay = (headerCycles + 1) * clockPeriod() + offset;
1455680Sgblack@eecs.umich.edu
1465081Sgblack@eecs.umich.edu    // Note that currently busLastWordDelay can be smaller than
1475933Sgblack@eecs.umich.edu    // busFirstWordDelay if the packet has no data
1485173Sgblack@eecs.umich.edu    pkt->busLastWordDelay = (headerCycles + dataCycles) * clockPeriod() +
1495359Sgblack@eecs.umich.edu        offset;
1505081Sgblack@eecs.umich.edu}
1515149Sgblack@eecs.umich.edu
1525298Sgblack@eecs.umich.edutemplate <typename PortClass>
1535081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name) :
1545081Sgblack@eecs.umich.edu    Drainable(),
1555081Sgblack@eecs.umich.edu    bus(_bus), _name(_name), state(IDLE), drainManager(NULL),
1565081Sgblack@eecs.umich.edu    releaseEvent(this)
1575081Sgblack@eecs.umich.edu{
1585081Sgblack@eecs.umich.edu}
1595081Sgblack@eecs.umich.edu
1605081Sgblack@eecs.umich.edutemplate <typename PortClass>
1615081Sgblack@eecs.umich.eduvoid BaseBus::Layer<PortClass>::occupyLayer(Tick until)
1625081Sgblack@eecs.umich.edu{
1635081Sgblack@eecs.umich.edu    // ensure the state is busy or in retry and never idle at this
1645081Sgblack@eecs.umich.edu    // point, as the bus should transition from idle as soon as it has
1655081Sgblack@eecs.umich.edu    // decided to forward the packet to prevent any follow-on calls to
1665081Sgblack@eecs.umich.edu    // sendTiming seeing an unoccupied bus
1675081Sgblack@eecs.umich.edu    assert(state != IDLE);
1685081Sgblack@eecs.umich.edu
1695081Sgblack@eecs.umich.edu    // note that we do not change the bus state here, if we are going
1705081Sgblack@eecs.umich.edu    // from idle to busy it is handled by tryTiming, and if we
1715081Sgblack@eecs.umich.edu    // are in retry we should remain in retry such that
1725081Sgblack@eecs.umich.edu    // succeededTiming still sees the accurate state
1735081Sgblack@eecs.umich.edu
1745081Sgblack@eecs.umich.edu    // until should never be 0 as express snoops never occupy the bus
1755081Sgblack@eecs.umich.edu    assert(until != 0);
1765081Sgblack@eecs.umich.edu    bus.schedule(releaseEvent, until);
1775081Sgblack@eecs.umich.edu
1785081Sgblack@eecs.umich.edu    DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n",
1795081Sgblack@eecs.umich.edu            curTick(), until);
1805081Sgblack@eecs.umich.edu}
1815081Sgblack@eecs.umich.edu
1825081Sgblack@eecs.umich.edutemplate <typename PortClass>
1835081Sgblack@eecs.umich.edubool
1845081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::tryTiming(PortClass* port)
1855081Sgblack@eecs.umich.edu{
1865081Sgblack@eecs.umich.edu    // first we see if the bus is busy, next we check if we are in a
1875081Sgblack@eecs.umich.edu    // retry with a port other than the current one
1885081Sgblack@eecs.umich.edu    if (state == BUSY || (state == RETRY && port != retryList.front())) {
1895081Sgblack@eecs.umich.edu        // put the port at the end of the retry list
1905081Sgblack@eecs.umich.edu        retryList.push_back(port);
1915081Sgblack@eecs.umich.edu        return false;
1925081Sgblack@eecs.umich.edu    }
1935081Sgblack@eecs.umich.edu
1945081Sgblack@eecs.umich.edu    // update the state which is shared for request, response and
1955081Sgblack@eecs.umich.edu    // snoop responses, if we were idle we are now busy, if we are in
1965081Sgblack@eecs.umich.edu    // a retry, then do not change
1975081Sgblack@eecs.umich.edu    if (state == IDLE)
1985081Sgblack@eecs.umich.edu        state = BUSY;
1995081Sgblack@eecs.umich.edu
2005081Sgblack@eecs.umich.edu    return true;
2015081Sgblack@eecs.umich.edu}
2025081Sgblack@eecs.umich.edu
2035081Sgblack@eecs.umich.edutemplate <typename PortClass>
2045081Sgblack@eecs.umich.eduvoid
2055081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::succeededTiming(Tick busy_time)
2065081Sgblack@eecs.umich.edu{
2075081Sgblack@eecs.umich.edu    // if a retrying port succeeded, also take it off the retry list
2085081Sgblack@eecs.umich.edu    if (state == RETRY) {
2095081Sgblack@eecs.umich.edu        DPRINTF(BaseBus, "Remove retry from list %s\n",
2105081Sgblack@eecs.umich.edu                retryList.front()->name());
2115081Sgblack@eecs.umich.edu        retryList.pop_front();
2125081Sgblack@eecs.umich.edu        state = BUSY;
2135081Sgblack@eecs.umich.edu    }
2145081Sgblack@eecs.umich.edu
2155081Sgblack@eecs.umich.edu    // we should either have gone from idle to busy in the
2165081Sgblack@eecs.umich.edu    // tryTiming test, or just gone from a retry to busy
2175081Sgblack@eecs.umich.edu    assert(state == BUSY);
2185081Sgblack@eecs.umich.edu
2195081Sgblack@eecs.umich.edu    // occupy the bus accordingly
2205081Sgblack@eecs.umich.edu    occupyLayer(busy_time);
2215081Sgblack@eecs.umich.edu}
2225081Sgblack@eecs.umich.edu
2235081Sgblack@eecs.umich.edutemplate <typename PortClass>
2245081Sgblack@eecs.umich.eduvoid
2255081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time)
2265081Sgblack@eecs.umich.edu{
2275081Sgblack@eecs.umich.edu    // if we are not in a retry, i.e. busy (but never idle), or we are
2285081Sgblack@eecs.umich.edu    // in a retry but not for the current port, then add the port at
2295081Sgblack@eecs.umich.edu    // the end of the retry list
2305081Sgblack@eecs.umich.edu    if (state != RETRY || port != retryList.front()) {
2315081Sgblack@eecs.umich.edu        retryList.push_back(port);
2325081Sgblack@eecs.umich.edu    }
2335081Sgblack@eecs.umich.edu
2345081Sgblack@eecs.umich.edu    // even if we retried the current one and did not succeed,
2355081Sgblack@eecs.umich.edu    // we are no longer retrying but instead busy
2365081Sgblack@eecs.umich.edu    state = BUSY;
2375081Sgblack@eecs.umich.edu
2385081Sgblack@eecs.umich.edu    // occupy the bus accordingly
2395081Sgblack@eecs.umich.edu    occupyLayer(busy_time);
2405081Sgblack@eecs.umich.edu}
2415081Sgblack@eecs.umich.edu
2425081Sgblack@eecs.umich.edutemplate <typename PortClass>
2435081Sgblack@eecs.umich.eduvoid
2445081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::releaseLayer()
2455081Sgblack@eecs.umich.edu{
2465081Sgblack@eecs.umich.edu    // releasing the bus means we should now be idle
2475081Sgblack@eecs.umich.edu    assert(state == BUSY);
2485081Sgblack@eecs.umich.edu    assert(!releaseEvent.scheduled());
2495081Sgblack@eecs.umich.edu
2505081Sgblack@eecs.umich.edu    // update the state
2515081Sgblack@eecs.umich.edu    state = IDLE;
2525081Sgblack@eecs.umich.edu
2535081Sgblack@eecs.umich.edu    // bus is now idle, so if someone is waiting we can retry
2545081Sgblack@eecs.umich.edu    if (!retryList.empty()) {
2555081Sgblack@eecs.umich.edu        // note that we block (return false on recvTiming) both
2565081Sgblack@eecs.umich.edu        // because the bus is busy and because the destination is
2575081Sgblack@eecs.umich.edu        // busy, and in the latter case the bus may be released before
2585081Sgblack@eecs.umich.edu        // we see a retry from the destination
2595081Sgblack@eecs.umich.edu        retryWaiting();
2605081Sgblack@eecs.umich.edu    } else if (drainManager) {
2615081Sgblack@eecs.umich.edu        DPRINTF(Drain, "Bus done draining, signaling drain manager\n");
2625081Sgblack@eecs.umich.edu        //If we weren't able to drain before, do it now.
2635081Sgblack@eecs.umich.edu        drainManager->signalDrainDone();
2645081Sgblack@eecs.umich.edu        // Clear the drain event once we're done with it.
2655081Sgblack@eecs.umich.edu        drainManager = NULL;
2665081Sgblack@eecs.umich.edu    }
2675081Sgblack@eecs.umich.edu}
2685081Sgblack@eecs.umich.edu
2695081Sgblack@eecs.umich.edutemplate <typename PortClass>
2705081Sgblack@eecs.umich.eduvoid
2715081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::retryWaiting()
2725081Sgblack@eecs.umich.edu{
2735081Sgblack@eecs.umich.edu    // this should never be called with an empty retry list
2745081Sgblack@eecs.umich.edu    assert(!retryList.empty());
2755081Sgblack@eecs.umich.edu
2765081Sgblack@eecs.umich.edu    // we always go to retrying from idle
2775081Sgblack@eecs.umich.edu    assert(state == IDLE);
2785081Sgblack@eecs.umich.edu
2795081Sgblack@eecs.umich.edu    // update the state which is shared for request, response and
2805081Sgblack@eecs.umich.edu    // snoop responses
2815081Sgblack@eecs.umich.edu    state = RETRY;
2825081Sgblack@eecs.umich.edu
2835081Sgblack@eecs.umich.edu    // note that we might have blocked on the receiving port being
2845081Sgblack@eecs.umich.edu    // busy (rather than the bus itself) and now call retry before the
2855081Sgblack@eecs.umich.edu    // destination called retry on the bus
2865081Sgblack@eecs.umich.edu    retryList.front()->sendRetry();
2875081Sgblack@eecs.umich.edu
2885081Sgblack@eecs.umich.edu    // If the bus is still in the retry state, sendTiming wasn't
2895081Sgblack@eecs.umich.edu    // called in zero time (e.g. the cache does this)
2905081Sgblack@eecs.umich.edu    if (state == RETRY) {
2915081Sgblack@eecs.umich.edu        retryList.pop_front();
2925081Sgblack@eecs.umich.edu
2935081Sgblack@eecs.umich.edu        //Burn a cycle for the missed grant.
2945081Sgblack@eecs.umich.edu
2955081Sgblack@eecs.umich.edu        // update the state which is shared for request, response and
2965081Sgblack@eecs.umich.edu        // snoop responses
2975081Sgblack@eecs.umich.edu        state = BUSY;
2985081Sgblack@eecs.umich.edu
2995081Sgblack@eecs.umich.edu        // occupy the bus layer until the next cycle ends
3005081Sgblack@eecs.umich.edu        occupyLayer(bus.clockEdge(Cycles(1)));
3015081Sgblack@eecs.umich.edu    }
3025081Sgblack@eecs.umich.edu}
3035081Sgblack@eecs.umich.edu
3045081Sgblack@eecs.umich.edutemplate <typename PortClass>
3055081Sgblack@eecs.umich.eduvoid
3065081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::recvRetry()
3075081Sgblack@eecs.umich.edu{
3085069Sgblack@eecs.umich.edu    // we got a retry from a peer that we tried to send something to
3094202Sbinkertn@umich.edu    // and failed, but we sent it on the account of someone else, and
3104202Sbinkertn@umich.edu    // that source port should be on our retry list, however if the
3114202Sbinkertn@umich.edu    // bus layer is released before this happens and the retry (from
3125069Sgblack@eecs.umich.edu    // the bus point of view) is successful then this no longer holds
3135069Sgblack@eecs.umich.edu    // and we could in fact have an empty retry list
3145069Sgblack@eecs.umich.edu    if (retryList.empty())
315        return;
316
317    // if the bus layer is idle
318    if (state == IDLE) {
319        // note that we do not care who told us to retry at the moment, we
320        // merely let the first one on the retry list go
321        retryWaiting();
322    }
323}
324
325PortID
326BaseBus::findPort(Addr addr)
327{
328    // we should never see any address lookups before we've got the
329    // ranges of all connected slave modules
330    assert(gotAllAddrRanges);
331
332    // Check the cache
333    PortID dest_id = checkPortCache(addr);
334    if (dest_id != InvalidPortID)
335        return dest_id;
336
337    // Check the address map interval tree
338    PortMapConstIter i = portMap.find(addr);
339    if (i != portMap.end()) {
340        dest_id = i->second;
341        updatePortCache(dest_id, i->first);
342        return dest_id;
343    }
344
345    // Check if this matches the default range
346    if (useDefaultRange) {
347        if (defaultRange.contains(addr)) {
348            DPRINTF(BusAddrRanges, "  found addr %#llx on default\n",
349                    addr);
350            return defaultPortID;
351        }
352    } else if (defaultPortID != InvalidPortID) {
353        DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, "
354                "will use default port\n", addr);
355        return defaultPortID;
356    }
357
358    // we should use the range for the default port and it did not
359    // match, or the default port is not set
360    fatal("Unable to find destination for addr %#llx on bus %s\n", addr,
361          name());
362}
363
364/** Function called by the port when the bus is receiving a range change.*/
365void
366BaseBus::recvRangeChange(PortID master_port_id)
367{
368    DPRINTF(BusAddrRanges, "Received range change from slave port %s\n",
369            masterPorts[master_port_id]->getSlavePort().name());
370
371    // remember that we got a range from this master port and thus the
372    // connected slave module
373    gotAddrRanges[master_port_id] = true;
374
375    // update the global flag
376    if (!gotAllAddrRanges) {
377        // take a logical AND of all the ports and see if we got
378        // ranges from everyone
379        gotAllAddrRanges = true;
380        std::vector<bool>::const_iterator r = gotAddrRanges.begin();
381        while (gotAllAddrRanges &&  r != gotAddrRanges.end()) {
382            gotAllAddrRanges &= *r++;
383        }
384        if (gotAllAddrRanges)
385            DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n");
386    }
387
388    // note that we could get the range from the default port at any
389    // point in time, and we cannot assume that the default range is
390    // set before the other ones are, so we do additional checks once
391    // all ranges are provided
392    if (master_port_id == defaultPortID) {
393        // only update if we are indeed checking ranges for the
394        // default port since the port might not have a valid range
395        // otherwise
396        if (useDefaultRange) {
397            AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
398
399            if (ranges.size() != 1)
400                fatal("Bus %s may only have a single default range",
401                      name());
402
403            defaultRange = ranges.front();
404        }
405    } else {
406        // the ports are allowed to update their address ranges
407        // dynamically, so remove any existing entries
408        if (gotAddrRanges[master_port_id]) {
409            for (PortMapIter p = portMap.begin(); p != portMap.end(); ) {
410                if (p->second == master_port_id)
411                    // erasing invalidates the iterator, so advance it
412                    // before the deletion takes place
413                    portMap.erase(p++);
414                else
415                    p++;
416            }
417        }
418
419        AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
420
421        for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) {
422            DPRINTF(BusAddrRanges, "Adding range %s for id %d\n",
423                    r->to_string(), master_port_id);
424            if (portMap.insert(*r, master_port_id) == portMap.end()) {
425                PortID conflict_id = portMap.find(*r)->second;
426                fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
427                      name(),
428                      masterPorts[master_port_id]->getSlavePort().name(),
429                      masterPorts[conflict_id]->getSlavePort().name());
430            }
431        }
432    }
433
434    // if we have received ranges from all our neighbouring slave
435    // modules, go ahead and tell our connected master modules in
436    // turn, this effectively assumes a tree structure of the system
437    if (gotAllAddrRanges) {
438        // also check that no range partially overlaps with the
439        // default range, this has to be done after all ranges are set
440        // as there are no guarantees for when the default range is
441        // update with respect to the other ones
442        if (useDefaultRange) {
443            for (PortID port_id = 0; port_id < masterPorts.size(); ++port_id) {
444                if (port_id == defaultPortID) {
445                    if (!gotAddrRanges[port_id])
446                        fatal("Bus %s uses default range, but none provided",
447                              name());
448                } else {
449                    AddrRangeList ranges =
450                        masterPorts[port_id]->getAddrRanges();
451
452                    for (AddrRangeConstIter r = ranges.begin();
453                         r != ranges.end(); ++r) {
454                        // see if the new range is partially
455                        // overlapping the default range
456                        if (r->intersects(defaultRange) &&
457                            !r->isSubset(defaultRange))
458                            fatal("Range %s intersects the " \
459                                  "default range of %s but is not a " \
460                                  "subset\n", r->to_string(), name());
461                    }
462                }
463            }
464        }
465
466        // tell all our neighbouring master ports that our address
467        // ranges have changed
468        for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end();
469             ++s)
470            (*s)->sendRangeChange();
471    }
472
473    clearPortCache();
474}
475
476AddrRangeList
477BaseBus::getAddrRanges() const
478{
479    // we should never be asked without first having sent a range
480    // change, and the latter is only done once we have all the ranges
481    // of the connected devices
482    assert(gotAllAddrRanges);
483
484    // at the moment, this never happens, as there are no cycles in
485    // the range queries and no devices on the master side of a bus
486    // (CPU, cache, bridge etc) actually care about the ranges of the
487    // ports they are connected to
488
489    DPRINTF(BusAddrRanges, "Received address range request, returning:\n");
490
491    // start out with the default range
492    AddrRangeList ranges;
493    if (useDefaultRange) {
494        ranges.push_back(defaultRange);
495        DPRINTF(BusAddrRanges, "  -- Default %s\n", defaultRange.to_string());
496    }
497
498    // add any range that is not a subset of the default range
499    for (PortMapConstIter p = portMap.begin(); p != portMap.end(); ++p) {
500        if (useDefaultRange && p->first.isSubset(defaultRange)) {
501            DPRINTF(BusAddrRanges, "  -- %s is a subset of default\n",
502                    p->first.to_string());
503        } else {
504            ranges.push_back(p->first);
505            DPRINTF(BusAddrRanges, "  -- %s\n", p->first.to_string());
506        }
507    }
508
509    return ranges;
510}
511
512unsigned
513BaseBus::deviceBlockSize() const
514{
515    return blockSize;
516}
517
518template <typename PortClass>
519unsigned int
520BaseBus::Layer<PortClass>::drain(DrainManager *dm)
521{
522    //We should check that we're not "doing" anything, and that noone is
523    //waiting. We might be idle but have someone waiting if the device we
524    //contacted for a retry didn't actually retry.
525    if (!retryList.empty() || state != IDLE) {
526        DPRINTF(Drain, "Bus not drained\n");
527        drainManager = dm;
528        return 1;
529    }
530    return 0;
531}
532
533/**
534 * Bus layer template instantiations. Could be removed with _impl.hh
535 * file, but since there are only two given options (MasterPort and
536 * SlavePort) it seems a bit excessive at this point.
537 */
538template class BaseBus::Layer<SlavePort>;
539template class BaseBus::Layer<MasterPort>;
540