xbar.cc revision 10414
12391SN/A/* 213998Stiago.muck@arm.com * Copyright (c) 2011-2014 ARM Limited 37733SN/A * All rights reserved 47733SN/A * 57733SN/A * The license below extends only to copyright in the software and shall 67733SN/A * not be construed as granting a license to any other intellectual 77733SN/A * property including but not limited to intellectual property relating 87733SN/A * to a hardware implementation of the functionality of the software 97733SN/A * licensed hereunder. You may use the software subject to the license 107733SN/A * terms below provided that you ensure that this notice is replicated 117733SN/A * unmodified and in its entirety in all distributions of the software, 127733SN/A * modified or unmodified, in source code or in binary form. 137733SN/A * 142391SN/A * Copyright (c) 2006 The Regents of The University of Michigan 152391SN/A * All rights reserved. 162391SN/A * 172391SN/A * Redistribution and use in source and binary forms, with or without 182391SN/A * modification, are permitted provided that the following conditions are 192391SN/A * met: redistributions of source code must retain the above copyright 202391SN/A * notice, this list of conditions and the following disclaimer; 212391SN/A * redistributions in binary form must reproduce the above copyright 222391SN/A * notice, this list of conditions and the following disclaimer in the 232391SN/A * documentation and/or other materials provided with the distribution; 242391SN/A * neither the name of the copyright holders nor the names of its 252391SN/A * contributors may be used to endorse or promote products derived from 262391SN/A * this software without specific prior written permission. 272391SN/A * 282391SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292391SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302391SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312391SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322391SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332391SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342391SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352391SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362391SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372391SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382391SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392665SN/A * 402665SN/A * Authors: Ali Saidi 412914SN/A * Andreas Hansson 428931Sandreas.hansson@arm.com * William Wang 432391SN/A */ 442391SN/A 4511793Sbrandon.potter@amd.com/** 4611793Sbrandon.potter@amd.com * @file 4710466Sandreas.hansson@arm.com * Definition of a crossbar object. 4810466Sandreas.hansson@arm.com */ 4912218Snikos.nikoleris@arm.com 5010102Sali.saidi@arm.com#include "base/misc.hh" 5110102Sali.saidi@arm.com#include "base/trace.hh" 528232SN/A#include "debug/AddrRanges.hh" 538232SN/A#include "debug/Drain.hh" 543879SN/A#include "debug/XBar.hh" 559053Sdam.sunwoo@arm.com#include "mem/xbar.hh" 562394SN/A 572391SN/ABaseXBar::BaseXBar(const BaseXBarParams *p) 582391SN/A : MemObject(p), 598931Sandreas.hansson@arm.com headerCycles(p->header_cycles), width(p->width), 6013892Sgabeblack@google.com gotAddrRanges(p->port_default_connection_count + 6113853Sgabeblack@google.com p->port_master_connection_count, false), 6213853Sgabeblack@google.com gotAllAddrRanges(false), defaultPortID(InvalidPortID), 6313853Sgabeblack@google.com useDefaultRange(p->use_default_range) 649053Sdam.sunwoo@arm.com{} 6511614Sdavid.j.hashe@gmail.com 662391SN/ABaseXBar::~BaseXBar() 6710466Sandreas.hansson@arm.com{ 6810466Sandreas.hansson@arm.com for (auto m: masterPorts) 6910466Sandreas.hansson@arm.com delete m; 7010466Sandreas.hansson@arm.com 7110466Sandreas.hansson@arm.com for (auto s: slavePorts) 7210466Sandreas.hansson@arm.com delete s; 7310466Sandreas.hansson@arm.com} 7410466Sandreas.hansson@arm.com 752391SN/Avoid 762391SN/ABaseXBar::init() 772391SN/A{ 789293Sandreas.hansson@arm.com} 799293Sandreas.hansson@arm.com 802391SN/ABaseMasterPort & 8113853Sgabeblack@google.comBaseXBar::getMasterPort(const std::string &if_name, PortID idx) 8213853Sgabeblack@google.com{ 8313853Sgabeblack@google.com if (if_name == "master" && idx < masterPorts.size()) { 8413853Sgabeblack@google.com // the master port index translates directly to the vector position 8513853Sgabeblack@google.com return *masterPorts[idx]; 8613853Sgabeblack@google.com } else if (if_name == "default") { 8713853Sgabeblack@google.com return *masterPorts[defaultPortID]; 889293Sandreas.hansson@arm.com } else { 892391SN/A return MemObject::getMasterPort(if_name, idx); 902391SN/A } 918719SN/A} 928931Sandreas.hansson@arm.com 938719SN/ABaseSlavePort & 9413892Sgabeblack@google.comBaseXBar::getSlavePort(const std::string &if_name, PortID idx) 9511522Sstephan.diestelhorst@arm.com{ 968719SN/A if (if_name == "slave" && idx < slavePorts.size()) { 978719SN/A // the slave port index translates directly to the vector position 989053Sdam.sunwoo@arm.com return *slavePorts[idx]; 999053Sdam.sunwoo@arm.com } else { 1008719SN/A return MemObject::getSlavePort(if_name, idx); 1019053Sdam.sunwoo@arm.com } 1028719SN/A} 1038719SN/A 1049053Sdam.sunwoo@arm.comvoid 1058719SN/ABaseXBar::calcPacketTiming(PacketPtr pkt) 1069053Sdam.sunwoo@arm.com{ 1079053Sdam.sunwoo@arm.com // the crossbar will be called at a time that is not necessarily 1089053Sdam.sunwoo@arm.com // coinciding with its own clock, so start by determining how long 1098719SN/A // until the next clock edge (could be zero) 1109053Sdam.sunwoo@arm.com Tick offset = clockEdge() - curTick(); 1118719SN/A 1128719SN/A // determine how many cycles are needed to send the data 1139053Sdam.sunwoo@arm.com unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0; 1148719SN/A 1159053Sdam.sunwoo@arm.com // before setting the bus delay fields of the packet, ensure that 1169053Sdam.sunwoo@arm.com // the delay from any previous crossbar has been accounted for 1179053Sdam.sunwoo@arm.com if (pkt->firstWordDelay != 0 || pkt->lastWordDelay != 0) 1188719SN/A panic("Packet %s already has delay (%d, %d) that should be " 1199053Sdam.sunwoo@arm.com "accounted for.\n", pkt->cmdString(), pkt->firstWordDelay, 1208719SN/A pkt->lastWordDelay); 1218719SN/A 1229053Sdam.sunwoo@arm.com // The first word will be delivered on the cycle after the header. 1238719SN/A pkt->firstWordDelay = (headerCycles + 1) * clockPeriod() + offset; 1249053Sdam.sunwoo@arm.com 1259053Sdam.sunwoo@arm.com // Note that currently lastWordDelay can be smaller than 1269053Sdam.sunwoo@arm.com // firstWordDelay if the packet has no data 1278719SN/A pkt->lastWordDelay = (headerCycles + dataCycles) * clockPeriod() + 1289053Sdam.sunwoo@arm.com offset; 1298719SN/A} 1308719SN/A 1319053Sdam.sunwoo@arm.comtemplate <typename SrcType, typename DstType> 1328719SN/ABaseXBar::Layer<SrcType,DstType>::Layer(DstType& _port, BaseXBar& _xbar, 1339053Sdam.sunwoo@arm.com const std::string& _name) : 1349053Sdam.sunwoo@arm.com port(_port), xbar(_xbar), _name(_name), state(IDLE), drainManager(NULL), 1359053Sdam.sunwoo@arm.com waitingForPeer(NULL), releaseEvent(this) 1368719SN/A{ 1379053Sdam.sunwoo@arm.com} 1388719SN/A 1398719SN/Atemplate <typename SrcType, typename DstType> 1409053Sdam.sunwoo@arm.comvoid BaseXBar::Layer<SrcType,DstType>::occupyLayer(Tick until) 1418719SN/A{ 1429053Sdam.sunwoo@arm.com // ensure the state is busy at this point, as the layer should 1439053Sdam.sunwoo@arm.com // transition from idle as soon as it has decided to forward the 1449053Sdam.sunwoo@arm.com // packet to prevent any follow-on calls to sendTiming seeing an 1458719SN/A // unoccupied layer 1469053Sdam.sunwoo@arm.com assert(state == BUSY); 1478719SN/A 1488719SN/A // until should never be 0 as express snoops never occupy the layer 1499053Sdam.sunwoo@arm.com assert(until != 0); 1508719SN/A xbar.schedule(releaseEvent, until); 1519053Sdam.sunwoo@arm.com 1529053Sdam.sunwoo@arm.com // account for the occupied ticks 1539053Sdam.sunwoo@arm.com occupancy += until - curTick(); 1548719SN/A 1558719SN/A DPRINTF(BaseXBar, "The crossbar layer is now busy from tick %d to %d\n", 1568719SN/A curTick(), until); 1578719SN/A} 1588719SN/A 1599053Sdam.sunwoo@arm.comtemplate <typename SrcType, typename DstType> 1608719SN/Abool 1619053Sdam.sunwoo@arm.comBaseXBar::Layer<SrcType,DstType>::tryTiming(SrcType* src_port) 1629053Sdam.sunwoo@arm.com{ 1639053Sdam.sunwoo@arm.com // if we are in the retry state, we will not see anything but the 1649053Sdam.sunwoo@arm.com // retrying port (or in the case of the snoop ports the snoop 1658719SN/A // response port that mirrors the actual slave port) as we leave 1668719SN/A // this state again in zero time if the peer does not immediately 1678719SN/A // call the layer when receiving the retry 1688719SN/A 1698719SN/A // first we see if the layer is busy, next we check if the 1709053Sdam.sunwoo@arm.com // destination port is already engaged in a transaction waiting 1718719SN/A // for a retry from the peer 1729053Sdam.sunwoo@arm.com if (state == BUSY || waitingForPeer != NULL) { 1739053Sdam.sunwoo@arm.com // the port should not be waiting already 1749053Sdam.sunwoo@arm.com assert(std::find(waitingForLayer.begin(), waitingForLayer.end(), 1758719SN/A src_port) == waitingForLayer.end()); 1768719SN/A 1778719SN/A // put the port at the end of the retry list waiting for the 1788719SN/A // layer to be freed up (and in the case of a busy peer, for 1798719SN/A // that transaction to go through, and then the layer to free 1809053Sdam.sunwoo@arm.com // up) 1818719SN/A waitingForLayer.push_back(src_port); 1829053Sdam.sunwoo@arm.com return false; 1839053Sdam.sunwoo@arm.com } 1849053Sdam.sunwoo@arm.com 1858719SN/A state = BUSY; 1868719SN/A 1878719SN/A return true; 1888719SN/A} 1898719SN/A 1909053Sdam.sunwoo@arm.comtemplate <typename SrcType, typename DstType> 1918719SN/Avoid 1929053Sdam.sunwoo@arm.comBaseXBar::Layer<SrcType,DstType>::succeededTiming(Tick busy_time) 1939053Sdam.sunwoo@arm.com{ 1949053Sdam.sunwoo@arm.com // we should have gone from idle or retry to busy in the tryTiming 1958719SN/A // test 1968719SN/A assert(state == BUSY); 1978719SN/A 1988719SN/A // occupy the layer accordingly 1998719SN/A occupyLayer(busy_time); 2008719SN/A} 2019235Sandreas.hansson@arm.com 2029098Sandreas.hansson@arm.comtemplate <typename SrcType, typename DstType> 2032408SN/Avoid 2048931Sandreas.hansson@arm.comBaseXBar::Layer<SrcType,DstType>::failedTiming(SrcType* src_port, 2052408SN/A Tick busy_time) 2062408SN/A{ 2073170SN/A // ensure no one got in between and tried to send something to 2086076SN/A // this port 2093170SN/A assert(waitingForPeer == NULL); 2108931Sandreas.hansson@arm.com 2113170SN/A // if the source port is the current retrying one or not, we have 21212749Sgiacomo.travaglini@arm.com // failed in forwarding and should track that we are now waiting 2133170SN/A // for the peer to send a retry 2143170SN/A waitingForPeer = src_port; 2153170SN/A 2163170SN/A // we should have gone from idle or retry to busy in the tryTiming 2173170SN/A // test 2183170SN/A assert(state == BUSY); 2193170SN/A 2203170SN/A // occupy the bus accordingly 2213170SN/A occupyLayer(busy_time); 2225714SN/A} 2235714SN/A 2243170SN/Atemplate <typename SrcType, typename DstType> 2253170SN/Avoid 2263170SN/ABaseXBar::Layer<SrcType,DstType>::releaseLayer() 2273170SN/A{ 2283170SN/A // releasing the bus means we should now be idle 2293170SN/A assert(state == BUSY); 2305714SN/A assert(!releaseEvent.scheduled()); 2315714SN/A 2323170SN/A // update the state 2333170SN/A state = IDLE; 2343170SN/A 2353170SN/A // bus layer is now idle, so if someone is waiting we can retry 2363170SN/A if (!waitingForLayer.empty()) { 2373170SN/A // there is no point in sending a retry if someone is still 2383170SN/A // waiting for the peer 2393170SN/A if (waitingForPeer == NULL) 2403170SN/A retryWaiting(); 2418931Sandreas.hansson@arm.com } else if (waitingForPeer == NULL && drainManager) { 2423170SN/A DPRINTF(Drain, "Crossbar done draining, signaling drain manager\n"); 24312749Sgiacomo.travaglini@arm.com //If we weren't able to drain before, do it now. 2443170SN/A drainManager->signalDrainDone(); 2456102SN/A // Clear the drain event once we're done with it. 2463170SN/A drainManager = NULL; 2473170SN/A } 2483170SN/A} 2493170SN/A 2509080Smatt.evans@arm.comtemplate <typename SrcType, typename DstType> 2513170SN/Avoid 2529080Smatt.evans@arm.comBaseXBar::Layer<SrcType,DstType>::retryWaiting() 2539080Smatt.evans@arm.com{ 2549080Smatt.evans@arm.com // this should never be called with no one waiting 2559080Smatt.evans@arm.com assert(!waitingForLayer.empty()); 2569080Smatt.evans@arm.com 2573170SN/A // we always go to retrying from idle 2583170SN/A assert(state == IDLE); 2599080Smatt.evans@arm.com 2609080Smatt.evans@arm.com // update the state 2619080Smatt.evans@arm.com state = RETRY; 2629080Smatt.evans@arm.com 2639080Smatt.evans@arm.com // set the retrying port to the front of the retry list and pop it 2645714SN/A // off the list 2655714SN/A SrcType* retryingPort = waitingForLayer.front(); 2669080Smatt.evans@arm.com waitingForLayer.pop_front(); 2679080Smatt.evans@arm.com 2683170SN/A // tell the port to retry, which in some cases ends up calling the 2699080Smatt.evans@arm.com // layer again 2709080Smatt.evans@arm.com retryingPort->sendRetry(); 2719080Smatt.evans@arm.com 2729080Smatt.evans@arm.com // If the layer is still in the retry state, sendTiming wasn't 2733170SN/A // called in zero time (e.g. the cache does this), burn a cycle 2749080Smatt.evans@arm.com if (state == RETRY) { 2759080Smatt.evans@arm.com // update the state to busy and reset the retrying port, we 2769080Smatt.evans@arm.com // have done our bit and sent the retry 2779080Smatt.evans@arm.com state = BUSY; 2789080Smatt.evans@arm.com 2799080Smatt.evans@arm.com // occupy the crossbar layer until the next cycle ends 2809080Smatt.evans@arm.com occupyLayer(xbar.clockEdge(Cycles(1))); 2819080Smatt.evans@arm.com } 2829080Smatt.evans@arm.com} 2839080Smatt.evans@arm.com 2849080Smatt.evans@arm.comtemplate <typename SrcType, typename DstType> 2859080Smatt.evans@arm.comvoid 28612218Snikos.nikoleris@arm.comBaseXBar::Layer<SrcType,DstType>::recvRetry() 28713998Stiago.muck@arm.com{ 28813998Stiago.muck@arm.com // we should never get a retry without having failed to forward 28913998Stiago.muck@arm.com // something to this port 29013998Stiago.muck@arm.com assert(waitingForPeer != NULL); 29112218Snikos.nikoleris@arm.com 29212218Snikos.nikoleris@arm.com // add the port where the failed packet originated to the front of 29312218Snikos.nikoleris@arm.com // the waiting ports for the layer, this allows us to call retry 29412218Snikos.nikoleris@arm.com // on the port immediately if the crossbar layer is idle 2959080Smatt.evans@arm.com waitingForLayer.push_front(waitingForPeer); 2969080Smatt.evans@arm.com 2979080Smatt.evans@arm.com // we are no longer waiting for the peer 2989080Smatt.evans@arm.com waitingForPeer = NULL; 2993170SN/A 3003170SN/A // if the layer is idle, retry this port straight away, if we 3013170SN/A // are busy, then simply let the port wait for its turn 3029080Smatt.evans@arm.com if (state == IDLE) { 3033170SN/A retryWaiting(); 3043170SN/A } else { 30513486Sgiacomo.travaglini@arm.com assert(state == BUSY); 30613346Sgabeblack@google.com } 30713346Sgabeblack@google.com} 30813346Sgabeblack@google.com 30913346Sgabeblack@google.comPortID 31013346Sgabeblack@google.comBaseXBar::findPort(Addr addr) 31113346Sgabeblack@google.com{ 31213346Sgabeblack@google.com // we should never see any address lookups before we've got the 31313346Sgabeblack@google.com // ranges of all connected slave modules 31413346Sgabeblack@google.com assert(gotAllAddrRanges); 31513346Sgabeblack@google.com 31613346Sgabeblack@google.com // Check the cache 31713346Sgabeblack@google.com PortID dest_id = checkPortCache(addr); 31813346Sgabeblack@google.com if (dest_id != InvalidPortID) 31913346Sgabeblack@google.com return dest_id; 32013346Sgabeblack@google.com 32113346Sgabeblack@google.com // Check the address map interval tree 32213346Sgabeblack@google.com auto i = portMap.find(addr); 32313346Sgabeblack@google.com if (i != portMap.end()) { 3244626SN/A dest_id = i->second; 32513346Sgabeblack@google.com updatePortCache(dest_id, i->first); 3264626SN/A return dest_id; 32713346Sgabeblack@google.com } 3284626SN/A 3294626SN/A // Check if this matches the default range 3308931Sandreas.hansson@arm.com if (useDefaultRange) { 3318931Sandreas.hansson@arm.com if (defaultRange.contains(addr)) { 3322413SN/A DPRINTF(AddrRanges, " found addr %#llx on default\n", 33311284Sandreas.hansson@arm.com addr); 33411284Sandreas.hansson@arm.com return defaultPortID; 3354626SN/A } 3368931Sandreas.hansson@arm.com } else if (defaultPortID != InvalidPortID) { 3373175SN/A DPRINTF(AddrRanges, "Unable to find destination for addr %#llx, " 3384626SN/A "will use default port\n", addr); 33911199Sandreas.hansson@arm.com return defaultPortID; 34010883Sali.jafri@arm.com } 34110883Sali.jafri@arm.com 34210883Sali.jafri@arm.com // we should use the range for the default port and it did not 34310883Sali.jafri@arm.com // match, or the default port is not set 34410883Sali.jafri@arm.com fatal("Unable to find destination for addr %#llx on %s\n", addr, 34513856Sodanrc@yahoo.com.br name()); 34610883Sali.jafri@arm.com} 3479405Sandreas.hansson@arm.com 3484626SN/A/** Function called by the port when the crossbar is receiving a range change.*/ 3494626SN/Avoid 35011306Santhony.gutierrez@amd.comBaseXBar::recvRangeChange(PortID master_port_id) 35111306Santhony.gutierrez@amd.com{ 35213377Sodanrc@yahoo.com.br DPRINTF(AddrRanges, "Received range change from slave port %s\n", 35311306Santhony.gutierrez@amd.com masterPorts[master_port_id]->getSlavePort().name()); 35411306Santhony.gutierrez@amd.com 35511306Santhony.gutierrez@amd.com // remember that we got a range from this master port and thus the 35611306Santhony.gutierrez@amd.com // connected slave module 35711306Santhony.gutierrez@amd.com gotAddrRanges[master_port_id] = true; 35811306Santhony.gutierrez@amd.com 3594040SN/A // update the global flag 36013377Sodanrc@yahoo.com.br if (!gotAllAddrRanges) { 36113377Sodanrc@yahoo.com.br // take a logical AND of all the ports and see if we got 3624040SN/A // ranges from everyone 36311306Santhony.gutierrez@amd.com gotAllAddrRanges = true; 36411306Santhony.gutierrez@amd.com std::vector<bool>::const_iterator r = gotAddrRanges.begin(); 36511306Santhony.gutierrez@amd.com while (gotAllAddrRanges && r != gotAddrRanges.end()) { 36613377Sodanrc@yahoo.com.br gotAllAddrRanges &= *r++; 36713377Sodanrc@yahoo.com.br } 3684040SN/A if (gotAllAddrRanges) 36911306Santhony.gutierrez@amd.com DPRINTF(AddrRanges, "Got address ranges from all slaves\n"); 37011306Santhony.gutierrez@amd.com } 37111306Santhony.gutierrez@amd.com 37211306Santhony.gutierrez@amd.com // note that we could get the range from the default port at any 37311306Santhony.gutierrez@amd.com // point in time, and we cannot assume that the default range is 37411306Santhony.gutierrez@amd.com // set before the other ones are, so we do additional checks once 37511306Santhony.gutierrez@amd.com // all ranges are provided 37611306Santhony.gutierrez@amd.com if (master_port_id == defaultPortID) { 37711306Santhony.gutierrez@amd.com // only update if we are indeed checking ranges for the 37811306Santhony.gutierrez@amd.com // default port since the port might not have a valid range 37911306Santhony.gutierrez@amd.com // otherwise 38011306Santhony.gutierrez@amd.com if (useDefaultRange) { 38111306Santhony.gutierrez@amd.com AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 38211306Santhony.gutierrez@amd.com 38311306Santhony.gutierrez@amd.com if (ranges.size() != 1) 38411306Santhony.gutierrez@amd.com fatal("Crossbar %s may only have a single default range", 38511306Santhony.gutierrez@amd.com name()); 38611306Santhony.gutierrez@amd.com 38711306Santhony.gutierrez@amd.com defaultRange = ranges.front(); 3884040SN/A } 3894626SN/A } else { 3904626SN/A // the ports are allowed to update their address ranges 3916102SN/A // dynamically, so remove any existing entries 39212218Snikos.nikoleris@arm.com if (gotAddrRanges[master_port_id]) { 39312218Snikos.nikoleris@arm.com for (auto p = portMap.begin(); p != portMap.end(); ) { 39412218Snikos.nikoleris@arm.com if (p->second == master_port_id) 3954626SN/A // erasing invalidates the iterator, so advance it 3964040SN/A // before the deletion takes place 39713377Sodanrc@yahoo.com.br portMap.erase(p++); 39813377Sodanrc@yahoo.com.br else 39913377Sodanrc@yahoo.com.br p++; 4006429SN/A } 4019053Sdam.sunwoo@arm.com } 4029053Sdam.sunwoo@arm.com 4038719SN/A AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 4049053Sdam.sunwoo@arm.com 40512354Snikos.nikoleris@arm.com for (const auto& r: ranges) { 40612354Snikos.nikoleris@arm.com DPRINTF(AddrRanges, "Adding range %s for id %d\n", 40712354Snikos.nikoleris@arm.com r.to_string(), master_port_id); 40812354Snikos.nikoleris@arm.com if (portMap.insert(r, master_port_id) == portMap.end()) { 40912354Snikos.nikoleris@arm.com PortID conflict_id = portMap.find(r)->second; 41010583SCurtis.Dunham@arm.com fatal("%s has two ports responding within range %s:\n\t%s\n\t%s\n", 4114626SN/A name(), 4124626SN/A r.to_string(), 4139663Suri.wiener@arm.com masterPorts[master_port_id]->getSlavePort().name(), 41413377Sodanrc@yahoo.com.br masterPorts[conflict_id]->getSlavePort().name()); 41511653SBrad.Beckmann@amd.com } 4169663Suri.wiener@arm.com } 4179663Suri.wiener@arm.com } 4186429SN/A 4194626SN/A // if we have received ranges from all our neighbouring slave 4209053Sdam.sunwoo@arm.com // modules, go ahead and tell our connected master modules in 4219053Sdam.sunwoo@arm.com // turn, this effectively assumes a tree structure of the system 4224626SN/A if (gotAllAddrRanges) { 4234040SN/A DPRINTF(AddrRanges, "Aggregating address ranges\n"); 42412354Snikos.nikoleris@arm.com xbarRanges.clear(); 4252413SN/A 4262420SN/A // start out with the default range 4274626SN/A if (useDefaultRange) { 4288931Sandreas.hansson@arm.com if (!gotAddrRanges[defaultPortID]) 4294626SN/A fatal("Crossbar %s uses default range, but none provided", 4302413SN/A name()); 4312413SN/A 4328931Sandreas.hansson@arm.com xbarRanges.push_back(defaultRange); 4338931Sandreas.hansson@arm.com DPRINTF(AddrRanges, "-- Adding default %s\n", 4348931Sandreas.hansson@arm.com defaultRange.to_string()); 43513856Sodanrc@yahoo.com.br } 4364626SN/A 4379405Sandreas.hansson@arm.com // merge all interleaved ranges and add any range that is not 4384626SN/A // a subset of the default range 4395314SN/A std::vector<AddrRange> intlv_ranges; 44013377Sodanrc@yahoo.com.br for (const auto& r: portMap) { 44113377Sodanrc@yahoo.com.br // if the range is interleaved then save it for now 44213377Sodanrc@yahoo.com.br if (r.first.interleaved()) { 4434626SN/A // if we already got interleaved ranges that are not 4448931Sandreas.hansson@arm.com // part of the same range, then first do a merge 4455314SN/A // before we add the new one 44613377Sodanrc@yahoo.com.br if (!intlv_ranges.empty() && 44713377Sodanrc@yahoo.com.br !intlv_ranges.back().mergesWith(r.first)) { 44813377Sodanrc@yahoo.com.br DPRINTF(AddrRanges, "-- Merging range from %d ranges\n", 4494626SN/A intlv_ranges.size()); 4508931Sandreas.hansson@arm.com AddrRange merged_range(intlv_ranges); 4515314SN/A // next decide if we keep the merged range or not 4525315SN/A if (!(useDefaultRange && 4535315SN/A merged_range.isSubset(defaultRange))) { 4548992SAli.Saidi@ARM.com xbarRanges.push_back(merged_range); 4555315SN/A DPRINTF(AddrRanges, "-- Adding merged range %s\n", 4565315SN/A merged_range.to_string()); 4575314SN/A } 4585315SN/A intlv_ranges.clear(); 4595314SN/A } 4604626SN/A intlv_ranges.push_back(r.first); 4618931Sandreas.hansson@arm.com } else { 4624626SN/A // keep the current range if not a subset of the default 4634626SN/A if (!(useDefaultRange && 4644490SN/A r.first.isSubset(defaultRange))) { 465 xbarRanges.push_back(r.first); 466 DPRINTF(AddrRanges, "-- Adding range %s\n", 467 r.first.to_string()); 468 } 469 } 470 } 471 472 // if there is still interleaved ranges waiting to be merged, 473 // go ahead and do it 474 if (!intlv_ranges.empty()) { 475 DPRINTF(AddrRanges, "-- Merging range from %d ranges\n", 476 intlv_ranges.size()); 477 AddrRange merged_range(intlv_ranges); 478 if (!(useDefaultRange && merged_range.isSubset(defaultRange))) { 479 xbarRanges.push_back(merged_range); 480 DPRINTF(AddrRanges, "-- Adding merged range %s\n", 481 merged_range.to_string()); 482 } 483 } 484 485 // also check that no range partially overlaps with the 486 // default range, this has to be done after all ranges are set 487 // as there are no guarantees for when the default range is 488 // update with respect to the other ones 489 if (useDefaultRange) { 490 for (const auto& r: xbarRanges) { 491 // see if the new range is partially 492 // overlapping the default range 493 if (r.intersects(defaultRange) && 494 !r.isSubset(defaultRange)) 495 fatal("Range %s intersects the " \ 496 "default range of %s but is not a " \ 497 "subset\n", r.to_string(), name()); 498 } 499 } 500 501 // tell all our neighbouring master ports that our address 502 // ranges have changed 503 for (const auto& s: slavePorts) 504 s->sendRangeChange(); 505 } 506 507 clearPortCache(); 508} 509 510AddrRangeList 511BaseXBar::getAddrRanges() const 512{ 513 // we should never be asked without first having sent a range 514 // change, and the latter is only done once we have all the ranges 515 // of the connected devices 516 assert(gotAllAddrRanges); 517 518 // at the moment, this never happens, as there are no cycles in 519 // the range queries and no devices on the master side of a crossbar 520 // (CPU, cache, bridge etc) actually care about the ranges of the 521 // ports they are connected to 522 523 DPRINTF(AddrRanges, "Received address range request\n"); 524 525 return xbarRanges; 526} 527 528void 529BaseXBar::regStats() 530{ 531 using namespace Stats; 532 533 transDist 534 .init(MemCmd::NUM_MEM_CMDS) 535 .name(name() + ".trans_dist") 536 .desc("Transaction distribution") 537 .flags(nozero); 538 539 // get the string representation of the commands 540 for (int i = 0; i < MemCmd::NUM_MEM_CMDS; i++) { 541 MemCmd cmd(i); 542 const std::string &cstr = cmd.toString(); 543 transDist.subname(i, cstr); 544 } 545 546 pktCount 547 .init(slavePorts.size(), masterPorts.size()) 548 .name(name() + ".pkt_count") 549 .desc("Packet count per connected master and slave (bytes)") 550 .flags(total | nozero | nonan); 551 552 pktSize 553 .init(slavePorts.size(), masterPorts.size()) 554 .name(name() + ".pkt_size") 555 .desc("Cumulative packet size per connected master and slave (bytes)") 556 .flags(total | nozero | nonan); 557 558 // both the packet count and total size are two-dimensional 559 // vectors, indexed by slave port id and master port id, thus the 560 // neighbouring master and slave, they do not differentiate what 561 // came from the master and was forwarded to the slave (requests 562 // and snoop responses) and what came from the slave and was 563 // forwarded to the master (responses and snoop requests) 564 for (int i = 0; i < slavePorts.size(); i++) { 565 pktCount.subname(i, slavePorts[i]->getMasterPort().name()); 566 pktSize.subname(i, slavePorts[i]->getMasterPort().name()); 567 for (int j = 0; j < masterPorts.size(); j++) { 568 pktCount.ysubname(j, masterPorts[j]->getSlavePort().name()); 569 pktSize.ysubname(j, masterPorts[j]->getSlavePort().name()); 570 } 571 } 572} 573 574template <typename SrcType, typename DstType> 575unsigned int 576BaseXBar::Layer<SrcType,DstType>::drain(DrainManager *dm) 577{ 578 //We should check that we're not "doing" anything, and that noone is 579 //waiting. We might be idle but have someone waiting if the device we 580 //contacted for a retry didn't actually retry. 581 if (state != IDLE) { 582 DPRINTF(Drain, "Crossbar not drained\n"); 583 drainManager = dm; 584 return 1; 585 } 586 return 0; 587} 588 589template <typename SrcType, typename DstType> 590void 591BaseXBar::Layer<SrcType,DstType>::regStats() 592{ 593 using namespace Stats; 594 595 occupancy 596 .name(name() + ".occupancy") 597 .desc("Layer occupancy (ticks)") 598 .flags(nozero); 599 600 utilization 601 .name(name() + ".utilization") 602 .desc("Layer utilization (%)") 603 .precision(1) 604 .flags(nozero); 605 606 utilization = 100 * occupancy / simTicks; 607} 608 609/** 610 * Crossbar layer template instantiations. Could be removed with _impl.hh 611 * file, but since there are only two given options (MasterPort and 612 * SlavePort) it seems a bit excessive at this point. 613 */ 614template class BaseXBar::Layer<SlavePort,MasterPort>; 615template class BaseXBar::Layer<MasterPort,SlavePort>; 616