xbar.cc revision 9715
12623SN/A/*
22623SN/A * Copyright (c) 2011-2013 ARM Limited
32623SN/A * All rights reserved
42623SN/A *
52623SN/A * The license below extends only to copyright in the software and shall
62623SN/A * not be construed as granting a license to any other intellectual
72623SN/A * property including but not limited to intellectual property relating
82623SN/A * to a hardware implementation of the functionality of the software
92623SN/A * licensed hereunder.  You may use the software subject to the license
102623SN/A * terms below provided that you ensure that this notice is replicated
112623SN/A * unmodified and in its entirety in all distributions of the software,
122623SN/A * modified or unmodified, in source code or in binary form.
132623SN/A *
142623SN/A * Copyright (c) 2006 The Regents of The University of Michigan
152623SN/A * All rights reserved.
162623SN/A *
172623SN/A * Redistribution and use in source and binary forms, with or without
182623SN/A * modification, are permitted provided that the following conditions are
192623SN/A * met: redistributions of source code must retain the above copyright
202623SN/A * notice, this list of conditions and the following disclaimer;
212623SN/A * redistributions in binary form must reproduce the above copyright
222623SN/A * notice, this list of conditions and the following disclaimer in the
232623SN/A * documentation and/or other materials provided with the distribution;
242623SN/A * neither the name of the copyright holders nor the names of its
252623SN/A * contributors may be used to endorse or promote products derived from
262623SN/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
292623SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302623SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312623SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322623SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332623SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342623SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352623SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362623SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372623SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382623SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392623SN/A *
402856Srdreslin@umich.edu * Authors: Ali Saidi
412856Srdreslin@umich.edu *          Andreas Hansson
422856Srdreslin@umich.edu *          William Wang
432856Srdreslin@umich.edu */
442856Srdreslin@umich.edu
452856Srdreslin@umich.edu/**
462856Srdreslin@umich.edu * @file
472856Srdreslin@umich.edu * Definition of a bus object.
482856Srdreslin@umich.edu */
492856Srdreslin@umich.edu
502623SN/A#include "base/misc.hh"
512623SN/A#include "base/trace.hh"
522623SN/A#include "debug/Bus.hh"
532623SN/A#include "debug/BusAddrRanges.hh"
542623SN/A#include "debug/Drain.hh"
552623SN/A#include "mem/bus.hh"
562680Sktlim@umich.edu
572680Sktlim@umich.eduBaseBus::BaseBus(const BaseBusParams *p)
582623SN/A    : MemObject(p),
592623SN/A      headerCycles(p->header_cycles), width(p->width),
602680Sktlim@umich.edu      gotAddrRanges(p->port_default_connection_count +
612623SN/A                          p->port_master_connection_count, false),
622623SN/A      gotAllAddrRanges(false), defaultPortID(InvalidPortID),
632623SN/A      useDefaultRange(p->use_default_range),
642623SN/A      blockSize(p->block_size)
652623SN/A{}
662630SN/A
672623SN/ABaseBus::~BaseBus()
682623SN/A{
692623SN/A    for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end();
702623SN/A         ++m) {
712623SN/A        delete *m;
722623SN/A    }
732630SN/A
742623SN/A    for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end();
752623SN/A         ++s) {
762623SN/A        delete *s;
772623SN/A    }
782623SN/A}
792623SN/A
802623SN/Avoid
812631SN/ABaseBus::init()
822631SN/A{
832631SN/A    // determine the maximum peer block size, look at both the
842623SN/A    // connected master and slave modules
852623SN/A    uint32_t peer_block_size = 0;
862623SN/A
872623SN/A    for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end();
882623SN/A         ++m) {
892623SN/A        peer_block_size = std::max((*m)->peerBlockSize(), peer_block_size);
902623SN/A    }
912623SN/A
922839Sktlim@umich.edu    for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end();
932798Sktlim@umich.edu         ++s) {
942623SN/A        peer_block_size = std::max((*s)->peerBlockSize(), peer_block_size);
952623SN/A    }
962623SN/A
972623SN/A    // if the peers do not have a block size, use the default value
982623SN/A    // set through the bus parameters
992623SN/A    if (peer_block_size != 0)
1002623SN/A        blockSize = peer_block_size;
1012623SN/A
1022623SN/A    // check if the block size is a value known to work
1032623SN/A    if (!(blockSize == 16 || blockSize == 32 || blockSize == 64 ||
1042798Sktlim@umich.edu          blockSize == 128))
1052623SN/A        warn_once("Block size is neither 16, 32, 64 or 128 bytes.\n");
1062623SN/A}
1072623SN/A
1082623SN/ABaseMasterPort &
1092623SN/ABaseBus::getMasterPort(const std::string &if_name, PortID idx)
1102623SN/A{
1112798Sktlim@umich.edu    if (if_name == "master" && idx < masterPorts.size()) {
1122623SN/A        // the master port index translates directly to the vector position
1132798Sktlim@umich.edu        return *masterPorts[idx];
1142798Sktlim@umich.edu    } else  if (if_name == "default") {
1152798Sktlim@umich.edu        return *masterPorts[defaultPortID];
1162839Sktlim@umich.edu    } else {
1172798Sktlim@umich.edu        return MemObject::getMasterPort(if_name, idx);
1182839Sktlim@umich.edu    }
1192798Sktlim@umich.edu}
1202798Sktlim@umich.edu
1212839Sktlim@umich.eduBaseSlavePort &
1222798Sktlim@umich.eduBaseBus::getSlavePort(const std::string &if_name, PortID idx)
1232798Sktlim@umich.edu{
1242839Sktlim@umich.edu    if (if_name == "slave" && idx < slavePorts.size()) {
1252839Sktlim@umich.edu        // the slave port index translates directly to the vector position
1262798Sktlim@umich.edu        return *slavePorts[idx];
1272798Sktlim@umich.edu    } else {
1282623SN/A        return MemObject::getSlavePort(if_name, idx);
1292623SN/A    }
1302623SN/A}
1312798Sktlim@umich.edu
1322623SN/Avoid
1332798Sktlim@umich.eduBaseBus::calcPacketTiming(PacketPtr pkt)
1342798Sktlim@umich.edu{
1352798Sktlim@umich.edu    // the bus will be called at a time that is not necessarily
1362798Sktlim@umich.edu    // coinciding with its own clock, so start by determining how long
1372623SN/A    // until the next clock edge (could be zero)
1382798Sktlim@umich.edu    Tick offset = clockEdge() - curTick();
1392798Sktlim@umich.edu
1402798Sktlim@umich.edu    // determine how many cycles are needed to send the data
1412798Sktlim@umich.edu    unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0;
1422798Sktlim@umich.edu
1432798Sktlim@umich.edu    // before setting the bus delay fields of the packet, ensure that
1442798Sktlim@umich.edu    // the delay from any previous bus has been accounted for
1452798Sktlim@umich.edu    if (pkt->busFirstWordDelay != 0 || pkt->busLastWordDelay != 0)
1462798Sktlim@umich.edu        panic("Packet %s already has bus delay (%d, %d) that should be "
1472798Sktlim@umich.edu              "accounted for.\n", pkt->cmdString(), pkt->busFirstWordDelay,
1482798Sktlim@umich.edu              pkt->busLastWordDelay);
1492798Sktlim@umich.edu
1502798Sktlim@umich.edu    // The first word will be delivered on the cycle after the header.
1512623SN/A    pkt->busFirstWordDelay = (headerCycles + 1) * clockPeriod() + offset;
1522623SN/A
1532623SN/A    // Note that currently busLastWordDelay can be smaller than
1542623SN/A    // busFirstWordDelay if the packet has no data
1552623SN/A    pkt->busLastWordDelay = (headerCycles + dataCycles) * clockPeriod() +
1562623SN/A        offset;
1572623SN/A}
1582623SN/A
1592680Sktlim@umich.edutemplate <typename SrcType, typename DstType>
1602623SN/ABaseBus::Layer<SrcType,DstType>::Layer(DstType& _port, BaseBus& _bus,
1612680Sktlim@umich.edu                                       const std::string& _name) :
1622680Sktlim@umich.edu    port(_port), bus(_bus), _name(_name), state(IDLE), drainManager(NULL),
1632680Sktlim@umich.edu    retryingPort(NULL), waitingForPeer(NULL),
1642623SN/A    releaseEvent(this)
1652623SN/A{
1662623SN/A}
1672623SN/A
1682623SN/Atemplate <typename SrcType, typename DstType>
1692623SN/Avoid BaseBus::Layer<SrcType,DstType>::occupyLayer(Tick until)
1702623SN/A{
1712623SN/A    // ensure the state is busy at this point, as the bus should
1722623SN/A    // transition from idle as soon as it has decided to forward the
1732623SN/A    // packet to prevent any follow-on calls to sendTiming seeing an
1742623SN/A    // unoccupied bus
1752683Sktlim@umich.edu    assert(state == BUSY);
1762623SN/A
1772623SN/A    // until should never be 0 as express snoops never occupy the bus
1782623SN/A    assert(until != 0);
1792623SN/A    bus.schedule(releaseEvent, until);
1802623SN/A
1812623SN/A    // account for the occupied ticks
1822623SN/A    occupancy += until - curTick();
1832623SN/A
1842623SN/A    DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n",
1852623SN/A            curTick(), until);
1862623SN/A}
1872623SN/A
1882623SN/Atemplate <typename SrcType, typename DstType>
1892623SN/Abool
1902623SN/ABaseBus::Layer<SrcType,DstType>::tryTiming(SrcType* src_port)
1912623SN/A{
1922683Sktlim@umich.edu    // first we see if the layer is busy, next we check if we are in a
1932623SN/A    // retry with a port other than the current one, lastly we check
1942644Sstever@eecs.umich.edu    // if the destination port is already engaged in a transaction
1952623SN/A    // waiting for a retry from the peer
1962644Sstever@eecs.umich.edu    if (state == BUSY || (state == RETRY && src_port != retryingPort) ||
1972644Sstever@eecs.umich.edu        waitingForPeer != NULL) {
1982623SN/A        // put the port at the end of the retry list waiting for the
1992623SN/A        // layer to be freed up (and in the case of a busy peer, for
2002623SN/A        // that transaction to go through, and then the bus to free
2012623SN/A        // up)
2022623SN/A        waitingForLayer.push_back(src_port);
2032623SN/A        return false;
2042623SN/A    }
2052623SN/A
2062623SN/A    // update the state to busy
2072623SN/A    state = BUSY;
2082663Sstever@eecs.umich.edu
2092663Sstever@eecs.umich.edu    // reset the retrying port
2102835Srdreslin@umich.edu    retryingPort = NULL;
2112683Sktlim@umich.edu
2122623SN/A    return true;
2132623SN/A}
2142623SN/A
2152623SN/Atemplate <typename SrcType, typename DstType>
2162623SN/Avoid
2172623SN/ABaseBus::Layer<SrcType,DstType>::succeededTiming(Tick busy_time)
2182683Sktlim@umich.edu{
2192623SN/A    // we should have gone from idle or retry to busy in the tryTiming
2202623SN/A    // test
2212623SN/A    assert(state == BUSY);
2222641Sstever@eecs.umich.edu
2232641Sstever@eecs.umich.edu    // occupy the bus accordingly
2242623SN/A    occupyLayer(busy_time);
2252623SN/A}
2262630SN/A
2272623SN/Atemplate <typename SrcType, typename DstType>
2282623SN/Avoid
2292623SN/ABaseBus::Layer<SrcType,DstType>::failedTiming(SrcType* src_port,
2302623SN/A                                              Tick busy_time)
2312623SN/A{
2322623SN/A    // ensure no one got in between and tried to send something to
2332623SN/A    // this port
2342623SN/A    assert(waitingForPeer == NULL);
2352623SN/A
2362623SN/A    // if the source port is the current retrying one or not, we have
2372623SN/A    // failed in forwarding and should track that we are now waiting
2382623SN/A    // for the peer to send a retry
2392623SN/A    waitingForPeer = src_port;
2402623SN/A
2412623SN/A    // we should have gone from idle or retry to busy in the tryTiming
2422623SN/A    // test
2432623SN/A    assert(state == BUSY);
2442623SN/A
2452623SN/A    // occupy the bus accordingly
2462623SN/A    occupyLayer(busy_time);
2472623SN/A}
2482623SN/A
2492623SN/Atemplate <typename SrcType, typename DstType>
2502623SN/Avoid
2512623SN/ABaseBus::Layer<SrcType,DstType>::releaseLayer()
2522623SN/A{
2532623SN/A    // releasing the bus means we should now be idle
2542623SN/A    assert(state == BUSY);
2552623SN/A    assert(!releaseEvent.scheduled());
2562623SN/A
2572623SN/A    // update the state
2582623SN/A    state = IDLE;
2592623SN/A
2602623SN/A    // bus layer is now idle, so if someone is waiting we can retry
2612623SN/A    if (!waitingForLayer.empty()) {
2622623SN/A        retryWaiting();
2632623SN/A    } else if (waitingForPeer == NULL && drainManager) {
2642623SN/A        DPRINTF(Drain, "Bus done draining, signaling drain manager\n");
2652623SN/A        //If we weren't able to drain before, do it now.
2662623SN/A        drainManager->signalDrainDone();
2672623SN/A        // Clear the drain event once we're done with it.
2682623SN/A        drainManager = NULL;
2692623SN/A    }
2702623SN/A}
2712623SN/A
2722623SN/Atemplate <typename SrcType, typename DstType>
2732623SN/Avoid
2742623SN/ABaseBus::Layer<SrcType,DstType>::retryWaiting()
2752623SN/A{
2762623SN/A    // this should never be called with no one waiting
2772623SN/A    assert(!waitingForLayer.empty());
2782623SN/A
2792623SN/A    // we always go to retrying from idle
2802623SN/A    assert(state == IDLE);
2812623SN/A
2822623SN/A    // update the state
2832623SN/A    state = RETRY;
2842623SN/A
2852623SN/A    // set the retrying port to the front of the retry list and pop it
2862623SN/A    // off the list
2872623SN/A    assert(retryingPort == NULL);
2882623SN/A    retryingPort = waitingForLayer.front();
2892663Sstever@eecs.umich.edu    waitingForLayer.pop_front();
2902663Sstever@eecs.umich.edu
2912835Srdreslin@umich.edu    // tell the port to retry, which in some cases ends up calling the
2922683Sktlim@umich.edu    // bus
2932623SN/A    retryingPort->sendRetry();
2942623SN/A
2952683Sktlim@umich.edu    // If the bus is still in the retry state, sendTiming wasn't
2962623SN/A    // called in zero time (e.g. the cache does this), burn a cycle
2972623SN/A    if (state == RETRY) {
2982641Sstever@eecs.umich.edu        // update the state to busy and reset the retrying port, we
2992641Sstever@eecs.umich.edu        // have done our bit and sent the retry
3002623SN/A        state = BUSY;
3012623SN/A        retryingPort = NULL;
3022623SN/A
3032630SN/A        // occupy the bus layer until the next cycle ends
3042623SN/A        occupyLayer(bus.clockEdge(Cycles(1)));
3052623SN/A    }
3062623SN/A}
3072623SN/A
3082623SN/Atemplate <typename SrcType, typename DstType>
3092623SN/Avoid
3102623SN/ABaseBus::Layer<SrcType,DstType>::recvRetry()
3112623SN/A{
3122623SN/A    // we should never get a retry without having failed to forward
3132623SN/A    // something to this port
3142623SN/A    assert(waitingForPeer != NULL);
3152623SN/A
3162623SN/A    // add the port where the failed packet originated to the front of
3172623SN/A    // the waiting ports for the layer, this allows us to call retry
3182623SN/A    // on the port immediately if the bus layer is idle
3192623SN/A    waitingForLayer.push_front(waitingForPeer);
3202623SN/A
3212623SN/A    // we are no longer waiting for the peer
3222623SN/A    waitingForPeer = NULL;
3232623SN/A
3242623SN/A    // if the bus layer is idle, retry this port straight away, if we
3252623SN/A    // are busy, then simply let the port wait for its turn
3262623SN/A    if (state == IDLE) {
3272623SN/A        retryWaiting();
3282623SN/A    } else {
3292623SN/A        assert(state == BUSY);
3302623SN/A    }
3312623SN/A}
3322623SN/A
3332623SN/APortID
3342623SN/ABaseBus::findPort(Addr addr)
3352623SN/A{
3362623SN/A    // we should never see any address lookups before we've got the
3372623SN/A    // ranges of all connected slave modules
3382623SN/A    assert(gotAllAddrRanges);
3392623SN/A
3402623SN/A    // Check the cache
3412623SN/A    PortID dest_id = checkPortCache(addr);
3422623SN/A    if (dest_id != InvalidPortID)
3432623SN/A        return dest_id;
3442623SN/A
3452623SN/A    // Check the address map interval tree
3462623SN/A    PortMapConstIter i = portMap.find(addr);
3472623SN/A    if (i != portMap.end()) {
3482623SN/A        dest_id = i->second;
3492623SN/A        updatePortCache(dest_id, i->first);
3502623SN/A        return dest_id;
3512623SN/A    }
3522623SN/A
3532623SN/A    // Check if this matches the default range
3542623SN/A    if (useDefaultRange) {
3552623SN/A        if (defaultRange.contains(addr)) {
3562623SN/A            DPRINTF(BusAddrRanges, "  found addr %#llx on default\n",
3572623SN/A                    addr);
3582623SN/A            return defaultPortID;
3592623SN/A        }
3602623SN/A    } else if (defaultPortID != InvalidPortID) {
3612623SN/A        DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, "
3622623SN/A                "will use default port\n", addr);
3632623SN/A        return defaultPortID;
3642623SN/A    }
3652623SN/A
3662623SN/A    // we should use the range for the default port and it did not
3672623SN/A    // match, or the default port is not set
3682623SN/A    fatal("Unable to find destination for addr %#llx on bus %s\n", addr,
3692623SN/A          name());
3702623SN/A}
3712631SN/A
3722631SN/A/** Function called by the port when the bus is receiving a range change.*/
3732663Sstever@eecs.umich.eduvoid
3742663Sstever@eecs.umich.eduBaseBus::recvRangeChange(PortID master_port_id)
3752835Srdreslin@umich.edu{
3762662Sstever@eecs.umich.edu    DPRINTF(BusAddrRanges, "Received range change from slave port %s\n",
3772623SN/A            masterPorts[master_port_id]->getSlavePort().name());
3782641Sstever@eecs.umich.edu
3792623SN/A    // remember that we got a range from this master port and thus the
3802623SN/A    // connected slave module
3812623SN/A    gotAddrRanges[master_port_id] = true;
3822630SN/A
3832623SN/A    // update the global flag
3842623SN/A    if (!gotAllAddrRanges) {
3852623SN/A        // take a logical AND of all the ports and see if we got
3862623SN/A        // ranges from everyone
3872623SN/A        gotAllAddrRanges = true;
3882623SN/A        std::vector<bool>::const_iterator r = gotAddrRanges.begin();
3892623SN/A        while (gotAllAddrRanges &&  r != gotAddrRanges.end()) {
3902623SN/A            gotAllAddrRanges &= *r++;
3912623SN/A        }
3922644Sstever@eecs.umich.edu        if (gotAllAddrRanges)
3932644Sstever@eecs.umich.edu            DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n");
3942623SN/A    }
3952623SN/A
3962623SN/A    // note that we could get the range from the default port at any
3972623SN/A    // point in time, and we cannot assume that the default range is
3982623SN/A    // set before the other ones are, so we do additional checks once
3992644Sstever@eecs.umich.edu    // all ranges are provided
4002623SN/A    if (master_port_id == defaultPortID) {
4012623SN/A        // only update if we are indeed checking ranges for the
4022623SN/A        // default port since the port might not have a valid range
4032631SN/A        // otherwise
4042631SN/A        if (useDefaultRange) {
4052631SN/A            AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
4062631SN/A
4072631SN/A            if (ranges.size() != 1)
4082631SN/A                fatal("Bus %s may only have a single default range",
4092623SN/A                      name());
4102623SN/A
4112623SN/A            defaultRange = ranges.front();
4122623SN/A        }
4132644Sstever@eecs.umich.edu    } else {
4142623SN/A        // the ports are allowed to update their address ranges
4152623SN/A        // dynamically, so remove any existing entries
4162623SN/A        if (gotAddrRanges[master_port_id]) {
4172644Sstever@eecs.umich.edu            for (PortMapIter p = portMap.begin(); p != portMap.end(); ) {
4182623SN/A                if (p->second == master_port_id)
4192798Sktlim@umich.edu                    // erasing invalidates the iterator, so advance it
4202623SN/A                    // before the deletion takes place
4212644Sstever@eecs.umich.edu                    portMap.erase(p++);
4222644Sstever@eecs.umich.edu                else
4232644Sstever@eecs.umich.edu                    p++;
4242644Sstever@eecs.umich.edu            }
4252839Sktlim@umich.edu        }
4262839Sktlim@umich.edu
4272798Sktlim@umich.edu        AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
4282798Sktlim@umich.edu
4292798Sktlim@umich.edu        for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) {
4302623SN/A            DPRINTF(BusAddrRanges, "Adding range %s for id %d\n",
4312644Sstever@eecs.umich.edu                    r->to_string(), master_port_id);
4322623SN/A            if (portMap.insert(*r, master_port_id) == portMap.end()) {
4332623SN/A                PortID conflict_id = portMap.find(*r)->second;
4342644Sstever@eecs.umich.edu                fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
4352644Sstever@eecs.umich.edu                      name(),
4362644Sstever@eecs.umich.edu                      masterPorts[master_port_id]->getSlavePort().name(),
4372644Sstever@eecs.umich.edu                      masterPorts[conflict_id]->getSlavePort().name());
4382644Sstever@eecs.umich.edu            }
4392644Sstever@eecs.umich.edu        }
4402644Sstever@eecs.umich.edu    }
4412644Sstever@eecs.umich.edu
4422644Sstever@eecs.umich.edu    // if we have received ranges from all our neighbouring slave
4432623SN/A    // modules, go ahead and tell our connected master modules in
4442623SN/A    // turn, this effectively assumes a tree structure of the system
4452623SN/A    if (gotAllAddrRanges) {
4462644Sstever@eecs.umich.edu        DPRINTF(BusAddrRanges, "Aggregating bus ranges\n");
4472644Sstever@eecs.umich.edu        busRanges.clear();
4482623SN/A
4492623SN/A        // start out with the default range
4502623SN/A        if (useDefaultRange) {
4512623SN/A            if (!gotAddrRanges[defaultPortID])
4522623SN/A                fatal("Bus %s uses default range, but none provided",
4532630SN/A                      name());
4542623SN/A
4552855Srdreslin@umich.edu            busRanges.push_back(defaultRange);
4562855Srdreslin@umich.edu            DPRINTF(BusAddrRanges, "-- Adding default %s\n",
4572855Srdreslin@umich.edu                    defaultRange.to_string());
4582855Srdreslin@umich.edu        }
4592855Srdreslin@umich.edu
4602855Srdreslin@umich.edu        // merge all interleaved ranges and add any range that is not
4612623SN/A        // a subset of the default range
4622623SN/A        std::vector<AddrRange> intlv_ranges;
4632623SN/A        for (AddrRangeMap<PortID>::const_iterator r = portMap.begin();
4642657Ssaidi@eecs.umich.edu             r != portMap.end(); ++r) {
4652623SN/A            // if the range is interleaved then save it for now
4662623SN/A            if (r->first.interleaved()) {
4672623SN/A                // if we already got interleaved ranges that are not
4682623SN/A                // part of the same range, then first do a merge
4692623SN/A                // before we add the new one
4702623SN/A                if (!intlv_ranges.empty() &&
4712623SN/A                    !intlv_ranges.back().mergesWith(r->first)) {
4722657Ssaidi@eecs.umich.edu                    DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n",
4732657Ssaidi@eecs.umich.edu                            intlv_ranges.size());
4742657Ssaidi@eecs.umich.edu                    AddrRange merged_range(intlv_ranges);
4752657Ssaidi@eecs.umich.edu                    // next decide if we keep the merged range or not
4762623SN/A                    if (!(useDefaultRange &&
4772623SN/A                          merged_range.isSubset(defaultRange))) {
4782623SN/A                        busRanges.push_back(merged_range);
4792623SN/A                        DPRINTF(BusAddrRanges, "-- Adding merged range %s\n",
4802623SN/A                                merged_range.to_string());
4812623SN/A                    }
4822623SN/A                    intlv_ranges.clear();
4832641Sstever@eecs.umich.edu                }
4842623SN/A                intlv_ranges.push_back(r->first);
4852623SN/A            } else {
4862623SN/A                // keep the current range if not a subset of the default
4872839Sktlim@umich.edu                if (!(useDefaultRange &&
4882839Sktlim@umich.edu                      r->first.isSubset(defaultRange))) {
4892798Sktlim@umich.edu                    busRanges.push_back(r->first);
4902798Sktlim@umich.edu                    DPRINTF(BusAddrRanges, "-- Adding range %s\n",
4912798Sktlim@umich.edu                            r->first.to_string());
4922798Sktlim@umich.edu                }
4932798Sktlim@umich.edu            }
4942798Sktlim@umich.edu        }
4952798Sktlim@umich.edu
4962623SN/A        // if there is still interleaved ranges waiting to be merged,
4972623SN/A        // go ahead and do it
4982644Sstever@eecs.umich.edu        if (!intlv_ranges.empty()) {
4992644Sstever@eecs.umich.edu            DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n",
5002644Sstever@eecs.umich.edu                    intlv_ranges.size());
5012644Sstever@eecs.umich.edu            AddrRange merged_range(intlv_ranges);
5022644Sstever@eecs.umich.edu            if (!(useDefaultRange && merged_range.isSubset(defaultRange))) {
5032623SN/A                busRanges.push_back(merged_range);
5042623SN/A                DPRINTF(BusAddrRanges, "-- Adding merged range %s\n",
5052623SN/A                        merged_range.to_string());
5062798Sktlim@umich.edu            }
5072839Sktlim@umich.edu        }
5082798Sktlim@umich.edu
5092839Sktlim@umich.edu        // also check that no range partially overlaps with the
5102839Sktlim@umich.edu        // default range, this has to be done after all ranges are set
5112839Sktlim@umich.edu        // as there are no guarantees for when the default range is
5122798Sktlim@umich.edu        // update with respect to the other ones
5132623SN/A        if (useDefaultRange) {
5142623SN/A            for (AddrRangeConstIter r = busRanges.begin();
5152630SN/A                 r != busRanges.end(); ++r) {
5162623SN/A                // see if the new range is partially
5172630SN/A                // overlapping the default range
5182623SN/A                if (r->intersects(defaultRange) &&
5192623SN/A                    !r->isSubset(defaultRange))
5202623SN/A                    fatal("Range %s intersects the "                    \
5212657Ssaidi@eecs.umich.edu                          "default range of %s but is not a "           \
5222623SN/A                          "subset\n", r->to_string(), name());
5232623SN/A            }
5242623SN/A        }
5252623SN/A
5262623SN/A        // tell all our neighbouring master ports that our address
5272623SN/A        // ranges have changed
5282623SN/A        for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end();
5292657Ssaidi@eecs.umich.edu             ++s)
5302657Ssaidi@eecs.umich.edu            (*s)->sendRangeChange();
5312657Ssaidi@eecs.umich.edu    }
5322657Ssaidi@eecs.umich.edu
5332623SN/A    clearPortCache();
5342623SN/A}
5352623SN/A
5362623SN/AAddrRangeList
5372623SN/ABaseBus::getAddrRanges() const
5382623SN/A{
5392623SN/A    // we should never be asked without first having sent a range
5402623SN/A    // change, and the latter is only done once we have all the ranges
5412623SN/A    // of the connected devices
5422623SN/A    assert(gotAllAddrRanges);
5432623SN/A
5442623SN/A    // at the moment, this never happens, as there are no cycles in
5452623SN/A    // the range queries and no devices on the master side of a bus
5462623SN/A    // (CPU, cache, bridge etc) actually care about the ranges of the
5472623SN/A    // ports they are connected to
5482623SN/A
5492623SN/A    DPRINTF(BusAddrRanges, "Received address range request\n");
5502623SN/A
5512623SN/A    return busRanges;
5522623SN/A}
5532623SN/A
5542623SN/Aunsigned
5552623SN/ABaseBus::deviceBlockSize() const
5562623SN/A{
5572623SN/A    return blockSize;
5582623SN/A}
5592623SN/A
5602623SN/Avoid
5612623SN/ABaseBus::regStats()
5622623SN/A{
5632623SN/A    using namespace Stats;
5642623SN/A
5652623SN/A    transDist
5662623SN/A        .init(MemCmd::NUM_MEM_CMDS)
5672623SN/A        .name(name() + ".trans_dist")
5682623SN/A        .desc("Transaction distribution")
5692623SN/A        .flags(nozero);
5702623SN/A
5712623SN/A    // get the string representation of the commands
5722623SN/A    for (int i = 0; i < MemCmd::NUM_MEM_CMDS; i++) {
5732623SN/A        MemCmd cmd(i);
5742623SN/A        const std::string &cstr = cmd.toString();
5752623SN/A        transDist.subname(i, cstr);
5762623SN/A    }
5772623SN/A
5782623SN/A    pktCount
5792623SN/A        .init(slavePorts.size(), masterPorts.size())
5802623SN/A        .name(name() + ".pkt_count")
5812623SN/A        .desc("Packet count per connected master and slave (bytes)")
5822623SN/A        .flags(total | nozero | nonan);
5832623SN/A
5842623SN/A    totPktSize
5852623SN/A        .init(slavePorts.size(), masterPorts.size())
5862623SN/A        .name(name() + ".tot_pkt_size")
5872623SN/A        .desc("Cumulative packet size per connected master and slave (bytes)")
5882623SN/A        .flags(total | nozero | nonan);
5892623SN/A
5902623SN/A    // both the packet count and total size are two-dimensional
5912623SN/A    // vectors, indexed by slave port id and master port id, thus the
5922623SN/A    // neighbouring master and slave, they do not differentiate what
5932623SN/A    // came from the master and was forwarded to the slave (requests
5942623SN/A    // and snoop responses) and what came from the slave and was
5952623SN/A    // forwarded to the master (responses and snoop requests)
5962623SN/A    for (int i = 0; i < slavePorts.size(); i++) {
5972623SN/A        pktCount.subname(i, slavePorts[i]->getMasterPort().name());
5982623SN/A        totPktSize.subname(i, slavePorts[i]->getMasterPort().name());
5992623SN/A        for (int j = 0; j < masterPorts.size(); j++) {
6002623SN/A            pktCount.ysubname(j, masterPorts[j]->getSlavePort().name());
6012623SN/A            totPktSize.ysubname(j, masterPorts[j]->getSlavePort().name());
6022623SN/A        }
6032623SN/A    }
6042623SN/A}
6052623SN/A
6062623SN/Atemplate <typename SrcType, typename DstType>
6072623SN/Aunsigned int
6082623SN/ABaseBus::Layer<SrcType,DstType>::drain(DrainManager *dm)
6092623SN/A{
6102623SN/A    //We should check that we're not "doing" anything, and that noone is
6112623SN/A    //waiting. We might be idle but have someone waiting if the device we
6122623SN/A    //contacted for a retry didn't actually retry.
6132623SN/A    if (state != IDLE) {
6142623SN/A        DPRINTF(Drain, "Bus not drained\n");
6152623SN/A        drainManager = dm;
6162623SN/A        return 1;
6172623SN/A    }
6182623SN/A    return 0;
6192623SN/A}
6202623SN/A
6212623SN/Atemplate <typename SrcType, typename DstType>
6222623SN/Avoid
6232623SN/ABaseBus::Layer<SrcType,DstType>::regStats()
6242623SN/A{
6252623SN/A    using namespace Stats;
6262623SN/A
6272623SN/A    occupancy
6282623SN/A        .name(name() + ".occupancy")
6292623SN/A        .desc("Layer occupancy (ticks)")
6302623SN/A        .flags(nozero);
631
632    utilization
633        .name(name() + ".utilization")
634        .desc("Layer utilization (%)")
635        .precision(1)
636        .flags(nozero);
637
638    utilization = 100 * occupancy / simTicks;
639}
640
641/**
642 * Bus layer template instantiations. Could be removed with _impl.hh
643 * file, but since there are only two given options (MasterPort and
644 * SlavePort) it seems a bit excessive at this point.
645 */
646template class BaseBus::Layer<SlavePort,MasterPort>;
647template class BaseBus::Layer<MasterPort,SlavePort>;
648