xbar.cc revision 9545
112137Sar4jc@virginia.edu/*
212137Sar4jc@virginia.edu * Copyright (c) 2011-2013 ARM Limited
312137Sar4jc@virginia.edu * All rights reserved
412137Sar4jc@virginia.edu *
512137Sar4jc@virginia.edu * The license below extends only to copyright in the software and shall
612137Sar4jc@virginia.edu * not be construed as granting a license to any other intellectual
712137Sar4jc@virginia.edu * property including but not limited to intellectual property relating
812137Sar4jc@virginia.edu * to a hardware implementation of the functionality of the software
912137Sar4jc@virginia.edu * licensed hereunder.  You may use the software subject to the license
1012137Sar4jc@virginia.edu * terms below provided that you ensure that this notice is replicated
1112137Sar4jc@virginia.edu * unmodified and in its entirety in all distributions of the software,
1212137Sar4jc@virginia.edu * modified or unmodified, in source code or in binary form.
1312137Sar4jc@virginia.edu *
1412137Sar4jc@virginia.edu * Copyright (c) 2006 The Regents of The University of Michigan
1512137Sar4jc@virginia.edu * All rights reserved.
1612137Sar4jc@virginia.edu *
1712137Sar4jc@virginia.edu * Redistribution and use in source and binary forms, with or without
1812137Sar4jc@virginia.edu * modification, are permitted provided that the following conditions are
1912137Sar4jc@virginia.edu * met: redistributions of source code must retain the above copyright
2012137Sar4jc@virginia.edu * notice, this list of conditions and the following disclaimer;
2112137Sar4jc@virginia.edu * redistributions in binary form must reproduce the above copyright
2212137Sar4jc@virginia.edu * notice, this list of conditions and the following disclaimer in the
2312137Sar4jc@virginia.edu * documentation and/or other materials provided with the distribution;
2412137Sar4jc@virginia.edu * neither the name of the copyright holders nor the names of its
2512137Sar4jc@virginia.edu * contributors may be used to endorse or promote products derived from
2612137Sar4jc@virginia.edu * this software without specific prior written permission.
2712137Sar4jc@virginia.edu *
2812137Sar4jc@virginia.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2912137Sar4jc@virginia.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3012137Sar4jc@virginia.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3112137Sar4jc@virginia.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3212137Sar4jc@virginia.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3312137Sar4jc@virginia.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3412137Sar4jc@virginia.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3512137Sar4jc@virginia.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3612137Sar4jc@virginia.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3712137Sar4jc@virginia.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3812137Sar4jc@virginia.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3912137Sar4jc@virginia.edu *
4012137Sar4jc@virginia.edu * Authors: Ali Saidi
4112137Sar4jc@virginia.edu *          Andreas Hansson
4212137Sar4jc@virginia.edu *          William Wang
4312137Sar4jc@virginia.edu */
4412137Sar4jc@virginia.edu
4512137Sar4jc@virginia.edu/**
4612137Sar4jc@virginia.edu * @file
4712137Sar4jc@virginia.edu * Definition of a bus object.
4812137Sar4jc@virginia.edu */
4912137Sar4jc@virginia.edu
5012137Sar4jc@virginia.edu#include "base/misc.hh"
5112137Sar4jc@virginia.edu#include "base/trace.hh"
5212137Sar4jc@virginia.edu#include "debug/Bus.hh"
5312137Sar4jc@virginia.edu#include "debug/BusAddrRanges.hh"
5412137Sar4jc@virginia.edu#include "debug/Drain.hh"
5512137Sar4jc@virginia.edu#include "mem/bus.hh"
5612137Sar4jc@virginia.edu
5712137Sar4jc@virginia.eduBaseBus::BaseBus(const BaseBusParams *p)
5812137Sar4jc@virginia.edu    : MemObject(p),
5912137Sar4jc@virginia.edu      headerCycles(p->header_cycles), width(p->width),
6012137Sar4jc@virginia.edu      gotAddrRanges(p->port_default_connection_count +
6112137Sar4jc@virginia.edu                          p->port_master_connection_count, false),
6212137Sar4jc@virginia.edu      gotAllAddrRanges(false), defaultPortID(InvalidPortID),
6312137Sar4jc@virginia.edu      useDefaultRange(p->use_default_range),
6412137Sar4jc@virginia.edu      blockSize(p->block_size)
6512137Sar4jc@virginia.edu{}
6612137Sar4jc@virginia.edu
6712137Sar4jc@virginia.eduBaseBus::~BaseBus()
6812137Sar4jc@virginia.edu{
6912137Sar4jc@virginia.edu    for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end();
7012137Sar4jc@virginia.edu         ++m) {
7112137Sar4jc@virginia.edu        delete *m;
7212137Sar4jc@virginia.edu    }
7312137Sar4jc@virginia.edu
7412137Sar4jc@virginia.edu    for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end();
7512137Sar4jc@virginia.edu         ++s) {
7612137Sar4jc@virginia.edu        delete *s;
7712137Sar4jc@virginia.edu    }
7812137Sar4jc@virginia.edu}
7912137Sar4jc@virginia.edu
8012137Sar4jc@virginia.eduvoid
8112137Sar4jc@virginia.eduBaseBus::init()
8212137Sar4jc@virginia.edu{
8312137Sar4jc@virginia.edu    // determine the maximum peer block size, look at both the
8412137Sar4jc@virginia.edu    // connected master and slave modules
8512137Sar4jc@virginia.edu    uint32_t peer_block_size = 0;
8612137Sar4jc@virginia.edu
8712137Sar4jc@virginia.edu    for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end();
8812137Sar4jc@virginia.edu         ++m) {
8912137Sar4jc@virginia.edu        peer_block_size = std::max((*m)->peerBlockSize(), peer_block_size);
9012137Sar4jc@virginia.edu    }
9112137Sar4jc@virginia.edu
9212137Sar4jc@virginia.edu    for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end();
9312137Sar4jc@virginia.edu         ++s) {
9412137Sar4jc@virginia.edu        peer_block_size = std::max((*s)->peerBlockSize(), peer_block_size);
9512137Sar4jc@virginia.edu    }
9612137Sar4jc@virginia.edu
9712137Sar4jc@virginia.edu    // if the peers do not have a block size, use the default value
9812137Sar4jc@virginia.edu    // set through the bus parameters
9912137Sar4jc@virginia.edu    if (peer_block_size != 0)
10012137Sar4jc@virginia.edu        blockSize = peer_block_size;
10112137Sar4jc@virginia.edu
10212137Sar4jc@virginia.edu    // check if the block size is a value known to work
10312137Sar4jc@virginia.edu    if (!(blockSize == 16 || blockSize == 32 || blockSize == 64 ||
10412137Sar4jc@virginia.edu          blockSize == 128))
10512137Sar4jc@virginia.edu        warn_once("Block size is neither 16, 32, 64 or 128 bytes.\n");
10612137Sar4jc@virginia.edu}
10712137Sar4jc@virginia.edu
10812137Sar4jc@virginia.eduBaseMasterPort &
10912137Sar4jc@virginia.eduBaseBus::getMasterPort(const std::string &if_name, PortID idx)
11012137Sar4jc@virginia.edu{
11112137Sar4jc@virginia.edu    if (if_name == "master" && idx < masterPorts.size()) {
11212137Sar4jc@virginia.edu        // the master port index translates directly to the vector position
11312137Sar4jc@virginia.edu        return *masterPorts[idx];
11412137Sar4jc@virginia.edu    } else  if (if_name == "default") {
11512137Sar4jc@virginia.edu        return *masterPorts[defaultPortID];
11612137Sar4jc@virginia.edu    } else {
11712137Sar4jc@virginia.edu        return MemObject::getMasterPort(if_name, idx);
11812137Sar4jc@virginia.edu    }
11912137Sar4jc@virginia.edu}
12012137Sar4jc@virginia.edu
12112137Sar4jc@virginia.eduBaseSlavePort &
12212137Sar4jc@virginia.eduBaseBus::getSlavePort(const std::string &if_name, PortID idx)
12312137Sar4jc@virginia.edu{
12412137Sar4jc@virginia.edu    if (if_name == "slave" && idx < slavePorts.size()) {
12512137Sar4jc@virginia.edu        // the slave port index translates directly to the vector position
12612137Sar4jc@virginia.edu        return *slavePorts[idx];
12712137Sar4jc@virginia.edu    } else {
12812137Sar4jc@virginia.edu        return MemObject::getSlavePort(if_name, idx);
12912137Sar4jc@virginia.edu    }
13012137Sar4jc@virginia.edu}
13112137Sar4jc@virginia.edu
13212137Sar4jc@virginia.eduTick
13312137Sar4jc@virginia.eduBaseBus::calcPacketTiming(PacketPtr pkt)
13412137Sar4jc@virginia.edu{
13512137Sar4jc@virginia.edu    // determine the header time rounded to the closest following
13612137Sar4jc@virginia.edu    // clock edge
13712137Sar4jc@virginia.edu    Tick headerTime = clockEdge(headerCycles);
13812137Sar4jc@virginia.edu
13912137Sar4jc@virginia.edu    // The packet will be sent. Figure out how long it occupies the bus, and
14012137Sar4jc@virginia.edu    // how much of that time is for the first "word", aka bus width.
14112137Sar4jc@virginia.edu    Cycles numCycles(0);
14212137Sar4jc@virginia.edu    if (pkt->hasData()) {
14312137Sar4jc@virginia.edu        // If a packet has data, it needs ceil(size/width) cycles to send it
14412137Sar4jc@virginia.edu        unsigned dataSize = pkt->getSize();
14512137Sar4jc@virginia.edu        numCycles = Cycles(divCeil(dataSize, width));
14612137Sar4jc@virginia.edu    }
14712137Sar4jc@virginia.edu
14812137Sar4jc@virginia.edu    // The first word will be delivered on the cycle after the header.
14912137Sar4jc@virginia.edu    pkt->firstWordTime = headerTime + clockPeriod();
15012137Sar4jc@virginia.edu
15112137Sar4jc@virginia.edu    // Note that currently finishTime can be smaller than
15212137Sar4jc@virginia.edu    // firstWordTime if the packet has no data
15312137Sar4jc@virginia.edu    pkt->finishTime = headerTime + numCycles * clockPeriod();
15412137Sar4jc@virginia.edu
15512137Sar4jc@virginia.edu    return headerTime;
15612137Sar4jc@virginia.edu}
15712137Sar4jc@virginia.edu
15812137Sar4jc@virginia.edutemplate <typename PortClass>
15912137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name) :
16012137Sar4jc@virginia.edu    Drainable(),
16112137Sar4jc@virginia.edu    bus(_bus), _name(_name), state(IDLE), drainManager(NULL),
16212137Sar4jc@virginia.edu    releaseEvent(this)
16312137Sar4jc@virginia.edu{
16412137Sar4jc@virginia.edu}
16512137Sar4jc@virginia.edu
16612137Sar4jc@virginia.edutemplate <typename PortClass>
16712137Sar4jc@virginia.eduvoid BaseBus::Layer<PortClass>::occupyLayer(Tick until)
16812137Sar4jc@virginia.edu{
16912137Sar4jc@virginia.edu    // ensure the state is busy or in retry and never idle at this
17012137Sar4jc@virginia.edu    // point, as the bus should transition from idle as soon as it has
17112137Sar4jc@virginia.edu    // decided to forward the packet to prevent any follow-on calls to
17212137Sar4jc@virginia.edu    // sendTiming seeing an unoccupied bus
17312137Sar4jc@virginia.edu    assert(state != IDLE);
17412137Sar4jc@virginia.edu
17512137Sar4jc@virginia.edu    // note that we do not change the bus state here, if we are going
17612137Sar4jc@virginia.edu    // from idle to busy it is handled by tryTiming, and if we
17712137Sar4jc@virginia.edu    // are in retry we should remain in retry such that
17812137Sar4jc@virginia.edu    // succeededTiming still sees the accurate state
17912137Sar4jc@virginia.edu
18012137Sar4jc@virginia.edu    // until should never be 0 as express snoops never occupy the bus
18112137Sar4jc@virginia.edu    assert(until != 0);
18212137Sar4jc@virginia.edu    bus.schedule(releaseEvent, until);
18312137Sar4jc@virginia.edu
18412137Sar4jc@virginia.edu    DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n",
18512137Sar4jc@virginia.edu            curTick(), until);
18612137Sar4jc@virginia.edu}
18712137Sar4jc@virginia.edu
18812137Sar4jc@virginia.edutemplate <typename PortClass>
18912137Sar4jc@virginia.edubool
19012137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::tryTiming(PortClass* port)
19112137Sar4jc@virginia.edu{
19212137Sar4jc@virginia.edu    // first we see if the bus is busy, next we check if we are in a
19312137Sar4jc@virginia.edu    // retry with a port other than the current one
19412137Sar4jc@virginia.edu    if (state == BUSY || (state == RETRY && port != retryList.front())) {
19512137Sar4jc@virginia.edu        // put the port at the end of the retry list
19612137Sar4jc@virginia.edu        retryList.push_back(port);
19712137Sar4jc@virginia.edu        return false;
19812137Sar4jc@virginia.edu    }
19912137Sar4jc@virginia.edu
20012137Sar4jc@virginia.edu    // update the state which is shared for request, response and
20112137Sar4jc@virginia.edu    // snoop responses, if we were idle we are now busy, if we are in
20212137Sar4jc@virginia.edu    // a retry, then do not change
20312137Sar4jc@virginia.edu    if (state == IDLE)
20412137Sar4jc@virginia.edu        state = BUSY;
20512137Sar4jc@virginia.edu
20612137Sar4jc@virginia.edu    return true;
20712137Sar4jc@virginia.edu}
20812137Sar4jc@virginia.edu
20912137Sar4jc@virginia.edutemplate <typename PortClass>
21012137Sar4jc@virginia.eduvoid
21112137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::succeededTiming(Tick busy_time)
21212137Sar4jc@virginia.edu{
21312137Sar4jc@virginia.edu    // if a retrying port succeeded, also take it off the retry list
21412137Sar4jc@virginia.edu    if (state == RETRY) {
21512137Sar4jc@virginia.edu        DPRINTF(BaseBus, "Remove retry from list %s\n",
21612137Sar4jc@virginia.edu                retryList.front()->name());
21712137Sar4jc@virginia.edu        retryList.pop_front();
21812137Sar4jc@virginia.edu        state = BUSY;
21912137Sar4jc@virginia.edu    }
22012137Sar4jc@virginia.edu
22112137Sar4jc@virginia.edu    // we should either have gone from idle to busy in the
22212137Sar4jc@virginia.edu    // tryTiming test, or just gone from a retry to busy
22312137Sar4jc@virginia.edu    assert(state == BUSY);
22412137Sar4jc@virginia.edu
22512137Sar4jc@virginia.edu    // occupy the bus accordingly
22612137Sar4jc@virginia.edu    occupyLayer(busy_time);
22712137Sar4jc@virginia.edu}
22812137Sar4jc@virginia.edu
22912137Sar4jc@virginia.edutemplate <typename PortClass>
23012137Sar4jc@virginia.eduvoid
23112137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time)
23212137Sar4jc@virginia.edu{
23312137Sar4jc@virginia.edu    // if we are not in a retry, i.e. busy (but never idle), or we are
23412137Sar4jc@virginia.edu    // in a retry but not for the current port, then add the port at
23512137Sar4jc@virginia.edu    // the end of the retry list
23612137Sar4jc@virginia.edu    if (state != RETRY || port != retryList.front()) {
23712137Sar4jc@virginia.edu        retryList.push_back(port);
23812137Sar4jc@virginia.edu    }
23912137Sar4jc@virginia.edu
24012137Sar4jc@virginia.edu    // even if we retried the current one and did not succeed,
24112137Sar4jc@virginia.edu    // we are no longer retrying but instead busy
24212137Sar4jc@virginia.edu    state = BUSY;
24312137Sar4jc@virginia.edu
24412137Sar4jc@virginia.edu    // occupy the bus accordingly
24512137Sar4jc@virginia.edu    occupyLayer(busy_time);
24612137Sar4jc@virginia.edu}
24712137Sar4jc@virginia.edu
24812137Sar4jc@virginia.edutemplate <typename PortClass>
24912137Sar4jc@virginia.eduvoid
25012137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::releaseLayer()
25112137Sar4jc@virginia.edu{
25212137Sar4jc@virginia.edu    // releasing the bus means we should now be idle
25312137Sar4jc@virginia.edu    assert(state == BUSY);
25412137Sar4jc@virginia.edu    assert(!releaseEvent.scheduled());
25512137Sar4jc@virginia.edu
25612137Sar4jc@virginia.edu    // update the state
25712137Sar4jc@virginia.edu    state = IDLE;
25812137Sar4jc@virginia.edu
25912137Sar4jc@virginia.edu    // bus is now idle, so if someone is waiting we can retry
26012137Sar4jc@virginia.edu    if (!retryList.empty()) {
26112137Sar4jc@virginia.edu        // note that we block (return false on recvTiming) both
26212137Sar4jc@virginia.edu        // because the bus is busy and because the destination is
26312137Sar4jc@virginia.edu        // busy, and in the latter case the bus may be released before
26412137Sar4jc@virginia.edu        // we see a retry from the destination
26512137Sar4jc@virginia.edu        retryWaiting();
26612137Sar4jc@virginia.edu    } else if (drainManager) {
26712137Sar4jc@virginia.edu        DPRINTF(Drain, "Bus done draining, signaling drain manager\n");
26812137Sar4jc@virginia.edu        //If we weren't able to drain before, do it now.
26912137Sar4jc@virginia.edu        drainManager->signalDrainDone();
27012137Sar4jc@virginia.edu        // Clear the drain event once we're done with it.
27112137Sar4jc@virginia.edu        drainManager = NULL;
27212137Sar4jc@virginia.edu    }
27312137Sar4jc@virginia.edu}
27412137Sar4jc@virginia.edu
27512137Sar4jc@virginia.edutemplate <typename PortClass>
27612137Sar4jc@virginia.eduvoid
27712137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::retryWaiting()
27812137Sar4jc@virginia.edu{
27912137Sar4jc@virginia.edu    // this should never be called with an empty retry list
28012137Sar4jc@virginia.edu    assert(!retryList.empty());
28112137Sar4jc@virginia.edu
28212137Sar4jc@virginia.edu    // we always go to retrying from idle
28312137Sar4jc@virginia.edu    assert(state == IDLE);
28412137Sar4jc@virginia.edu
28512137Sar4jc@virginia.edu    // update the state which is shared for request, response and
28612137Sar4jc@virginia.edu    // snoop responses
28712137Sar4jc@virginia.edu    state = RETRY;
28812137Sar4jc@virginia.edu
28912137Sar4jc@virginia.edu    // note that we might have blocked on the receiving port being
29012137Sar4jc@virginia.edu    // busy (rather than the bus itself) and now call retry before the
29112137Sar4jc@virginia.edu    // destination called retry on the bus
29212137Sar4jc@virginia.edu    retryList.front()->sendRetry();
29312137Sar4jc@virginia.edu
29412137Sar4jc@virginia.edu    // If the bus is still in the retry state, sendTiming wasn't
29512137Sar4jc@virginia.edu    // called in zero time (e.g. the cache does this)
29612137Sar4jc@virginia.edu    if (state == RETRY) {
29712137Sar4jc@virginia.edu        retryList.pop_front();
29812137Sar4jc@virginia.edu
29912137Sar4jc@virginia.edu        //Burn a cycle for the missed grant.
30012137Sar4jc@virginia.edu
30112137Sar4jc@virginia.edu        // update the state which is shared for request, response and
30212137Sar4jc@virginia.edu        // snoop responses
30312137Sar4jc@virginia.edu        state = BUSY;
30412137Sar4jc@virginia.edu
30512137Sar4jc@virginia.edu        // occupy the bus layer until the next cycle ends
30612137Sar4jc@virginia.edu        occupyLayer(bus.clockEdge(Cycles(1)));
30712137Sar4jc@virginia.edu    }
30812137Sar4jc@virginia.edu}
30912137Sar4jc@virginia.edu
31012137Sar4jc@virginia.edutemplate <typename PortClass>
31112137Sar4jc@virginia.eduvoid
31212137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::recvRetry()
31312137Sar4jc@virginia.edu{
31412137Sar4jc@virginia.edu    // we got a retry from a peer that we tried to send something to
31512137Sar4jc@virginia.edu    // and failed, but we sent it on the account of someone else, and
31612137Sar4jc@virginia.edu    // that source port should be on our retry list, however if the
31712137Sar4jc@virginia.edu    // bus layer is released before this happens and the retry (from
31812137Sar4jc@virginia.edu    // the bus point of view) is successful then this no longer holds
31912137Sar4jc@virginia.edu    // and we could in fact have an empty retry list
32012137Sar4jc@virginia.edu    if (retryList.empty())
32112137Sar4jc@virginia.edu        return;
32212137Sar4jc@virginia.edu
32312137Sar4jc@virginia.edu    // if the bus layer is idle
32412137Sar4jc@virginia.edu    if (state == IDLE) {
32512137Sar4jc@virginia.edu        // note that we do not care who told us to retry at the moment, we
32612137Sar4jc@virginia.edu        // merely let the first one on the retry list go
32712137Sar4jc@virginia.edu        retryWaiting();
32812137Sar4jc@virginia.edu    }
32912137Sar4jc@virginia.edu}
33012137Sar4jc@virginia.edu
33112137Sar4jc@virginia.eduPortID
33212137Sar4jc@virginia.eduBaseBus::findPort(Addr addr)
33312137Sar4jc@virginia.edu{
33412137Sar4jc@virginia.edu    // we should never see any address lookups before we've got the
33512137Sar4jc@virginia.edu    // ranges of all connected slave modules
33612137Sar4jc@virginia.edu    assert(gotAllAddrRanges);
33712137Sar4jc@virginia.edu
33812137Sar4jc@virginia.edu    // Check the cache
33912137Sar4jc@virginia.edu    PortID dest_id = checkPortCache(addr);
34012137Sar4jc@virginia.edu    if (dest_id != InvalidPortID)
34112137Sar4jc@virginia.edu        return dest_id;
34212137Sar4jc@virginia.edu
34312137Sar4jc@virginia.edu    // Check the address map interval tree
34412137Sar4jc@virginia.edu    PortMapConstIter i = portMap.find(addr);
34512137Sar4jc@virginia.edu    if (i != portMap.end()) {
34612137Sar4jc@virginia.edu        dest_id = i->second;
34712137Sar4jc@virginia.edu        updatePortCache(dest_id, i->first);
34812137Sar4jc@virginia.edu        return dest_id;
34912137Sar4jc@virginia.edu    }
35012137Sar4jc@virginia.edu
35112137Sar4jc@virginia.edu    // Check if this matches the default range
35212137Sar4jc@virginia.edu    if (useDefaultRange) {
35312137Sar4jc@virginia.edu        if (defaultRange.contains(addr)) {
35412137Sar4jc@virginia.edu            DPRINTF(BusAddrRanges, "  found addr %#llx on default\n",
35512137Sar4jc@virginia.edu                    addr);
35612137Sar4jc@virginia.edu            return defaultPortID;
35712137Sar4jc@virginia.edu        }
35812137Sar4jc@virginia.edu    } else if (defaultPortID != InvalidPortID) {
35912137Sar4jc@virginia.edu        DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, "
36012137Sar4jc@virginia.edu                "will use default port\n", addr);
36112137Sar4jc@virginia.edu        return defaultPortID;
36212137Sar4jc@virginia.edu    }
36312137Sar4jc@virginia.edu
36412137Sar4jc@virginia.edu    // we should use the range for the default port and it did not
36512137Sar4jc@virginia.edu    // match, or the default port is not set
36612137Sar4jc@virginia.edu    fatal("Unable to find destination for addr %#llx on bus %s\n", addr,
36712137Sar4jc@virginia.edu          name());
36812137Sar4jc@virginia.edu}
36912137Sar4jc@virginia.edu
37012137Sar4jc@virginia.edu/** Function called by the port when the bus is receiving a range change.*/
37112137Sar4jc@virginia.eduvoid
37212137Sar4jc@virginia.eduBaseBus::recvRangeChange(PortID master_port_id)
37312137Sar4jc@virginia.edu{
37412137Sar4jc@virginia.edu    DPRINTF(BusAddrRanges, "Received range change from slave port %s\n",
37512137Sar4jc@virginia.edu            masterPorts[master_port_id]->getSlavePort().name());
37612137Sar4jc@virginia.edu
37712137Sar4jc@virginia.edu    // remember that we got a range from this master port and thus the
37812137Sar4jc@virginia.edu    // connected slave module
37912137Sar4jc@virginia.edu    gotAddrRanges[master_port_id] = true;
38012137Sar4jc@virginia.edu
38112137Sar4jc@virginia.edu    // update the global flag
38212137Sar4jc@virginia.edu    if (!gotAllAddrRanges) {
38312137Sar4jc@virginia.edu        // take a logical AND of all the ports and see if we got
38412137Sar4jc@virginia.edu        // ranges from everyone
38512137Sar4jc@virginia.edu        gotAllAddrRanges = true;
38612137Sar4jc@virginia.edu        std::vector<bool>::const_iterator r = gotAddrRanges.begin();
38712137Sar4jc@virginia.edu        while (gotAllAddrRanges &&  r != gotAddrRanges.end()) {
38812137Sar4jc@virginia.edu            gotAllAddrRanges &= *r++;
38912137Sar4jc@virginia.edu        }
39012137Sar4jc@virginia.edu        if (gotAllAddrRanges)
39112137Sar4jc@virginia.edu            DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n");
39212137Sar4jc@virginia.edu    }
39312137Sar4jc@virginia.edu
39412137Sar4jc@virginia.edu    // note that we could get the range from the default port at any
39512137Sar4jc@virginia.edu    // point in time, and we cannot assume that the default range is
39612137Sar4jc@virginia.edu    // set before the other ones are, so we do additional checks once
39712137Sar4jc@virginia.edu    // all ranges are provided
39812137Sar4jc@virginia.edu    if (master_port_id == defaultPortID) {
39912137Sar4jc@virginia.edu        // only update if we are indeed checking ranges for the
40012137Sar4jc@virginia.edu        // default port since the port might not have a valid range
40112137Sar4jc@virginia.edu        // otherwise
40212137Sar4jc@virginia.edu        if (useDefaultRange) {
40312137Sar4jc@virginia.edu            AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
40412137Sar4jc@virginia.edu
40512137Sar4jc@virginia.edu            if (ranges.size() != 1)
40612137Sar4jc@virginia.edu                fatal("Bus %s may only have a single default range",
40712137Sar4jc@virginia.edu                      name());
40812137Sar4jc@virginia.edu
40912137Sar4jc@virginia.edu            defaultRange = ranges.front();
41012137Sar4jc@virginia.edu        }
41112137Sar4jc@virginia.edu    } else {
41212137Sar4jc@virginia.edu        // the ports are allowed to update their address ranges
41312137Sar4jc@virginia.edu        // dynamically, so remove any existing entries
41412137Sar4jc@virginia.edu        if (gotAddrRanges[master_port_id]) {
41512137Sar4jc@virginia.edu            for (PortMapIter p = portMap.begin(); p != portMap.end(); ) {
41612137Sar4jc@virginia.edu                if (p->second == master_port_id)
41712137Sar4jc@virginia.edu                    // erasing invalidates the iterator, so advance it
41812137Sar4jc@virginia.edu                    // before the deletion takes place
41912137Sar4jc@virginia.edu                    portMap.erase(p++);
42012137Sar4jc@virginia.edu                else
42112137Sar4jc@virginia.edu                    p++;
42212137Sar4jc@virginia.edu            }
42312137Sar4jc@virginia.edu        }
42412137Sar4jc@virginia.edu
42512137Sar4jc@virginia.edu        AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
42612137Sar4jc@virginia.edu
42712137Sar4jc@virginia.edu        for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) {
42812137Sar4jc@virginia.edu            DPRINTF(BusAddrRanges, "Adding range %s for id %d\n",
42912137Sar4jc@virginia.edu                    r->to_string(), master_port_id);
43012137Sar4jc@virginia.edu            if (portMap.insert(*r, master_port_id) == portMap.end()) {
43112137Sar4jc@virginia.edu                PortID conflict_id = portMap.find(*r)->second;
43212137Sar4jc@virginia.edu                fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
43312137Sar4jc@virginia.edu                      name(),
43412137Sar4jc@virginia.edu                      masterPorts[master_port_id]->getSlavePort().name(),
43512137Sar4jc@virginia.edu                      masterPorts[conflict_id]->getSlavePort().name());
43612137Sar4jc@virginia.edu            }
43712137Sar4jc@virginia.edu        }
43812137Sar4jc@virginia.edu    }
43912137Sar4jc@virginia.edu
44012137Sar4jc@virginia.edu    // if we have received ranges from all our neighbouring slave
44112137Sar4jc@virginia.edu    // modules, go ahead and tell our connected master modules in
44212137Sar4jc@virginia.edu    // turn, this effectively assumes a tree structure of the system
44312137Sar4jc@virginia.edu    if (gotAllAddrRanges) {
44412137Sar4jc@virginia.edu        // also check that no range partially overlaps with the
44512137Sar4jc@virginia.edu        // default range, this has to be done after all ranges are set
44612137Sar4jc@virginia.edu        // as there are no guarantees for when the default range is
44712137Sar4jc@virginia.edu        // update with respect to the other ones
44812137Sar4jc@virginia.edu        if (useDefaultRange) {
44912137Sar4jc@virginia.edu            for (PortID port_id = 0; port_id < masterPorts.size(); ++port_id) {
45012137Sar4jc@virginia.edu                if (port_id == defaultPortID) {
45112137Sar4jc@virginia.edu                    if (!gotAddrRanges[port_id])
45212137Sar4jc@virginia.edu                        fatal("Bus %s uses default range, but none provided",
45312137Sar4jc@virginia.edu                              name());
45412137Sar4jc@virginia.edu                } else {
45512137Sar4jc@virginia.edu                    AddrRangeList ranges =
45612137Sar4jc@virginia.edu                        masterPorts[port_id]->getAddrRanges();
45712137Sar4jc@virginia.edu
45812137Sar4jc@virginia.edu                    for (AddrRangeConstIter r = ranges.begin();
45912137Sar4jc@virginia.edu                         r != ranges.end(); ++r) {
46012137Sar4jc@virginia.edu                        // see if the new range is partially
46112137Sar4jc@virginia.edu                        // overlapping the default range
46212137Sar4jc@virginia.edu                        if (r->intersects(defaultRange) &&
46312137Sar4jc@virginia.edu                            !r->isSubset(defaultRange))
46412137Sar4jc@virginia.edu                            fatal("Range %s intersects the " \
46512137Sar4jc@virginia.edu                                  "default range of %s but is not a " \
46612137Sar4jc@virginia.edu                                  "subset\n", r->to_string(), name());
46712137Sar4jc@virginia.edu                    }
46812137Sar4jc@virginia.edu                }
46912137Sar4jc@virginia.edu            }
47012137Sar4jc@virginia.edu        }
47112137Sar4jc@virginia.edu
47212137Sar4jc@virginia.edu        // tell all our neighbouring master ports that our address
47312137Sar4jc@virginia.edu        // ranges have changed
47412137Sar4jc@virginia.edu        for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end();
47512137Sar4jc@virginia.edu             ++s)
47612137Sar4jc@virginia.edu            (*s)->sendRangeChange();
47712137Sar4jc@virginia.edu    }
47812137Sar4jc@virginia.edu
47912137Sar4jc@virginia.edu    clearPortCache();
48012137Sar4jc@virginia.edu}
48112137Sar4jc@virginia.edu
48212137Sar4jc@virginia.eduAddrRangeList
48312137Sar4jc@virginia.eduBaseBus::getAddrRanges() const
48412137Sar4jc@virginia.edu{
48512137Sar4jc@virginia.edu    // we should never be asked without first having sent a range
48612137Sar4jc@virginia.edu    // change, and the latter is only done once we have all the ranges
48712137Sar4jc@virginia.edu    // of the connected devices
48812137Sar4jc@virginia.edu    assert(gotAllAddrRanges);
48912137Sar4jc@virginia.edu
49012137Sar4jc@virginia.edu    // at the moment, this never happens, as there are no cycles in
49112137Sar4jc@virginia.edu    // the range queries and no devices on the master side of a bus
49212137Sar4jc@virginia.edu    // (CPU, cache, bridge etc) actually care about the ranges of the
49312137Sar4jc@virginia.edu    // ports they are connected to
49412137Sar4jc@virginia.edu
49512137Sar4jc@virginia.edu    DPRINTF(BusAddrRanges, "Received address range request, returning:\n");
49612137Sar4jc@virginia.edu
49712137Sar4jc@virginia.edu    // start out with the default range
49812137Sar4jc@virginia.edu    AddrRangeList ranges;
49912137Sar4jc@virginia.edu    if (useDefaultRange) {
50012137Sar4jc@virginia.edu        ranges.push_back(defaultRange);
50112137Sar4jc@virginia.edu        DPRINTF(BusAddrRanges, "  -- Default %s\n", defaultRange.to_string());
50212137Sar4jc@virginia.edu    }
50312137Sar4jc@virginia.edu
50412137Sar4jc@virginia.edu    // add any range that is not a subset of the default range
50512137Sar4jc@virginia.edu    for (PortMapConstIter p = portMap.begin(); p != portMap.end(); ++p) {
50612137Sar4jc@virginia.edu        if (useDefaultRange && p->first.isSubset(defaultRange)) {
50712137Sar4jc@virginia.edu            DPRINTF(BusAddrRanges, "  -- %s is a subset of default\n",
50812137Sar4jc@virginia.edu                    p->first.to_string());
50912137Sar4jc@virginia.edu        } else {
51012137Sar4jc@virginia.edu            ranges.push_back(p->first);
51112137Sar4jc@virginia.edu            DPRINTF(BusAddrRanges, "  -- %s\n", p->first.to_string());
51212137Sar4jc@virginia.edu        }
51312137Sar4jc@virginia.edu    }
51412137Sar4jc@virginia.edu
51512137Sar4jc@virginia.edu    return ranges;
51612137Sar4jc@virginia.edu}
51712137Sar4jc@virginia.edu
51812137Sar4jc@virginia.eduunsigned
51912137Sar4jc@virginia.eduBaseBus::deviceBlockSize() const
52012137Sar4jc@virginia.edu{
52112137Sar4jc@virginia.edu    return blockSize;
52212137Sar4jc@virginia.edu}
52312137Sar4jc@virginia.edu
52412137Sar4jc@virginia.edutemplate <typename PortClass>
52512137Sar4jc@virginia.eduunsigned int
52612137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::drain(DrainManager *dm)
52712137Sar4jc@virginia.edu{
52812137Sar4jc@virginia.edu    //We should check that we're not "doing" anything, and that noone is
52912137Sar4jc@virginia.edu    //waiting. We might be idle but have someone waiting if the device we
53012137Sar4jc@virginia.edu    //contacted for a retry didn't actually retry.
53112137Sar4jc@virginia.edu    if (!retryList.empty() || state != IDLE) {
53212137Sar4jc@virginia.edu        DPRINTF(Drain, "Bus not drained\n");
53312137Sar4jc@virginia.edu        drainManager = dm;
53412137Sar4jc@virginia.edu        return 1;
53512137Sar4jc@virginia.edu    }
53612137Sar4jc@virginia.edu    return 0;
53712137Sar4jc@virginia.edu}
53812137Sar4jc@virginia.edu
53912137Sar4jc@virginia.edu/**
54012137Sar4jc@virginia.edu * Bus layer template instantiations. Could be removed with _impl.hh
54112137Sar4jc@virginia.edu * file, but since there are only two given options (MasterPort and
54212137Sar4jc@virginia.edu * SlavePort) it seems a bit excessive at this point.
54312137Sar4jc@virginia.edu */
54412137Sar4jc@virginia.edutemplate class BaseBus::Layer<SlavePort>;
54512137Sar4jc@virginia.edutemplate class BaseBus::Layer<MasterPort>;
54612137Sar4jc@virginia.edu