xbar.cc revision 12776:410b60d8a397
12568SN/A/*
212652Sandreas.sandberg@arm.com * Copyright (c) 2011-2015, 2018 ARM Limited
38668Sgeoffrey.blake@arm.com * All rights reserved
48668Sgeoffrey.blake@arm.com *
58668Sgeoffrey.blake@arm.com * The license below extends only to copyright in the software and shall
68668Sgeoffrey.blake@arm.com * not be construed as granting a license to any other intellectual
78668Sgeoffrey.blake@arm.com * property including but not limited to intellectual property relating
88668Sgeoffrey.blake@arm.com * to a hardware implementation of the functionality of the software
98668Sgeoffrey.blake@arm.com * licensed hereunder.  You may use the software subject to the license
108668Sgeoffrey.blake@arm.com * terms below provided that you ensure that this notice is replicated
118668Sgeoffrey.blake@arm.com * unmodified and in its entirety in all distributions of the software,
128668Sgeoffrey.blake@arm.com * modified or unmodified, in source code or in binary form.
138668Sgeoffrey.blake@arm.com *
142568SN/A * Copyright (c) 2006 The Regents of The University of Michigan
1510975Sdavid.hashe@amd.com * All rights reserved.
162568SN/A *
172568SN/A * Redistribution and use in source and binary forms, with or without
182568SN/A * modification, are permitted provided that the following conditions are
192568SN/A * met: redistributions of source code must retain the above copyright
202568SN/A * notice, this list of conditions and the following disclaimer;
212568SN/A * redistributions in binary form must reproduce the above copyright
222568SN/A * notice, this list of conditions and the following disclaimer in the
232568SN/A * documentation and/or other materials provided with the distribution;
242568SN/A * neither the name of the copyright holders nor the names of its
252568SN/A * contributors may be used to endorse or promote products derived from
262568SN/A * this software without specific prior written permission.
272568SN/A *
282568SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292568SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302568SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312568SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322568SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332568SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342568SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352568SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362568SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372568SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382568SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392568SN/A *
402665Ssaidi@eecs.umich.edu * Authors: Ali Saidi
412665Ssaidi@eecs.umich.edu *          Andreas Hansson
422665Ssaidi@eecs.umich.edu *          William Wang
432568SN/A */
442568SN/A
452568SN/A/**
462568SN/A * @file
472568SN/A * Definition of a crossbar object.
482568SN/A */
492568SN/A
503260Ssaidi@eecs.umich.edu#include "mem/xbar.hh"
5111793Sbrandon.potter@amd.com
5211793Sbrandon.potter@amd.com#include "base/logging.hh"
538229Snate@binkert.org#include "base/trace.hh"
543260Ssaidi@eecs.umich.edu#include "debug/AddrRanges.hh"
558229Snate@binkert.org#include "debug/Drain.hh"
565314Sstever@gmail.com#include "debug/XBar.hh"
5712334Sgabeblack@google.com
583348Sbinkertn@umich.eduBaseXBar::BaseXBar(const BaseXBarParams *p)
5912652Sandreas.sandberg@arm.com    : MemObject(p),
602568SN/A      frontendLatency(p->frontend_latency),
615735Snate@binkert.org      forwardLatency(p->forward_latency),
625735Snate@binkert.org      responseLatency(p->response_latency),
634022Sstever@eecs.umich.edu      width(p->width),
644022Sstever@eecs.umich.edu      gotAddrRanges(p->port_default_connection_count +
654022Sstever@eecs.umich.edu                          p->port_master_connection_count, false),
664022Sstever@eecs.umich.edu      gotAllAddrRanges(false), defaultPortID(InvalidPortID),
674022Sstever@eecs.umich.edu      useDefaultRange(p->use_default_range)
684022Sstever@eecs.umich.edu{}
694022Sstever@eecs.umich.edu
7011600Sandreas.hansson@arm.comBaseXBar::~BaseXBar()
7111600Sandreas.hansson@arm.com{
722641Sstever@eecs.umich.edu    for (auto m: masterPorts)
734022Sstever@eecs.umich.edu        delete m;
744022Sstever@eecs.umich.edu
752641Sstever@eecs.umich.edu    for (auto s: slavePorts)
764022Sstever@eecs.umich.edu        delete s;
774022Sstever@eecs.umich.edu}
7810885Sandreas.hansson@arm.com
7910885Sandreas.hansson@arm.comvoid
804022Sstever@eecs.umich.eduBaseXBar::init()
814473Sstever@eecs.umich.edu{
824473Sstever@eecs.umich.edu}
835319Sstever@gmail.com
845319Sstever@gmail.comBaseMasterPort &
855319Sstever@gmail.comBaseXBar::getMasterPort(const std::string &if_name, PortID idx)
864022Sstever@eecs.umich.edu{
8711284Sandreas.hansson@arm.com    if (if_name == "master" && idx < masterPorts.size()) {
884022Sstever@eecs.umich.edu        // the master port index translates directly to the vector position
894022Sstever@eecs.umich.edu        return *masterPorts[idx];
9011287Sandreas.hansson@arm.com    } else  if (if_name == "default") {
9111199Sandreas.hansson@arm.com        return *masterPorts[defaultPortID];
9211600Sandreas.hansson@arm.com    } else {
9311199Sandreas.hansson@arm.com        return MemObject::getMasterPort(if_name, idx);
9411199Sandreas.hansson@arm.com    }
9511199Sandreas.hansson@arm.com}
9611199Sandreas.hansson@arm.com
9711600Sandreas.hansson@arm.comBaseSlavePort &
9811199Sandreas.hansson@arm.comBaseXBar::getSlavePort(const std::string &if_name, PortID idx)
9912344Snikos.nikoleris@arm.com{
10012344Snikos.nikoleris@arm.com    if (if_name == "slave" && idx < slavePorts.size()) {
10112344Snikos.nikoleris@arm.com        // the slave port index translates directly to the vector position
10210883Sali.jafri@arm.com        return *slavePorts[idx];
10311600Sandreas.hansson@arm.com    } else {
1044022Sstever@eecs.umich.edu        return MemObject::getSlavePort(if_name, idx);
1054022Sstever@eecs.umich.edu    }
1064022Sstever@eecs.umich.edu}
1074022Sstever@eecs.umich.edu
10811600Sandreas.hansson@arm.comvoid
1094022Sstever@eecs.umich.eduBaseXBar::calcPacketTiming(PacketPtr pkt, Tick header_delay)
1104022Sstever@eecs.umich.edu{
1114022Sstever@eecs.umich.edu    // the crossbar will be called at a time that is not necessarily
1124022Sstever@eecs.umich.edu    // coinciding with its own clock, so start by determining how long
1134022Sstever@eecs.umich.edu    // until the next clock edge (could be zero)
1144022Sstever@eecs.umich.edu    Tick offset = clockEdge() - curTick();
1154022Sstever@eecs.umich.edu
11610886Sandreas.hansson@arm.com    // the header delay depends on the path through the crossbar, and
11711284Sandreas.hansson@arm.com    // we therefore rely on the caller to provide the actual
11810886Sandreas.hansson@arm.com    // value
1194022Sstever@eecs.umich.edu    pkt->headerDelay += offset + header_delay;
12011600Sandreas.hansson@arm.com
12111600Sandreas.hansson@arm.com    // note that we add the header delay to the existing value, and
1224628Sstever@eecs.umich.edu    // align it to the crossbar clock
1237465Ssteve.reinhardt@amd.com
12411600Sandreas.hansson@arm.com    // do a quick sanity check to ensure the timings are not being
12511600Sandreas.hansson@arm.com    // ignored, note that this specific value may cause problems for
1267465Ssteve.reinhardt@amd.com    // slower interconnects
1274628Sstever@eecs.umich.edu    panic_if(pkt->headerDelay > SimClock::Int::us,
12811287Sandreas.hansson@arm.com             "Encountered header delay exceeding 1 us\n");
1297465Ssteve.reinhardt@amd.com
13010325Sgeoffrey.blake@arm.com    if (pkt->hasData()) {
13111600Sandreas.hansson@arm.com        // the payloadDelay takes into account the relative time to
13211600Sandreas.hansson@arm.com        // deliver the payload of the packet, after the header delay,
1337465Ssteve.reinhardt@amd.com        // we take the maximum since the payload delay could already
13410325Sgeoffrey.blake@arm.com        // be longer than what this parcitular crossbar enforces.
13510325Sgeoffrey.blake@arm.com        pkt->payloadDelay = std::max<Tick>(pkt->payloadDelay,
13611287Sandreas.hansson@arm.com                                           divCeil(pkt->getSize(), width) *
1377465Ssteve.reinhardt@amd.com                                           clockPeriod());
13810885Sandreas.hansson@arm.com    }
13910885Sandreas.hansson@arm.com
14010885Sandreas.hansson@arm.com    // the payload delay is not paying for the clock offset as that is
14111600Sandreas.hansson@arm.com    // already done using the header delay, and the payload delay is
14211600Sandreas.hansson@arm.com    // also used to determine how long the crossbar layer is busy and
1434022Sstever@eecs.umich.edu    // thus regulates throughput
14410885Sandreas.hansson@arm.com}
14510885Sandreas.hansson@arm.com
14611287Sandreas.hansson@arm.comtemplate <typename SrcType, typename DstType>
1474040Ssaidi@eecs.umich.eduBaseXBar::Layer<SrcType,DstType>::Layer(DstType& _port, BaseXBar& _xbar,
14810885Sandreas.hansson@arm.com                                       const std::string& _name) :
14910885Sandreas.hansson@arm.com    port(_port), xbar(_xbar), _name(_name), state(IDLE),
15010885Sandreas.hansson@arm.com    waitingForPeer(NULL), releaseEvent([this]{ releaseLayer(); }, name())
15111600Sandreas.hansson@arm.com{
15211600Sandreas.hansson@arm.com}
15310885Sandreas.hansson@arm.com
15410885Sandreas.hansson@arm.comtemplate <typename SrcType, typename DstType>
15510885Sandreas.hansson@arm.comvoid BaseXBar::Layer<SrcType,DstType>::occupyLayer(Tick until)
15611600Sandreas.hansson@arm.com{
15711600Sandreas.hansson@arm.com    // ensure the state is busy at this point, as the layer should
1585507Sstever@gmail.com    // transition from idle as soon as it has decided to forward the
1595507Sstever@gmail.com    // packet to prevent any follow-on calls to sendTiming seeing an
1606076Sgblack@eecs.umich.edu    // unoccupied layer
1615507Sstever@gmail.com    assert(state == BUSY);
1624626Sstever@eecs.umich.edu
16311284Sandreas.hansson@arm.com    // until should never be 0 as express snoops never occupy the layer
1644626Sstever@eecs.umich.edu    assert(until != 0);
1654626Sstever@eecs.umich.edu    xbar.schedule(releaseEvent, until);
16610325Sgeoffrey.blake@arm.com
16711284Sandreas.hansson@arm.com    // account for the occupied ticks
1687669Ssteve.reinhardt@amd.com    occupancy += until - curTick();
1697669Ssteve.reinhardt@amd.com
1704626Sstever@eecs.umich.edu    DPRINTF(BaseXBar, "The crossbar layer is now busy from tick %d to %d\n",
17111287Sandreas.hansson@arm.com            curTick(), until);
1724626Sstever@eecs.umich.edu}
1734040Ssaidi@eecs.umich.edu
17411284Sandreas.hansson@arm.comtemplate <typename SrcType, typename DstType>
1754040Ssaidi@eecs.umich.edubool
1764040Ssaidi@eecs.umich.eduBaseXBar::Layer<SrcType,DstType>::tryTiming(SrcType* src_port)
17711287Sandreas.hansson@arm.com{
1784870Sstever@eecs.umich.edu    // if we are in the retry state, we will not see anything but the
1795650Sgblack@eecs.umich.edu    // retrying port (or in the case of the snoop ports the snoop
1805650Sgblack@eecs.umich.edu    // response port that mirrors the actual slave port) as we leave
1816063Sgblack@eecs.umich.edu    // this state again in zero time if the peer does not immediately
1825650Sgblack@eecs.umich.edu    // call the layer when receiving the retry
1836063Sgblack@eecs.umich.edu
18411256Santhony.gutierrez@amd.com    // first we see if the layer is busy, next we check if the
18511256Santhony.gutierrez@amd.com    // destination port is already engaged in a transaction waiting
18611256Santhony.gutierrez@amd.com    // for a retry from the peer
18711256Santhony.gutierrez@amd.com    if (state == BUSY || waitingForPeer != NULL) {
18812347Snikos.nikoleris@arm.com        // the port should not be waiting already
18912347Snikos.nikoleris@arm.com        assert(std::find(waitingForLayer.begin(), waitingForLayer.end(),
19012347Snikos.nikoleris@arm.com                         src_port) == waitingForLayer.end());
19112347Snikos.nikoleris@arm.com
19212347Snikos.nikoleris@arm.com        // put the port at the end of the retry list waiting for the
19312347Snikos.nikoleris@arm.com        // layer to be freed up (and in the case of a busy peer, for
19412347Snikos.nikoleris@arm.com        // that transaction to go through, and then the layer to free
19512347Snikos.nikoleris@arm.com        // up)
19612347Snikos.nikoleris@arm.com        waitingForLayer.push_back(src_port);
19712347Snikos.nikoleris@arm.com        return false;
19812347Snikos.nikoleris@arm.com    }
19912347Snikos.nikoleris@arm.com
20012347Snikos.nikoleris@arm.com    state = BUSY;
20112347Snikos.nikoleris@arm.com
20212347Snikos.nikoleris@arm.com    return true;
20312347Snikos.nikoleris@arm.com}
20412347Snikos.nikoleris@arm.com
20512347Snikos.nikoleris@arm.comtemplate <typename SrcType, typename DstType>
2064870Sstever@eecs.umich.eduvoid
2074986Ssaidi@eecs.umich.eduBaseXBar::Layer<SrcType,DstType>::succeededTiming(Tick busy_time)
2084870Sstever@eecs.umich.edu{
2095314Sstever@gmail.com    // we should have gone from idle or retry to busy in the tryTiming
2108436SBrad.Beckmann@amd.com    // test
2118436SBrad.Beckmann@amd.com    assert(state == BUSY);
2128436SBrad.Beckmann@amd.com
2138436SBrad.Beckmann@amd.com    // occupy the layer accordingly
2145314Sstever@gmail.com    occupyLayer(busy_time);
2158184Ssomayeh@cs.wisc.edu}
2168184Ssomayeh@cs.wisc.edu
21711284Sandreas.hansson@arm.comtemplate <typename SrcType, typename DstType>
2188716Snilay@cs.wisc.eduvoid
21911600Sandreas.hansson@arm.comBaseXBar::Layer<SrcType,DstType>::failedTiming(SrcType* src_port,
22010886Sandreas.hansson@arm.com                                              Tick busy_time)
22110886Sandreas.hansson@arm.com{
22211287Sandreas.hansson@arm.com    // ensure no one got in between and tried to send something to
22310886Sandreas.hansson@arm.com    // this port
2244022Sstever@eecs.umich.edu    assert(waitingForPeer == NULL);
2252592SN/A
2263607Srdreslin@umich.edu    // if the source port is the current retrying one or not, we have
22710028SGiacomo.Gabrielli@arm.com    // failed in forwarding and should track that we are now waiting
22810570Sandreas.hansson@arm.com    // for the peer to send a retry
2292641Sstever@eecs.umich.edu    waitingForPeer = src_port;
2304626Sstever@eecs.umich.edu
2314626Sstever@eecs.umich.edu    // we should have gone from idle or retry to busy in the tryTiming
2324626Sstever@eecs.umich.edu    // test
2334626Sstever@eecs.umich.edu    assert(state == BUSY);
2343260Ssaidi@eecs.umich.edu
23510028SGiacomo.Gabrielli@arm.com    // occupy the bus accordingly
23610028SGiacomo.Gabrielli@arm.com    occupyLayer(busy_time);
2374626Sstever@eecs.umich.edu}
2384626Sstever@eecs.umich.edu
2394626Sstever@eecs.umich.edutemplate <typename SrcType, typename DstType>
2403260Ssaidi@eecs.umich.eduvoid
2415314Sstever@gmail.comBaseXBar::Layer<SrcType,DstType>::releaseLayer()
2425314Sstever@gmail.com{
24310570Sandreas.hansson@arm.com    // releasing the bus means we should now be idle
24410376Sandreas.hansson@arm.com    assert(state == BUSY);
2455314Sstever@gmail.com    assert(!releaseEvent.scheduled());
2465314Sstever@gmail.com
2475314Sstever@gmail.com    // update the state
24810570Sandreas.hansson@arm.com    state = IDLE;
24910570Sandreas.hansson@arm.com
25010570Sandreas.hansson@arm.com    // bus layer is now idle, so if someone is waiting we can retry
2515314Sstever@gmail.com    if (!waitingForLayer.empty()) {
2525314Sstever@gmail.com        // there is no point in sending a retry if someone is still
2535314Sstever@gmail.com        // waiting for the peer
2544626Sstever@eecs.umich.edu        if (waitingForPeer == NULL)
2554626Sstever@eecs.umich.edu            retryWaiting();
2564626Sstever@eecs.umich.edu    } else if (waitingForPeer == NULL && drainState() == DrainState::Draining) {
2573260Ssaidi@eecs.umich.edu        DPRINTF(Drain, "Crossbar done draining, signaling drain manager\n");
2584626Sstever@eecs.umich.edu        //If we weren't able to drain before, do it now.
2594626Sstever@eecs.umich.edu        signalDrainDone();
26010570Sandreas.hansson@arm.com    }
26110723Sandreas.hansson@arm.com}
26210723Sandreas.hansson@arm.com
26310570Sandreas.hansson@arm.comtemplate <typename SrcType, typename DstType>
26410570Sandreas.hansson@arm.comvoid
2654626Sstever@eecs.umich.eduBaseXBar::Layer<SrcType,DstType>::retryWaiting()
2663260Ssaidi@eecs.umich.edu{
2678668Sgeoffrey.blake@arm.com    // this should never be called with no one waiting
2688668Sgeoffrey.blake@arm.com    assert(!waitingForLayer.empty());
2698668Sgeoffrey.blake@arm.com
2708668Sgeoffrey.blake@arm.com    // we always go to retrying from idle
2718668Sgeoffrey.blake@arm.com    assert(state == IDLE);
2728668Sgeoffrey.blake@arm.com
2738668Sgeoffrey.blake@arm.com    // update the state
27410723Sandreas.hansson@arm.com    state = RETRY;
27510723Sandreas.hansson@arm.com
2768668Sgeoffrey.blake@arm.com    // set the retrying port to the front of the retry list and pop it
2778668Sgeoffrey.blake@arm.com    // off the list
2788668Sgeoffrey.blake@arm.com    SrcType* retryingPort = waitingForLayer.front();
2798668Sgeoffrey.blake@arm.com    waitingForLayer.pop_front();
28010723Sandreas.hansson@arm.com
28110723Sandreas.hansson@arm.com    // tell the port to retry, which in some cases ends up calling the
2828668Sgeoffrey.blake@arm.com    // layer again
2838668Sgeoffrey.blake@arm.com    sendRetry(retryingPort);
2848668Sgeoffrey.blake@arm.com
2858668Sgeoffrey.blake@arm.com    // If the layer is still in the retry state, sendTiming wasn't
28610723Sandreas.hansson@arm.com    // called in zero time (e.g. the cache does this when a writeback
28710723Sandreas.hansson@arm.com    // is squashed)
28810723Sandreas.hansson@arm.com    if (state == RETRY) {
2898668Sgeoffrey.blake@arm.com        // update the state to busy and reset the retrying port, we
2908668Sgeoffrey.blake@arm.com        // have done our bit and sent the retry
2918668Sgeoffrey.blake@arm.com        state = BUSY;
29210723Sandreas.hansson@arm.com
29310723Sandreas.hansson@arm.com        // occupy the crossbar layer until the next clock edge
29410723Sandreas.hansson@arm.com        occupyLayer(xbar.clockEdge());
29510723Sandreas.hansson@arm.com    }
29610723Sandreas.hansson@arm.com}
29710723Sandreas.hansson@arm.com
2988668Sgeoffrey.blake@arm.comtemplate <typename SrcType, typename DstType>
29910723Sandreas.hansson@arm.comvoid
30010723Sandreas.hansson@arm.comBaseXBar::Layer<SrcType,DstType>::recvRetry()
30110723Sandreas.hansson@arm.com{
3028668Sgeoffrey.blake@arm.com    // we should never get a retry without having failed to forward
3038668Sgeoffrey.blake@arm.com    // something to this port
3048668Sgeoffrey.blake@arm.com    assert(waitingForPeer != NULL);
3058668Sgeoffrey.blake@arm.com
30610570Sandreas.hansson@arm.com    // add the port where the failed packet originated to the front of
3078668Sgeoffrey.blake@arm.com    // the waiting ports for the layer, this allows us to call retry
3088668Sgeoffrey.blake@arm.com    // on the port immediately if the crossbar layer is idle
30910723Sandreas.hansson@arm.com    waitingForLayer.push_front(waitingForPeer);
31010723Sandreas.hansson@arm.com
31110723Sandreas.hansson@arm.com    // we are no longer waiting for the peer
31210723Sandreas.hansson@arm.com    waitingForPeer = NULL;
31310723Sandreas.hansson@arm.com
31410723Sandreas.hansson@arm.com    // if the layer is idle, retry this port straight away, if we
31510723Sandreas.hansson@arm.com    // are busy, then simply let the port wait for its turn
31610723Sandreas.hansson@arm.com    if (state == IDLE) {
31710723Sandreas.hansson@arm.com        retryWaiting();
31810723Sandreas.hansson@arm.com    } else {
31910723Sandreas.hansson@arm.com        assert(state == BUSY);
32010723Sandreas.hansson@arm.com    }
32110723Sandreas.hansson@arm.com}
32210723Sandreas.hansson@arm.com
32310723Sandreas.hansson@arm.comPortID
32410723Sandreas.hansson@arm.comBaseXBar::findPort(Addr addr)
32510723Sandreas.hansson@arm.com{
32610723Sandreas.hansson@arm.com    // we should never see any address lookups before we've got the
32710723Sandreas.hansson@arm.com    // ranges of all connected slave modules
32810723Sandreas.hansson@arm.com    assert(gotAllAddrRanges);
32910723Sandreas.hansson@arm.com
33010723Sandreas.hansson@arm.com    // Check the cache
33110723Sandreas.hansson@arm.com    PortID dest_id = checkPortCache(addr);
3323260Ssaidi@eecs.umich.edu    if (dest_id != InvalidPortID)
3334626Sstever@eecs.umich.edu        return dest_id;
3344626Sstever@eecs.umich.edu
33510570Sandreas.hansson@arm.com    // Check the address map interval tree
3365735Snate@binkert.org    auto i = portMap.contains(addr);
3375735Snate@binkert.org    if (i != portMap.end()) {
3385735Snate@binkert.org        dest_id = i->second;
33910570Sandreas.hansson@arm.com        updatePortCache(dest_id, i->first);
3405735Snate@binkert.org        return dest_id;
3413260Ssaidi@eecs.umich.edu    }
3425314Sstever@gmail.com
3434626Sstever@eecs.umich.edu    // Check if this matches the default range
3445314Sstever@gmail.com    if (useDefaultRange) {
3455314Sstever@gmail.com        if (defaultRange.contains(addr)) {
3465314Sstever@gmail.com            DPRINTF(AddrRanges, "  found addr %#llx on default\n",
3475314Sstever@gmail.com                    addr);
3482641Sstever@eecs.umich.edu            return defaultPortID;
3493260Ssaidi@eecs.umich.edu        }
3505314Sstever@gmail.com    } else if (defaultPortID != InvalidPortID) {
3519542Sandreas.hansson@arm.com        DPRINTF(AddrRanges, "Unable to find destination for addr %#llx, "
3529542Sandreas.hansson@arm.com                "will use default port\n", addr);
3539542Sandreas.hansson@arm.com        return defaultPortID;
3549542Sandreas.hansson@arm.com    }
3559542Sandreas.hansson@arm.com
3569542Sandreas.hansson@arm.com    // we should use the range for the default port and it did not
3579542Sandreas.hansson@arm.com    // match, or the default port is not set
3589542Sandreas.hansson@arm.com    fatal("Unable to find destination for addr %#llx on %s\n", addr,
3599542Sandreas.hansson@arm.com          name());
3609542Sandreas.hansson@arm.com}
3619542Sandreas.hansson@arm.com
3629542Sandreas.hansson@arm.com/** Function called by the port when the crossbar is receiving a range change.*/
3639542Sandreas.hansson@arm.comvoid
3649542Sandreas.hansson@arm.comBaseXBar::recvRangeChange(PortID master_port_id)
3659542Sandreas.hansson@arm.com{
3669542Sandreas.hansson@arm.com    DPRINTF(AddrRanges, "Received range change from slave port %s\n",
3679542Sandreas.hansson@arm.com            masterPorts[master_port_id]->getSlavePort().name());
36812652Sandreas.sandberg@arm.com
36912652Sandreas.sandberg@arm.com    // remember that we got a range from this master port and thus the
37012652Sandreas.sandberg@arm.com    // connected slave module
37112652Sandreas.sandberg@arm.com    gotAddrRanges[master_port_id] = true;
37212652Sandreas.sandberg@arm.com
37312652Sandreas.sandberg@arm.com    // update the global flag
37412652Sandreas.sandberg@arm.com    if (!gotAllAddrRanges) {
37512652Sandreas.sandberg@arm.com        // take a logical AND of all the ports and see if we got
37612652Sandreas.sandberg@arm.com        // ranges from everyone
37712652Sandreas.sandberg@arm.com        gotAllAddrRanges = true;
37812652Sandreas.sandberg@arm.com        std::vector<bool>::const_iterator r = gotAddrRanges.begin();
37912652Sandreas.sandberg@arm.com        while (gotAllAddrRanges &&  r != gotAddrRanges.end()) {
38012652Sandreas.sandberg@arm.com            gotAllAddrRanges &= *r++;
38112652Sandreas.sandberg@arm.com        }
38212652Sandreas.sandberg@arm.com        if (gotAllAddrRanges)
38312652Sandreas.sandberg@arm.com            DPRINTF(AddrRanges, "Got address ranges from all slaves\n");
38412652Sandreas.sandberg@arm.com    }
38512652Sandreas.sandberg@arm.com
38612652Sandreas.sandberg@arm.com    // note that we could get the range from the default port at any
38712652Sandreas.sandberg@arm.com    // point in time, and we cannot assume that the default range is
38812652Sandreas.sandberg@arm.com    // set before the other ones are, so we do additional checks once
38912652Sandreas.sandberg@arm.com    // all ranges are provided
39012652Sandreas.sandberg@arm.com    if (master_port_id == defaultPortID) {
39112652Sandreas.sandberg@arm.com        // only update if we are indeed checking ranges for the
39212652Sandreas.sandberg@arm.com        // default port since the port might not have a valid range
39312652Sandreas.sandberg@arm.com        // otherwise
39412652Sandreas.sandberg@arm.com        if (useDefaultRange) {
39512652Sandreas.sandberg@arm.com            AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
39612652Sandreas.sandberg@arm.com
39712652Sandreas.sandberg@arm.com            if (ranges.size() != 1)
39812652Sandreas.sandberg@arm.com                fatal("Crossbar %s may only have a single default range",
39912652Sandreas.sandberg@arm.com                      name());
40012652Sandreas.sandberg@arm.com
40112652Sandreas.sandberg@arm.com            defaultRange = ranges.front();
40212652Sandreas.sandberg@arm.com        }
40312652Sandreas.sandberg@arm.com    } else {
40412652Sandreas.sandberg@arm.com        // the ports are allowed to update their address ranges
40512652Sandreas.sandberg@arm.com        // dynamically, so remove any existing entries
40612652Sandreas.sandberg@arm.com        if (gotAddrRanges[master_port_id]) {
4079542Sandreas.hansson@arm.com            for (auto p = portMap.begin(); p != portMap.end(); ) {
4085735Snate@binkert.org                if (p->second == master_port_id)
4093260Ssaidi@eecs.umich.edu                    // erasing invalidates the iterator, so advance it
41012346Snikos.nikoleris@arm.com                    // before the deletion takes place
41111744Snikos.nikoleris@arm.com                    portMap.erase(p++);
41211744Snikos.nikoleris@arm.com                else
41311744Snikos.nikoleris@arm.com                    p++;
41411744Snikos.nikoleris@arm.com            }
41512346Snikos.nikoleris@arm.com        }
41612346Snikos.nikoleris@arm.com
41712346Snikos.nikoleris@arm.com        AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
4183260Ssaidi@eecs.umich.edu
4193260Ssaidi@eecs.umich.edu        for (const auto& r: ranges) {
4209663Suri.wiener@arm.com            DPRINTF(AddrRanges, "Adding range %s for id %d\n",
4219663Suri.wiener@arm.com                    r.to_string(), master_port_id);
4229663Suri.wiener@arm.com            if (portMap.insert(r, master_port_id) == portMap.end()) {
4239663Suri.wiener@arm.com                PortID conflict_id = portMap.intersects(r)->second;
4249663Suri.wiener@arm.com                fatal("%s has two ports responding within range "
4259663Suri.wiener@arm.com                      "%s:\n\t%s\n\t%s\n",
4269663Suri.wiener@arm.com                      name(),
4275735Snate@binkert.org                      r.to_string(),
4285735Snate@binkert.org                      masterPorts[master_port_id]->getSlavePort().name(),
4295314Sstever@gmail.com                      masterPorts[conflict_id]->getSlavePort().name());
4305314Sstever@gmail.com            }
4315314Sstever@gmail.com        }
4325314Sstever@gmail.com    }
4335314Sstever@gmail.com
4345314Sstever@gmail.com    // if we have received ranges from all our neighbouring slave
4355314Sstever@gmail.com    // modules, go ahead and tell our connected master modules in
4365314Sstever@gmail.com    // turn, this effectively assumes a tree structure of the system
4375314Sstever@gmail.com    if (gotAllAddrRanges) {
4385314Sstever@gmail.com        DPRINTF(AddrRanges, "Aggregating address ranges\n");
4395314Sstever@gmail.com        xbarRanges.clear();
4405314Sstever@gmail.com
4415735Snate@binkert.org        // start out with the default range
4425314Sstever@gmail.com        if (useDefaultRange) {
4435314Sstever@gmail.com            if (!gotAddrRanges[defaultPortID])
4445314Sstever@gmail.com                fatal("Crossbar %s uses default range, but none provided",
4455314Sstever@gmail.com                      name());
4465314Sstever@gmail.com
4475735Snate@binkert.org            xbarRanges.push_back(defaultRange);
4485314Sstever@gmail.com            DPRINTF(AddrRanges, "-- Adding default %s\n",
4495314Sstever@gmail.com                    defaultRange.to_string());
4505735Snate@binkert.org        }
4515314Sstever@gmail.com
4525314Sstever@gmail.com        // merge all interleaved ranges and add any range that is not
4535314Sstever@gmail.com        // a subset of the default range
4545314Sstever@gmail.com        std::vector<AddrRange> intlv_ranges;
4555314Sstever@gmail.com        for (const auto& r: portMap) {
4565314Sstever@gmail.com            // if the range is interleaved then save it for now
4575314Sstever@gmail.com            if (r.first.interleaved()) {
4585314Sstever@gmail.com                // if we already got interleaved ranges that are not
4595314Sstever@gmail.com                // part of the same range, then first do a merge
4605314Sstever@gmail.com                // before we add the new one
4615314Sstever@gmail.com                if (!intlv_ranges.empty() &&
4625314Sstever@gmail.com                    !intlv_ranges.back().mergesWith(r.first)) {
4635314Sstever@gmail.com                    DPRINTF(AddrRanges, "-- Merging range from %d ranges\n",
4645314Sstever@gmail.com                            intlv_ranges.size());
4655314Sstever@gmail.com                    AddrRange merged_range(intlv_ranges);
4665314Sstever@gmail.com                    // next decide if we keep the merged range or not
4675314Sstever@gmail.com                    if (!(useDefaultRange &&
4685314Sstever@gmail.com                          merged_range.isSubset(defaultRange))) {
4695314Sstever@gmail.com                        xbarRanges.push_back(merged_range);
4705314Sstever@gmail.com                        DPRINTF(AddrRanges, "-- Adding merged range %s\n",
4715314Sstever@gmail.com                                merged_range.to_string());
4725314Sstever@gmail.com                    }
4735314Sstever@gmail.com                    intlv_ranges.clear();
4745314Sstever@gmail.com                }
4755314Sstever@gmail.com                intlv_ranges.push_back(r.first);
4765314Sstever@gmail.com            } else {
4775314Sstever@gmail.com                // keep the current range if not a subset of the default
4785314Sstever@gmail.com                if (!(useDefaultRange &&
4795314Sstever@gmail.com                      r.first.isSubset(defaultRange))) {
4805314Sstever@gmail.com                    xbarRanges.push_back(r.first);
4815314Sstever@gmail.com                    DPRINTF(AddrRanges, "-- Adding range %s\n",
4825314Sstever@gmail.com                            r.first.to_string());
4835314Sstever@gmail.com                }
4845314Sstever@gmail.com            }
4855314Sstever@gmail.com        }
486
487        // if there is still interleaved ranges waiting to be merged,
488        // go ahead and do it
489        if (!intlv_ranges.empty()) {
490            DPRINTF(AddrRanges, "-- Merging range from %d ranges\n",
491                    intlv_ranges.size());
492            AddrRange merged_range(intlv_ranges);
493            if (!(useDefaultRange && merged_range.isSubset(defaultRange))) {
494                xbarRanges.push_back(merged_range);
495                DPRINTF(AddrRanges, "-- Adding merged range %s\n",
496                        merged_range.to_string());
497            }
498        }
499
500        // also check that no range partially intersects with the
501        // default range, this has to be done after all ranges are set
502        // as there are no guarantees for when the default range is
503        // update with respect to the other ones
504        if (useDefaultRange) {
505            for (const auto& r: xbarRanges) {
506                // see if the new range is partially
507                // overlapping the default range
508                if (r.intersects(defaultRange) &&
509                    !r.isSubset(defaultRange))
510                    fatal("Range %s intersects the "                    \
511                          "default range of %s but is not a "           \
512                          "subset\n", r.to_string(), name());
513            }
514        }
515
516        // tell all our neighbouring master ports that our address
517        // ranges have changed
518        for (const auto& s: slavePorts)
519            s->sendRangeChange();
520    }
521
522    clearPortCache();
523}
524
525AddrRangeList
526BaseXBar::getAddrRanges() const
527{
528    // we should never be asked without first having sent a range
529    // change, and the latter is only done once we have all the ranges
530    // of the connected devices
531    assert(gotAllAddrRanges);
532
533    // at the moment, this never happens, as there are no cycles in
534    // the range queries and no devices on the master side of a crossbar
535    // (CPU, cache, bridge etc) actually care about the ranges of the
536    // ports they are connected to
537
538    DPRINTF(AddrRanges, "Received address range request\n");
539
540    return xbarRanges;
541}
542
543void
544BaseXBar::regStats()
545{
546    ClockedObject::regStats();
547
548    using namespace Stats;
549
550    transDist
551        .init(MemCmd::NUM_MEM_CMDS)
552        .name(name() + ".trans_dist")
553        .desc("Transaction distribution")
554        .flags(nozero);
555
556    // get the string representation of the commands
557    for (int i = 0; i < MemCmd::NUM_MEM_CMDS; i++) {
558        MemCmd cmd(i);
559        const std::string &cstr = cmd.toString();
560        transDist.subname(i, cstr);
561    }
562
563    pktCount
564        .init(slavePorts.size(), masterPorts.size())
565        .name(name() + ".pkt_count")
566        .desc("Packet count per connected master and slave (bytes)")
567        .flags(total | nozero | nonan);
568
569    pktSize
570        .init(slavePorts.size(), masterPorts.size())
571        .name(name() + ".pkt_size")
572        .desc("Cumulative packet size per connected master and slave (bytes)")
573        .flags(total | nozero | nonan);
574
575    // both the packet count and total size are two-dimensional
576    // vectors, indexed by slave port id and master port id, thus the
577    // neighbouring master and slave, they do not differentiate what
578    // came from the master and was forwarded to the slave (requests
579    // and snoop responses) and what came from the slave and was
580    // forwarded to the master (responses and snoop requests)
581    for (int i = 0; i < slavePorts.size(); i++) {
582        pktCount.subname(i, slavePorts[i]->getMasterPort().name());
583        pktSize.subname(i, slavePorts[i]->getMasterPort().name());
584        for (int j = 0; j < masterPorts.size(); j++) {
585            pktCount.ysubname(j, masterPorts[j]->getSlavePort().name());
586            pktSize.ysubname(j, masterPorts[j]->getSlavePort().name());
587        }
588    }
589}
590
591template <typename SrcType, typename DstType>
592DrainState
593BaseXBar::Layer<SrcType,DstType>::drain()
594{
595    //We should check that we're not "doing" anything, and that noone is
596    //waiting. We might be idle but have someone waiting if the device we
597    //contacted for a retry didn't actually retry.
598    if (state != IDLE) {
599        DPRINTF(Drain, "Crossbar not drained\n");
600        return DrainState::Draining;
601    } else {
602        return DrainState::Drained;
603    }
604}
605
606template <typename SrcType, typename DstType>
607void
608BaseXBar::Layer<SrcType,DstType>::regStats()
609{
610    using namespace Stats;
611
612    occupancy
613        .name(name() + ".occupancy")
614        .desc("Layer occupancy (ticks)")
615        .flags(nozero);
616
617    utilization
618        .name(name() + ".utilization")
619        .desc("Layer utilization (%)")
620        .precision(1)
621        .flags(nozero);
622
623    utilization = 100 * occupancy / simTicks;
624}
625
626/**
627 * Crossbar layer template instantiations. Could be removed with _impl.hh
628 * file, but since there are only two given options (MasterPort and
629 * SlavePort) it seems a bit excessive at this point.
630 */
631template class BaseXBar::Layer<SlavePort,MasterPort>;
632template class BaseXBar::Layer<MasterPort,SlavePort>;
633