xbar.cc revision 9157
111731Sjason@lowepower.com/*
211731Sjason@lowepower.com * Copyright (c) 2011-2012 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      defaultPortID(InvalidPortID),
6112137Sar4jc@virginia.edu      useDefaultRange(p->use_default_range),
6212137Sar4jc@virginia.edu      defaultBlockSize(p->block_size),
6312137Sar4jc@virginia.edu      cachedBlockSize(0), cachedBlockSizeValid(false)
6412137Sar4jc@virginia.edu{
6512137Sar4jc@virginia.edu    //width, clock period, and header cycles must be positive
6612137Sar4jc@virginia.edu    if (width <= 0)
6712137Sar4jc@virginia.edu        fatal("Bus width must be positive\n");
6812137Sar4jc@virginia.edu    if (clock <= 0)
6912137Sar4jc@virginia.edu        fatal("Bus clock period must be positive\n");
7012137Sar4jc@virginia.edu    if (headerCycles <= 0)
7112137Sar4jc@virginia.edu        fatal("Number of header cycles must be positive\n");
7212137Sar4jc@virginia.edu}
7312137Sar4jc@virginia.edu
7412137Sar4jc@virginia.eduBaseBus::~BaseBus()
7512137Sar4jc@virginia.edu{
7612137Sar4jc@virginia.edu    for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end();
7712137Sar4jc@virginia.edu         ++m) {
7812137Sar4jc@virginia.edu        delete *m;
7912137Sar4jc@virginia.edu    }
8012137Sar4jc@virginia.edu
8112137Sar4jc@virginia.edu    for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end();
8212137Sar4jc@virginia.edu         ++s) {
8312137Sar4jc@virginia.edu        delete *s;
8412137Sar4jc@virginia.edu    }
8512137Sar4jc@virginia.edu}
8612137Sar4jc@virginia.edu
8712137Sar4jc@virginia.eduMasterPort &
8812137Sar4jc@virginia.eduBaseBus::getMasterPort(const std::string &if_name, int idx)
8912137Sar4jc@virginia.edu{
9012137Sar4jc@virginia.edu    if (if_name == "master" && idx < masterPorts.size()) {
9112137Sar4jc@virginia.edu        // the master port index translates directly to the vector position
9212137Sar4jc@virginia.edu        return *masterPorts[idx];
9312137Sar4jc@virginia.edu    } else  if (if_name == "default") {
9412137Sar4jc@virginia.edu        return *masterPorts[defaultPortID];
9512137Sar4jc@virginia.edu    } else {
9612137Sar4jc@virginia.edu        return MemObject::getMasterPort(if_name, idx);
9712137Sar4jc@virginia.edu    }
9812137Sar4jc@virginia.edu}
9912137Sar4jc@virginia.edu
10012137Sar4jc@virginia.eduSlavePort &
10112137Sar4jc@virginia.eduBaseBus::getSlavePort(const std::string &if_name, int idx)
10212137Sar4jc@virginia.edu{
10312137Sar4jc@virginia.edu    if (if_name == "slave" && idx < slavePorts.size()) {
10412137Sar4jc@virginia.edu        // the slave port index translates directly to the vector position
10512137Sar4jc@virginia.edu        return *slavePorts[idx];
10612137Sar4jc@virginia.edu    } else {
10712137Sar4jc@virginia.edu        return MemObject::getSlavePort(if_name, idx);
10812137Sar4jc@virginia.edu    }
10912137Sar4jc@virginia.edu}
11012137Sar4jc@virginia.edu
11112137Sar4jc@virginia.eduTick
11212137Sar4jc@virginia.eduBaseBus::calcPacketTiming(PacketPtr pkt)
11312137Sar4jc@virginia.edu{
11412137Sar4jc@virginia.edu    // determine the current time rounded to the closest following
11512137Sar4jc@virginia.edu    // clock edge
11612137Sar4jc@virginia.edu    Tick now = nextCycle();
11712137Sar4jc@virginia.edu
11812137Sar4jc@virginia.edu    Tick headerTime = now + headerCycles * clock;
11912137Sar4jc@virginia.edu
12012137Sar4jc@virginia.edu    // The packet will be sent. Figure out how long it occupies the bus, and
12112137Sar4jc@virginia.edu    // how much of that time is for the first "word", aka bus width.
12212137Sar4jc@virginia.edu    int numCycles = 0;
12312137Sar4jc@virginia.edu    if (pkt->hasData()) {
12412137Sar4jc@virginia.edu        // If a packet has data, it needs ceil(size/width) cycles to send it
12512137Sar4jc@virginia.edu        int dataSize = pkt->getSize();
12612137Sar4jc@virginia.edu        numCycles += dataSize/width;
12712137Sar4jc@virginia.edu        if (dataSize % width)
12812137Sar4jc@virginia.edu            numCycles++;
12912137Sar4jc@virginia.edu    }
13012137Sar4jc@virginia.edu
13112137Sar4jc@virginia.edu    // The first word will be delivered after the current tick, the delivery
13212137Sar4jc@virginia.edu    // of the address if any, and one bus cycle to deliver the data
13312137Sar4jc@virginia.edu    pkt->firstWordTime = headerTime + clock;
13412137Sar4jc@virginia.edu
13512137Sar4jc@virginia.edu    pkt->finishTime = headerTime + numCycles * clock;
13612137Sar4jc@virginia.edu
13712137Sar4jc@virginia.edu    return headerTime;
13812137Sar4jc@virginia.edu}
13912137Sar4jc@virginia.edu
14012137Sar4jc@virginia.edutemplate <typename PortClass>
14112137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name,
14212137Sar4jc@virginia.edu                                 Tick _clock) :
14312137Sar4jc@virginia.edu    bus(_bus), _name(_name), state(IDLE), clock(_clock), drainEvent(NULL),
14412137Sar4jc@virginia.edu    releaseEvent(this)
14512137Sar4jc@virginia.edu{
14612137Sar4jc@virginia.edu}
14712137Sar4jc@virginia.edu
14812137Sar4jc@virginia.edutemplate <typename PortClass>
14912137Sar4jc@virginia.eduvoid BaseBus::Layer<PortClass>::occupyLayer(Tick until)
15012137Sar4jc@virginia.edu{
15112137Sar4jc@virginia.edu    // ensure the state is busy or in retry and never idle at this
15212137Sar4jc@virginia.edu    // point, as the bus should transition from idle as soon as it has
15312137Sar4jc@virginia.edu    // decided to forward the packet to prevent any follow-on calls to
15412137Sar4jc@virginia.edu    // sendTiming seeing an unoccupied bus
15512137Sar4jc@virginia.edu    assert(state != IDLE);
15612137Sar4jc@virginia.edu
15712137Sar4jc@virginia.edu    // note that we do not change the bus state here, if we are going
15812137Sar4jc@virginia.edu    // from idle to busy it is handled by tryTiming, and if we
15912137Sar4jc@virginia.edu    // are in retry we should remain in retry such that
16012137Sar4jc@virginia.edu    // succeededTiming still sees the accurate state
16112137Sar4jc@virginia.edu
16212137Sar4jc@virginia.edu    // until should never be 0 as express snoops never occupy the bus
16312137Sar4jc@virginia.edu    assert(until != 0);
16412137Sar4jc@virginia.edu    bus.schedule(releaseEvent, until);
16512137Sar4jc@virginia.edu
16612137Sar4jc@virginia.edu    DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n",
16712137Sar4jc@virginia.edu            curTick(), until);
16812137Sar4jc@virginia.edu}
16912137Sar4jc@virginia.edu
17012137Sar4jc@virginia.edutemplate <typename PortClass>
17112137Sar4jc@virginia.edubool
17212137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::tryTiming(PortClass* port)
17312137Sar4jc@virginia.edu{
17412137Sar4jc@virginia.edu    // first we see if the bus is busy, next we check if we are in a
17512137Sar4jc@virginia.edu    // retry with a port other than the current one
17612137Sar4jc@virginia.edu    if (state == BUSY || (state == RETRY && port != retryList.front())) {
17712137Sar4jc@virginia.edu        // put the port at the end of the retry list
17812137Sar4jc@virginia.edu        retryList.push_back(port);
17912137Sar4jc@virginia.edu        return false;
18012137Sar4jc@virginia.edu    }
18112137Sar4jc@virginia.edu
18212137Sar4jc@virginia.edu    // update the state which is shared for request, response and
18312137Sar4jc@virginia.edu    // snoop responses, if we were idle we are now busy, if we are in
18412137Sar4jc@virginia.edu    // a retry, then do not change
18512137Sar4jc@virginia.edu    if (state == IDLE)
18612137Sar4jc@virginia.edu        state = BUSY;
18712137Sar4jc@virginia.edu
18812137Sar4jc@virginia.edu    return true;
18912137Sar4jc@virginia.edu}
19012137Sar4jc@virginia.edu
19112137Sar4jc@virginia.edutemplate <typename PortClass>
19212137Sar4jc@virginia.eduvoid
19312137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::succeededTiming(Tick busy_time)
19412137Sar4jc@virginia.edu{
19512137Sar4jc@virginia.edu    // if a retrying port succeeded, also take it off the retry list
19612137Sar4jc@virginia.edu    if (state == RETRY) {
19712137Sar4jc@virginia.edu        DPRINTF(BaseBus, "Remove retry from list %s\n",
19812137Sar4jc@virginia.edu                retryList.front()->name());
19912137Sar4jc@virginia.edu        retryList.pop_front();
20012137Sar4jc@virginia.edu        state = BUSY;
20112137Sar4jc@virginia.edu    }
20212137Sar4jc@virginia.edu
20312137Sar4jc@virginia.edu    // we should either have gone from idle to busy in the
20412137Sar4jc@virginia.edu    // tryTiming test, or just gone from a retry to busy
20512137Sar4jc@virginia.edu    assert(state == BUSY);
20612137Sar4jc@virginia.edu
20712137Sar4jc@virginia.edu    // occupy the bus accordingly
20812137Sar4jc@virginia.edu    occupyLayer(busy_time);
20912137Sar4jc@virginia.edu}
21012137Sar4jc@virginia.edu
21112137Sar4jc@virginia.edutemplate <typename PortClass>
21212137Sar4jc@virginia.eduvoid
21312137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time)
21412137Sar4jc@virginia.edu{
21512137Sar4jc@virginia.edu    // if we are not in a retry, i.e. busy (but never idle), or we are
21612137Sar4jc@virginia.edu    // in a retry but not for the current port, then add the port at
21712137Sar4jc@virginia.edu    // the end of the retry list
21812137Sar4jc@virginia.edu    if (state != RETRY || port != retryList.front()) {
21912137Sar4jc@virginia.edu        retryList.push_back(port);
22012137Sar4jc@virginia.edu    }
22112137Sar4jc@virginia.edu
22212137Sar4jc@virginia.edu    // even if we retried the current one and did not succeed,
22312137Sar4jc@virginia.edu    // we are no longer retrying but instead busy
22412137Sar4jc@virginia.edu    state = BUSY;
22512137Sar4jc@virginia.edu
22612137Sar4jc@virginia.edu    // occupy the bus accordingly
22712137Sar4jc@virginia.edu    occupyLayer(busy_time);
22812137Sar4jc@virginia.edu}
22912137Sar4jc@virginia.edu
23012137Sar4jc@virginia.edutemplate <typename PortClass>
23112137Sar4jc@virginia.eduvoid
23212137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::releaseLayer()
23312137Sar4jc@virginia.edu{
23412137Sar4jc@virginia.edu    // releasing the bus means we should now be idle
23512137Sar4jc@virginia.edu    assert(state == BUSY);
23612137Sar4jc@virginia.edu    assert(!releaseEvent.scheduled());
23712137Sar4jc@virginia.edu
23812137Sar4jc@virginia.edu    // update the state
23912137Sar4jc@virginia.edu    state = IDLE;
24012137Sar4jc@virginia.edu
24112137Sar4jc@virginia.edu    // bus is now idle, so if someone is waiting we can retry
24212137Sar4jc@virginia.edu    if (!retryList.empty()) {
24312137Sar4jc@virginia.edu        // note that we block (return false on recvTiming) both
24412137Sar4jc@virginia.edu        // because the bus is busy and because the destination is
24512137Sar4jc@virginia.edu        // busy, and in the latter case the bus may be released before
24612137Sar4jc@virginia.edu        // we see a retry from the destination
24712137Sar4jc@virginia.edu        retryWaiting();
24812137Sar4jc@virginia.edu    } else if (drainEvent) {
24912137Sar4jc@virginia.edu        DPRINTF(Drain, "Bus done draining, processing drain event\n");
25012137Sar4jc@virginia.edu        //If we weren't able to drain before, do it now.
25112137Sar4jc@virginia.edu        drainEvent->process();
25212137Sar4jc@virginia.edu        // Clear the drain event once we're done with it.
25312137Sar4jc@virginia.edu        drainEvent = NULL;
25412137Sar4jc@virginia.edu    }
25512137Sar4jc@virginia.edu}
25612137Sar4jc@virginia.edu
25712137Sar4jc@virginia.edutemplate <typename PortClass>
25812137Sar4jc@virginia.eduvoid
25912137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::retryWaiting()
26012137Sar4jc@virginia.edu{
26112137Sar4jc@virginia.edu    // this should never be called with an empty retry list
26212137Sar4jc@virginia.edu    assert(!retryList.empty());
26312137Sar4jc@virginia.edu
26412137Sar4jc@virginia.edu    // we always go to retrying from idle
26512137Sar4jc@virginia.edu    assert(state == IDLE);
26612137Sar4jc@virginia.edu
26712137Sar4jc@virginia.edu    // update the state which is shared for request, response and
26812137Sar4jc@virginia.edu    // snoop responses
26912137Sar4jc@virginia.edu    state = RETRY;
27012137Sar4jc@virginia.edu
27112137Sar4jc@virginia.edu    // note that we might have blocked on the receiving port being
27212137Sar4jc@virginia.edu    // busy (rather than the bus itself) and now call retry before the
27312137Sar4jc@virginia.edu    // destination called retry on the bus
27412137Sar4jc@virginia.edu    retryList.front()->sendRetry();
27512137Sar4jc@virginia.edu
27612137Sar4jc@virginia.edu    // If the bus is still in the retry state, sendTiming wasn't
27712137Sar4jc@virginia.edu    // called in zero time (e.g. the cache does this)
27812137Sar4jc@virginia.edu    if (state == RETRY) {
27912137Sar4jc@virginia.edu        retryList.pop_front();
28012137Sar4jc@virginia.edu
28112137Sar4jc@virginia.edu        //Burn a cycle for the missed grant.
28212137Sar4jc@virginia.edu
28312137Sar4jc@virginia.edu        // update the state which is shared for request, response and
28412137Sar4jc@virginia.edu        // snoop responses
28512137Sar4jc@virginia.edu        state = BUSY;
28612137Sar4jc@virginia.edu
28712137Sar4jc@virginia.edu        // determine the current time rounded to the closest following
28812137Sar4jc@virginia.edu        // clock edge
28912137Sar4jc@virginia.edu        Tick now = bus.nextCycle();
29012137Sar4jc@virginia.edu
29112137Sar4jc@virginia.edu        occupyLayer(now + clock);
29212137Sar4jc@virginia.edu    }
29312137Sar4jc@virginia.edu}
29412137Sar4jc@virginia.edu
29512137Sar4jc@virginia.edutemplate <typename PortClass>
29612137Sar4jc@virginia.eduvoid
29712137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::recvRetry()
29812137Sar4jc@virginia.edu{
29912137Sar4jc@virginia.edu    // we got a retry from a peer that we tried to send something to
30012137Sar4jc@virginia.edu    // and failed, but we sent it on the account of someone else, and
30112137Sar4jc@virginia.edu    // that source port should be on our retry list, however if the
30212137Sar4jc@virginia.edu    // bus layer is released before this happens and the retry (from
30312137Sar4jc@virginia.edu    // the bus point of view) is successful then this no longer holds
30412137Sar4jc@virginia.edu    // and we could in fact have an empty retry list
30512137Sar4jc@virginia.edu    if (retryList.empty())
30612137Sar4jc@virginia.edu        return;
30712137Sar4jc@virginia.edu
30812137Sar4jc@virginia.edu    // if the bus layer is idle
30912137Sar4jc@virginia.edu    if (state == IDLE) {
31012137Sar4jc@virginia.edu        // note that we do not care who told us to retry at the moment, we
31112137Sar4jc@virginia.edu        // merely let the first one on the retry list go
31212137Sar4jc@virginia.edu        retryWaiting();
31312137Sar4jc@virginia.edu    }
31412137Sar4jc@virginia.edu}
31512137Sar4jc@virginia.edu
31612137Sar4jc@virginia.eduPortID
31712137Sar4jc@virginia.eduBaseBus::findPort(Addr addr)
31812137Sar4jc@virginia.edu{
31912137Sar4jc@virginia.edu    /* An interval tree would be a better way to do this. --ali. */
32012137Sar4jc@virginia.edu    PortID dest_id = checkPortCache(addr);
32112137Sar4jc@virginia.edu    if (dest_id != InvalidPortID)
32212137Sar4jc@virginia.edu        return dest_id;
32312137Sar4jc@virginia.edu
32412137Sar4jc@virginia.edu    // Check normal port ranges
32512137Sar4jc@virginia.edu    PortMapConstIter i = portMap.find(RangeSize(addr,1));
32612137Sar4jc@virginia.edu    if (i != portMap.end()) {
32712137Sar4jc@virginia.edu        dest_id = i->second;
32812137Sar4jc@virginia.edu        updatePortCache(dest_id, i->first.start, i->first.end);
32912137Sar4jc@virginia.edu        return dest_id;
33012137Sar4jc@virginia.edu    }
33112137Sar4jc@virginia.edu
33212137Sar4jc@virginia.edu    // Check if this matches the default range
33312137Sar4jc@virginia.edu    if (useDefaultRange) {
33412137Sar4jc@virginia.edu        AddrRangeConstIter a_end = defaultRange.end();
33512137Sar4jc@virginia.edu        for (AddrRangeConstIter i = defaultRange.begin(); i != a_end; i++) {
33612137Sar4jc@virginia.edu            if (*i == addr) {
33712137Sar4jc@virginia.edu                DPRINTF(BusAddrRanges, "  found addr %#llx on default\n",
33812137Sar4jc@virginia.edu                        addr);
33912137Sar4jc@virginia.edu                return defaultPortID;
34012137Sar4jc@virginia.edu            }
34112137Sar4jc@virginia.edu        }
34212137Sar4jc@virginia.edu    } else if (defaultPortID != InvalidPortID) {
34312137Sar4jc@virginia.edu        DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, "
34412137Sar4jc@virginia.edu                "will use default port\n", addr);
34512137Sar4jc@virginia.edu        return defaultPortID;
34612137Sar4jc@virginia.edu    }
34712137Sar4jc@virginia.edu
34812137Sar4jc@virginia.edu    // we should use the range for the default port and it did not
34912137Sar4jc@virginia.edu    // match, or the default port is not set
35012137Sar4jc@virginia.edu    fatal("Unable to find destination for addr %#llx on bus %s\n", addr,
35112137Sar4jc@virginia.edu          name());
35212137Sar4jc@virginia.edu}
35312137Sar4jc@virginia.edu
35412137Sar4jc@virginia.edu/** Function called by the port when the bus is receiving a range change.*/
35512137Sar4jc@virginia.eduvoid
35612137Sar4jc@virginia.eduBaseBus::recvRangeChange(PortID master_port_id)
35712137Sar4jc@virginia.edu{
35812137Sar4jc@virginia.edu    AddrRangeList ranges;
35912137Sar4jc@virginia.edu    AddrRangeIter iter;
36012137Sar4jc@virginia.edu
36112137Sar4jc@virginia.edu    if (inRecvRangeChange.count(master_port_id))
36212137Sar4jc@virginia.edu        return;
36312137Sar4jc@virginia.edu    inRecvRangeChange.insert(master_port_id);
36412137Sar4jc@virginia.edu
36512137Sar4jc@virginia.edu    DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n",
36612137Sar4jc@virginia.edu            master_port_id);
36712137Sar4jc@virginia.edu
36812137Sar4jc@virginia.edu    clearPortCache();
36912137Sar4jc@virginia.edu    if (master_port_id == defaultPortID) {
37012137Sar4jc@virginia.edu        defaultRange.clear();
37112137Sar4jc@virginia.edu        // Only try to update these ranges if the user set a default responder.
37212137Sar4jc@virginia.edu        if (useDefaultRange) {
37312137Sar4jc@virginia.edu            // get the address ranges of the connected slave port
37412137Sar4jc@virginia.edu            AddrRangeList ranges =
37512137Sar4jc@virginia.edu                masterPorts[master_port_id]->getAddrRanges();
37612137Sar4jc@virginia.edu            for(iter = ranges.begin(); iter != ranges.end(); iter++) {
37712137Sar4jc@virginia.edu                defaultRange.push_back(*iter);
37812137Sar4jc@virginia.edu                DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
37912137Sar4jc@virginia.edu                        iter->start, iter->end);
38012137Sar4jc@virginia.edu            }
38112137Sar4jc@virginia.edu        }
38212137Sar4jc@virginia.edu    } else {
38312137Sar4jc@virginia.edu
38412137Sar4jc@virginia.edu        assert(master_port_id < masterPorts.size() && master_port_id >= 0);
38512137Sar4jc@virginia.edu        MasterPort *port = masterPorts[master_port_id];
38612137Sar4jc@virginia.edu
38712137Sar4jc@virginia.edu        // Clean out any previously existent ids
38812137Sar4jc@virginia.edu        for (PortMapIter portIter = portMap.begin();
38912137Sar4jc@virginia.edu             portIter != portMap.end(); ) {
39012137Sar4jc@virginia.edu            if (portIter->second == master_port_id)
39112137Sar4jc@virginia.edu                portMap.erase(portIter++);
39212137Sar4jc@virginia.edu            else
39312137Sar4jc@virginia.edu                portIter++;
39412137Sar4jc@virginia.edu        }
39512137Sar4jc@virginia.edu
39612137Sar4jc@virginia.edu        // get the address ranges of the connected slave port
39712137Sar4jc@virginia.edu        ranges = port->getAddrRanges();
39812137Sar4jc@virginia.edu
39912137Sar4jc@virginia.edu        for (iter = ranges.begin(); iter != ranges.end(); iter++) {
40012137Sar4jc@virginia.edu            DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
40112137Sar4jc@virginia.edu                    iter->start, iter->end, master_port_id);
40212137Sar4jc@virginia.edu            if (portMap.insert(*iter, master_port_id) == portMap.end()) {
40312137Sar4jc@virginia.edu                PortID conflict_id = portMap.find(*iter)->second;
40412137Sar4jc@virginia.edu                fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
40512137Sar4jc@virginia.edu                      name(),
40612137Sar4jc@virginia.edu                      masterPorts[master_port_id]->getSlavePort().name(),
40712137Sar4jc@virginia.edu                      masterPorts[conflict_id]->getSlavePort().name());
40812137Sar4jc@virginia.edu            }
40912137Sar4jc@virginia.edu        }
41012137Sar4jc@virginia.edu    }
41112137Sar4jc@virginia.edu    DPRINTF(BusAddrRanges, "port list has %d entries\n", portMap.size());
41212137Sar4jc@virginia.edu
41312137Sar4jc@virginia.edu    // tell all our neighbouring master ports that our address range
41412137Sar4jc@virginia.edu    // has changed
41512137Sar4jc@virginia.edu    for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end();
41612137Sar4jc@virginia.edu         ++p)
41712137Sar4jc@virginia.edu        (*p)->sendRangeChange();
41812137Sar4jc@virginia.edu
41912137Sar4jc@virginia.edu    inRecvRangeChange.erase(master_port_id);
42012137Sar4jc@virginia.edu}
42112137Sar4jc@virginia.edu
42212137Sar4jc@virginia.eduAddrRangeList
42312137Sar4jc@virginia.eduBaseBus::getAddrRanges() const
42412137Sar4jc@virginia.edu{
42512137Sar4jc@virginia.edu    AddrRangeList ranges;
42612137Sar4jc@virginia.edu
42712137Sar4jc@virginia.edu    DPRINTF(BusAddrRanges, "received address range request, returning:\n");
42812137Sar4jc@virginia.edu
42912137Sar4jc@virginia.edu    for (AddrRangeConstIter dflt_iter = defaultRange.begin();
43012137Sar4jc@virginia.edu         dflt_iter != defaultRange.end(); dflt_iter++) {
43112137Sar4jc@virginia.edu        ranges.push_back(*dflt_iter);
43212137Sar4jc@virginia.edu        DPRINTF(BusAddrRanges, "  -- Dflt: %#llx : %#llx\n",dflt_iter->start,
43312137Sar4jc@virginia.edu                dflt_iter->end);
43412137Sar4jc@virginia.edu    }
43512137Sar4jc@virginia.edu    for (PortMapConstIter portIter = portMap.begin();
43612137Sar4jc@virginia.edu         portIter != portMap.end(); portIter++) {
43712137Sar4jc@virginia.edu        bool subset = false;
43812137Sar4jc@virginia.edu        for (AddrRangeConstIter dflt_iter = defaultRange.begin();
43912137Sar4jc@virginia.edu             dflt_iter != defaultRange.end(); dflt_iter++) {
44012137Sar4jc@virginia.edu            if ((portIter->first.start < dflt_iter->start &&
44112137Sar4jc@virginia.edu                portIter->first.end >= dflt_iter->start) ||
44212137Sar4jc@virginia.edu               (portIter->first.start < dflt_iter->end &&
44312137Sar4jc@virginia.edu                portIter->first.end >= dflt_iter->end))
44412137Sar4jc@virginia.edu                fatal("Devices can not set ranges that itersect the default set\
44512137Sar4jc@virginia.edu                        but are not a subset of the default set.\n");
44612137Sar4jc@virginia.edu            if (portIter->first.start >= dflt_iter->start &&
44712137Sar4jc@virginia.edu                portIter->first.end <= dflt_iter->end) {
44812137Sar4jc@virginia.edu                subset = true;
44912137Sar4jc@virginia.edu                DPRINTF(BusAddrRanges, "  -- %#llx : %#llx is a SUBSET\n",
45012137Sar4jc@virginia.edu                    portIter->first.start, portIter->first.end);
45112137Sar4jc@virginia.edu            }
45212137Sar4jc@virginia.edu        }
45312137Sar4jc@virginia.edu        if (!subset) {
45412137Sar4jc@virginia.edu            ranges.push_back(portIter->first);
45512137Sar4jc@virginia.edu            DPRINTF(BusAddrRanges, "  -- %#llx : %#llx\n",
45612137Sar4jc@virginia.edu                    portIter->first.start, portIter->first.end);
45712137Sar4jc@virginia.edu        }
45812137Sar4jc@virginia.edu    }
45912137Sar4jc@virginia.edu
46012137Sar4jc@virginia.edu    return ranges;
46112137Sar4jc@virginia.edu}
46212137Sar4jc@virginia.edu
46312137Sar4jc@virginia.eduunsigned
46412137Sar4jc@virginia.eduBaseBus::findBlockSize()
46512137Sar4jc@virginia.edu{
46612137Sar4jc@virginia.edu    if (cachedBlockSizeValid)
46712137Sar4jc@virginia.edu        return cachedBlockSize;
46812137Sar4jc@virginia.edu
46912137Sar4jc@virginia.edu    unsigned max_bs = 0;
47012137Sar4jc@virginia.edu
47112137Sar4jc@virginia.edu    for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end();
47212137Sar4jc@virginia.edu         ++m) {
47312137Sar4jc@virginia.edu        unsigned tmp_bs = (*m)->peerBlockSize();
47412137Sar4jc@virginia.edu        if (tmp_bs > max_bs)
47512137Sar4jc@virginia.edu            max_bs = tmp_bs;
47612137Sar4jc@virginia.edu    }
47712137Sar4jc@virginia.edu
47812137Sar4jc@virginia.edu    for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end();
47912137Sar4jc@virginia.edu         ++s) {
48012137Sar4jc@virginia.edu        unsigned tmp_bs = (*s)->peerBlockSize();
48112137Sar4jc@virginia.edu        if (tmp_bs > max_bs)
48212137Sar4jc@virginia.edu            max_bs = tmp_bs;
48312137Sar4jc@virginia.edu    }
48412137Sar4jc@virginia.edu    if (max_bs == 0)
48512137Sar4jc@virginia.edu        max_bs = defaultBlockSize;
48612137Sar4jc@virginia.edu
48712137Sar4jc@virginia.edu    if (max_bs != 64)
48812137Sar4jc@virginia.edu        warn_once("Blocksize found to not be 64... hmm... probably not.\n");
48912137Sar4jc@virginia.edu    cachedBlockSize = max_bs;
49012137Sar4jc@virginia.edu    cachedBlockSizeValid = true;
49112137Sar4jc@virginia.edu    return max_bs;
49212137Sar4jc@virginia.edu}
49312137Sar4jc@virginia.edu
49412137Sar4jc@virginia.edutemplate <typename PortClass>
49512137Sar4jc@virginia.eduunsigned int
49612137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::drain(Event * de)
49712137Sar4jc@virginia.edu{
49812137Sar4jc@virginia.edu    //We should check that we're not "doing" anything, and that noone is
49912137Sar4jc@virginia.edu    //waiting. We might be idle but have someone waiting if the device we
50012137Sar4jc@virginia.edu    //contacted for a retry didn't actually retry.
50112137Sar4jc@virginia.edu    if (!retryList.empty() || state != IDLE) {
50212137Sar4jc@virginia.edu        DPRINTF(Drain, "Bus not drained\n");
50312137Sar4jc@virginia.edu        drainEvent = de;
50412137Sar4jc@virginia.edu        return 1;
50512137Sar4jc@virginia.edu    }
50612137Sar4jc@virginia.edu    return 0;
50712137Sar4jc@virginia.edu}
50812137Sar4jc@virginia.edu
50912137Sar4jc@virginia.edu/**
51012137Sar4jc@virginia.edu * Bus layer template instantiations. Could be removed with _impl.hh
51112137Sar4jc@virginia.edu * file, but since there are only two given options (MasterPort and
51212137Sar4jc@virginia.edu * SlavePort) it seems a bit excessive at this point.
51312137Sar4jc@virginia.edu */
51412137Sar4jc@virginia.edutemplate class BaseBus::Layer<SlavePort>;
51512137Sar4jc@virginia.edutemplate class BaseBus::Layer<MasterPort>;
51612137Sar4jc@virginia.edu