xbar.cc revision 9611
12207SN/A/* 22207SN/A * Copyright (c) 2011-2013 ARM Limited 32207SN/A * All rights reserved 42207SN/A * 52207SN/A * The license below extends only to copyright in the software and shall 62207SN/A * not be construed as granting a license to any other intellectual 72207SN/A * property including but not limited to intellectual property relating 82207SN/A * to a hardware implementation of the functionality of the software 92207SN/A * licensed hereunder. You may use the software subject to the license 102207SN/A * terms below provided that you ensure that this notice is replicated 112207SN/A * unmodified and in its entirety in all distributions of the software, 122207SN/A * modified or unmodified, in source code or in binary form. 132207SN/A * 142207SN/A * Copyright (c) 2006 The Regents of The University of Michigan 152207SN/A * All rights reserved. 162207SN/A * 172207SN/A * Redistribution and use in source and binary forms, with or without 182207SN/A * modification, are permitted provided that the following conditions are 192207SN/A * met: redistributions of source code must retain the above copyright 202207SN/A * notice, this list of conditions and the following disclaimer; 212207SN/A * redistributions in binary form must reproduce the above copyright 222207SN/A * notice, this list of conditions and the following disclaimer in the 232207SN/A * documentation and/or other materials provided with the distribution; 242207SN/A * neither the name of the copyright holders nor the names of its 252207SN/A * contributors may be used to endorse or promote products derived from 262207SN/A * this software without specific prior written permission. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302207SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312207SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 323589Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 334111Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342474SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 358229Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 366335Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 373760Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 388229Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392454SN/A * 402454SN/A * Authors: Ali Saidi 412680Sktlim@umich.edu * Andreas Hansson 428232Snate@binkert.org * William Wang 432561SN/A */ 448229Snate@binkert.org 454434Ssaidi@eecs.umich.edu/** 462474SN/A * @file 472207SN/A * Definition of a bus object. 482458SN/A */ 492474SN/A 502458SN/A#include "base/misc.hh" 515958Sgblack@eecs.umich.edu#include "base/trace.hh" 525958Sgblack@eecs.umich.edu#include "debug/Bus.hh" 532207SN/A#include "debug/BusAddrRanges.hh" 545154Sgblack@eecs.umich.edu#include "debug/Drain.hh" 555285Sgblack@eecs.umich.edu#include "mem/bus.hh" 565285Sgblack@eecs.umich.edu 572474SN/ABaseBus::BaseBus(const BaseBusParams *p) 582474SN/A : MemObject(p), 592474SN/A headerCycles(p->header_cycles), width(p->width), 602474SN/A gotAddrRanges(p->port_default_connection_count + 612474SN/A p->port_master_connection_count, false), 622474SN/A gotAllAddrRanges(false), defaultPortID(InvalidPortID), 632474SN/A useDefaultRange(p->use_default_range), 642474SN/A blockSize(p->block_size) 653415Sgblack@eecs.umich.edu{} 667741Sgblack@eecs.umich.edu 673415Sgblack@eecs.umich.eduBaseBus::~BaseBus() 683415Sgblack@eecs.umich.edu{ 692474SN/A for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); 702474SN/A ++m) { 717741Sgblack@eecs.umich.edu delete *m; 727741Sgblack@eecs.umich.edu } 734111Sgblack@eecs.umich.edu 747720Sgblack@eecs.umich.edu for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); 757741Sgblack@eecs.umich.edu ++s) { 767741Sgblack@eecs.umich.edu delete *s; 777720Sgblack@eecs.umich.edu } 785128Sgblack@eecs.umich.edu} 797741Sgblack@eecs.umich.edu 807720Sgblack@eecs.umich.eduvoid 815128Sgblack@eecs.umich.eduBaseBus::init() 827741Sgblack@eecs.umich.edu{ 835128Sgblack@eecs.umich.edu // determine the maximum peer block size, look at both the 845128Sgblack@eecs.umich.edu // connected master and slave modules 857741Sgblack@eecs.umich.edu uint32_t peer_block_size = 0; 865128Sgblack@eecs.umich.edu 877720Sgblack@eecs.umich.edu for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); 885128Sgblack@eecs.umich.edu ++m) { 897741Sgblack@eecs.umich.edu peer_block_size = std::max((*m)->peerBlockSize(), peer_block_size); 907720Sgblack@eecs.umich.edu } 915128Sgblack@eecs.umich.edu 927741Sgblack@eecs.umich.edu for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 935128Sgblack@eecs.umich.edu ++s) { 947720Sgblack@eecs.umich.edu peer_block_size = std::max((*s)->peerBlockSize(), peer_block_size); 955128Sgblack@eecs.umich.edu } 967741Sgblack@eecs.umich.edu 977720Sgblack@eecs.umich.edu // if the peers do not have a block size, use the default value 985128Sgblack@eecs.umich.edu // set through the bus parameters 997741Sgblack@eecs.umich.edu if (peer_block_size != 0) 1005128Sgblack@eecs.umich.edu blockSize = peer_block_size; 1017720Sgblack@eecs.umich.edu 1025128Sgblack@eecs.umich.edu // check if the block size is a value known to work 1037741Sgblack@eecs.umich.edu if (!(blockSize == 16 || blockSize == 32 || blockSize == 64 || 1045128Sgblack@eecs.umich.edu blockSize == 128)) 1057720Sgblack@eecs.umich.edu warn_once("Block size is neither 16, 32, 64 or 128 bytes.\n"); 1064111Sgblack@eecs.umich.edu} 1074111Sgblack@eecs.umich.edu 1084111Sgblack@eecs.umich.eduBaseMasterPort & 1094111Sgblack@eecs.umich.eduBaseBus::getMasterPort(const std::string &if_name, PortID idx) 1104111Sgblack@eecs.umich.edu{ 1114111Sgblack@eecs.umich.edu if (if_name == "master" && idx < masterPorts.size()) { 1122474SN/A // the master port index translates directly to the vector position 1137532Ssteve.reinhardt@amd.com return *masterPorts[idx]; 1144111Sgblack@eecs.umich.edu } else if (if_name == "default") { 1157532Ssteve.reinhardt@amd.com return *masterPorts[defaultPortID]; 1164111Sgblack@eecs.umich.edu } else { 1175713Shsul@eecs.umich.edu return MemObject::getMasterPort(if_name, idx); 1187741Sgblack@eecs.umich.edu } 1194111Sgblack@eecs.umich.edu} 1207741Sgblack@eecs.umich.edu 1215713Shsul@eecs.umich.eduBaseSlavePort & 1222646Ssaidi@eecs.umich.eduBaseBus::getSlavePort(const std::string &if_name, PortID idx) 1235713Shsul@eecs.umich.edu{ 1244997Sgblack@eecs.umich.edu if (if_name == "slave" && idx < slavePorts.size()) { 1252561SN/A // the slave port index translates directly to the vector position 1262561SN/A return *slavePorts[idx]; 1272561SN/A } else { 1282561SN/A return MemObject::getSlavePort(if_name, idx); 1297741Sgblack@eecs.umich.edu } 1307741Sgblack@eecs.umich.edu} 1315713Shsul@eecs.umich.edu 1327741Sgblack@eecs.umich.eduvoid 1337741Sgblack@eecs.umich.eduBaseBus::calcPacketTiming(PacketPtr pkt) 1345713Shsul@eecs.umich.edu{ 1357741Sgblack@eecs.umich.edu // the bus will be called at a time that is not necessarily 1367741Sgblack@eecs.umich.edu // coinciding with its own clock, so start by determining how long 1375713Shsul@eecs.umich.edu // until the next clock edge (could be zero) 1387741Sgblack@eecs.umich.edu Tick offset = nextCycle() - curTick(); 1397741Sgblack@eecs.umich.edu 1405713Shsul@eecs.umich.edu // determine how many cycles are needed to send the data 1417741Sgblack@eecs.umich.edu unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0; 1426337Sgblack@eecs.umich.edu 1437741Sgblack@eecs.umich.edu // before setting the bus delay fields of the packet, ensure that 1447741Sgblack@eecs.umich.edu // the delay from any previous bus has been accounted for 1455713Shsul@eecs.umich.edu if (pkt->busFirstWordDelay != 0 || pkt->busLastWordDelay != 0) 1467741Sgblack@eecs.umich.edu panic("Packet %s already has bus delay (%d, %d) that should be " 1475713Shsul@eecs.umich.edu "accounted for.\n", pkt->cmdString(), pkt->busFirstWordDelay, 1487741Sgblack@eecs.umich.edu pkt->busLastWordDelay); 1495713Shsul@eecs.umich.edu 1504997Sgblack@eecs.umich.edu // The first word will be delivered on the cycle after the header. 1514997Sgblack@eecs.umich.edu pkt->busFirstWordDelay = (headerCycles + 1) * clockPeriod() + offset; 1524997Sgblack@eecs.umich.edu 1534997Sgblack@eecs.umich.edu // Note that currently busLastWordDelay can be smaller than 1547741Sgblack@eecs.umich.edu // busFirstWordDelay if the packet has no data 1555713Shsul@eecs.umich.edu pkt->busLastWordDelay = (headerCycles + dataCycles) * clockPeriod() + 1562474SN/A offset; 1572474SN/A} 1585285Sgblack@eecs.umich.edu 1597532Ssteve.reinhardt@amd.comtemplate <typename PortClass> 1602585SN/ABaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name) : 1617532Ssteve.reinhardt@amd.com Drainable(), 1625285Sgblack@eecs.umich.edu bus(_bus), _name(_name), state(IDLE), drainManager(NULL), 1635713Shsul@eecs.umich.edu retryingPort(NULL), releaseEvent(this) 1647741Sgblack@eecs.umich.edu{ 1655713Shsul@eecs.umich.edu} 1665285Sgblack@eecs.umich.edu 1675285Sgblack@eecs.umich.edutemplate <typename PortClass> 1684111Sgblack@eecs.umich.eduvoid BaseBus::Layer<PortClass>::occupyLayer(Tick until) 1693415Sgblack@eecs.umich.edu{ 1702561SN/A // ensure the state is busy or in retry and never idle at this 1717532Ssteve.reinhardt@amd.com // point, as the bus should transition from idle as soon as it has 1722561SN/A // decided to forward the packet to prevent any follow-on calls to 1737532Ssteve.reinhardt@amd.com // sendTiming seeing an unoccupied bus 1745285Sgblack@eecs.umich.edu assert(state != IDLE); 1755713Shsul@eecs.umich.edu 1767741Sgblack@eecs.umich.edu // note that we do not change the bus state here, if we are going 1775713Shsul@eecs.umich.edu // from idle to busy it is handled by tryTiming, and if we 1785285Sgblack@eecs.umich.edu // are in retry we should remain in retry such that 1795285Sgblack@eecs.umich.edu // succeededTiming still sees the accurate state 1805285Sgblack@eecs.umich.edu 1815285Sgblack@eecs.umich.edu // until should never be 0 as express snoops never occupy the bus 1825285Sgblack@eecs.umich.edu assert(until != 0); 1835285Sgblack@eecs.umich.edu bus.schedule(releaseEvent, until); 1845285Sgblack@eecs.umich.edu 1855285Sgblack@eecs.umich.edu DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", 1865285Sgblack@eecs.umich.edu curTick(), until); 1875285Sgblack@eecs.umich.edu} 1885771Shsul@eecs.umich.edu 1895285Sgblack@eecs.umich.edutemplate <typename PortClass> 1905285Sgblack@eecs.umich.edubool 1912474SN/ABaseBus::Layer<PortClass>::tryTiming(PortClass* port) 1923044Sgblack@eecs.umich.edu{ 1937741Sgblack@eecs.umich.edu // first we see if the bus is busy, next we check if we are in a 1943044Sgblack@eecs.umich.edu // retry with a port other than the current one 1953044Sgblack@eecs.umich.edu if (state == BUSY || (state == RETRY && port != retryingPort)) { 1963044Sgblack@eecs.umich.edu // put the port at the end of the retry list 1973044Sgblack@eecs.umich.edu retryList.push_back(port); 1987741Sgblack@eecs.umich.edu return false; 1997741Sgblack@eecs.umich.edu } 2005286Sgblack@eecs.umich.edu 2012561SN/A // @todo: here we should no longer consider this port retrying 2022561SN/A // once we can differentiate retries due to a busy bus and a 2032561SN/A // failed forwarding, for now keep it so we can stick it back at 2042561SN/A // the front of the retry list if needed 2052585SN/A 2062585SN/A // update the state which is shared for request, response and 2072585SN/A // snoop responses, if we were idle we are now busy, if we are in 2082585SN/A // a retry, then do not change 2092585SN/A if (state == IDLE) 2102585SN/A state = BUSY; 2112585SN/A 2127741Sgblack@eecs.umich.edu return true; 2137741Sgblack@eecs.umich.edu} 2147741Sgblack@eecs.umich.edu 2152585SN/Atemplate <typename PortClass> 2162585SN/Avoid 2172585SN/ABaseBus::Layer<PortClass>::succeededTiming(Tick busy_time) 2182585SN/A{ 2192585SN/A // if a retrying port succeeded, update the state and reset the 2202585SN/A // retrying port 2212585SN/A if (state == RETRY) { 2222585SN/A DPRINTF(BaseBus, "Succeeded retry from %s\n", 2232585SN/A retryingPort->name()); 2242585SN/A state = BUSY; 2252585SN/A retryingPort = NULL; 2267741Sgblack@eecs.umich.edu } 2277741Sgblack@eecs.umich.edu 2282976Sgblack@eecs.umich.edu // we should either have gone from idle to busy in the 2297741Sgblack@eecs.umich.edu // tryTiming test, or just gone from a retry to busy 2307741Sgblack@eecs.umich.edu assert(state == BUSY); 2314793Sgblack@eecs.umich.edu 2327741Sgblack@eecs.umich.edu // occupy the bus accordingly 2334793Sgblack@eecs.umich.edu occupyLayer(busy_time); 2347741Sgblack@eecs.umich.edu} 2357741Sgblack@eecs.umich.edu 2364793Sgblack@eecs.umich.edutemplate <typename PortClass> 2372976Sgblack@eecs.umich.eduvoid 2382976Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time) 2394793Sgblack@eecs.umich.edu{ 2402976Sgblack@eecs.umich.edu // if the current failing port is the retrying one, then for now stick it 2414793Sgblack@eecs.umich.edu // back at the front of the retry list to not change any regressions 2422976Sgblack@eecs.umich.edu if (state == RETRY) { 2434793Sgblack@eecs.umich.edu // we should never see a retry from any port but the current 2447741Sgblack@eecs.umich.edu // retry port at this point 2457741Sgblack@eecs.umich.edu assert(port == retryingPort); 2467741Sgblack@eecs.umich.edu retryList.push_front(port); 2474793Sgblack@eecs.umich.edu retryingPort = NULL; 2487741Sgblack@eecs.umich.edu } else { 2494793Sgblack@eecs.umich.edu // if we are not in a retry, i.e. busy (but never idle), then 2507741Sgblack@eecs.umich.edu // add the port at the end of the retry list 2514793Sgblack@eecs.umich.edu retryList.push_back(port); 2527741Sgblack@eecs.umich.edu } 2534793Sgblack@eecs.umich.edu 2544793Sgblack@eecs.umich.edu // even if we retried the current one and did not succeed, 2554793Sgblack@eecs.umich.edu // we are no longer retrying but instead busy 2564793Sgblack@eecs.umich.edu state = BUSY; 2577741Sgblack@eecs.umich.edu 2584793Sgblack@eecs.umich.edu // occupy the bus accordingly 2592976Sgblack@eecs.umich.edu occupyLayer(busy_time); 2602585SN/A} 2617741Sgblack@eecs.umich.edu 2622561SN/Atemplate <typename PortClass> 2634164Sgblack@eecs.umich.eduvoid 2645286Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::releaseLayer() 2654111Sgblack@eecs.umich.edu{ 2667741Sgblack@eecs.umich.edu // releasing the bus means we should now be idle 2677741Sgblack@eecs.umich.edu assert(state == BUSY); 2684111Sgblack@eecs.umich.edu assert(!releaseEvent.scheduled()); 2694111Sgblack@eecs.umich.edu 2704111Sgblack@eecs.umich.edu // update the state 2714111Sgblack@eecs.umich.edu state = IDLE; 2724111Sgblack@eecs.umich.edu 2734111Sgblack@eecs.umich.edu // bus is now idle, so if someone is waiting we can retry 2744111Sgblack@eecs.umich.edu if (!retryList.empty()) { 2754111Sgblack@eecs.umich.edu // note that we block (return false on recvTiming) both 2764111Sgblack@eecs.umich.edu // because the bus is busy and because the destination is 2774111Sgblack@eecs.umich.edu // busy, and in the latter case the bus may be released before 2784111Sgblack@eecs.umich.edu // we see a retry from the destination 2797741Sgblack@eecs.umich.edu retryWaiting(); 2805286Sgblack@eecs.umich.edu } else if (drainManager) { 2815286Sgblack@eecs.umich.edu DPRINTF(Drain, "Bus done draining, signaling drain manager\n"); 2825286Sgblack@eecs.umich.edu //If we weren't able to drain before, do it now. 2835286Sgblack@eecs.umich.edu drainManager->signalDrainDone(); 2845286Sgblack@eecs.umich.edu // Clear the drain event once we're done with it. 2855286Sgblack@eecs.umich.edu drainManager = NULL; 2864111Sgblack@eecs.umich.edu } 2877741Sgblack@eecs.umich.edu} 2884111Sgblack@eecs.umich.edu 2894111Sgblack@eecs.umich.edutemplate <typename PortClass> 2904111Sgblack@eecs.umich.eduvoid 2914111Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::retryWaiting() 2924111Sgblack@eecs.umich.edu{ 2934111Sgblack@eecs.umich.edu // this should never be called with an empty retry list 2944111Sgblack@eecs.umich.edu assert(!retryList.empty()); 2954111Sgblack@eecs.umich.edu 2967741Sgblack@eecs.umich.edu // we always go to retrying from idle 2975286Sgblack@eecs.umich.edu assert(state == IDLE); 2984111Sgblack@eecs.umich.edu 2994111Sgblack@eecs.umich.edu // update the state 3004111Sgblack@eecs.umich.edu state = RETRY; 3014111Sgblack@eecs.umich.edu 3024111Sgblack@eecs.umich.edu // set the retrying port to the front of the retry list and pop it 3034111Sgblack@eecs.umich.edu // off the list 3047741Sgblack@eecs.umich.edu assert(retryingPort == NULL); 3057741Sgblack@eecs.umich.edu retryingPort = retryList.front(); 3065286Sgblack@eecs.umich.edu retryList.pop_front(); 3075286Sgblack@eecs.umich.edu 3085286Sgblack@eecs.umich.edu // note that we might have blocked on the receiving port being 3095286Sgblack@eecs.umich.edu // busy (rather than the bus itself) and now call retry before the 3105286Sgblack@eecs.umich.edu // destination called retry on the bus 3115286Sgblack@eecs.umich.edu retryingPort->sendRetry(); 3125286Sgblack@eecs.umich.edu 3135286Sgblack@eecs.umich.edu // If the bus is still in the retry state, sendTiming wasn't 3144111Sgblack@eecs.umich.edu // called in zero time (e.g. the cache does this) 3155286Sgblack@eecs.umich.edu if (state == RETRY) { 3164111Sgblack@eecs.umich.edu //Burn a cycle for the missed grant. 3174111Sgblack@eecs.umich.edu 3185285Sgblack@eecs.umich.edu // update the state to busy and reset the retrying port 3198601Ssteve.reinhardt@amd.com state = BUSY; 3204111Sgblack@eecs.umich.edu retryingPort = NULL; 3214111Sgblack@eecs.umich.edu 3225286Sgblack@eecs.umich.edu // occupy the bus layer until the next cycle ends 3235286Sgblack@eecs.umich.edu occupyLayer(bus.clockEdge(Cycles(1))); 3245286Sgblack@eecs.umich.edu } 3255286Sgblack@eecs.umich.edu} 3265286Sgblack@eecs.umich.edu 3275286Sgblack@eecs.umich.edutemplate <typename PortClass> 3285286Sgblack@eecs.umich.eduvoid 3295286Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::recvRetry() 3305286Sgblack@eecs.umich.edu{ 3315286Sgblack@eecs.umich.edu // we got a retry from a peer that we tried to send something to 3325286Sgblack@eecs.umich.edu // and failed, but we sent it on the account of someone else, and 3335286Sgblack@eecs.umich.edu // that source port should be on our retry list, however if the 3344111Sgblack@eecs.umich.edu // bus layer is released before this happens and the retry (from 3355941Sgblack@eecs.umich.edu // the bus point of view) is successful then this no longer holds 3365941Sgblack@eecs.umich.edu // and we could in fact have an empty retry list 3375941Sgblack@eecs.umich.edu if (retryList.empty()) 3385941Sgblack@eecs.umich.edu return; 3395941Sgblack@eecs.umich.edu 3405941Sgblack@eecs.umich.edu // if the bus layer is idle 3415941Sgblack@eecs.umich.edu if (state == IDLE) { 3425941Sgblack@eecs.umich.edu // note that we do not care who told us to retry at the moment, we 3435941Sgblack@eecs.umich.edu // merely let the first one on the retry list go 3445941Sgblack@eecs.umich.edu retryWaiting(); 3455941Sgblack@eecs.umich.edu } 3465941Sgblack@eecs.umich.edu} 3474111Sgblack@eecs.umich.edu 3485286Sgblack@eecs.umich.eduPortID 3495286Sgblack@eecs.umich.eduBaseBus::findPort(Addr addr) 3504111Sgblack@eecs.umich.edu{ 3514111Sgblack@eecs.umich.edu // we should never see any address lookups before we've got the 3524111Sgblack@eecs.umich.edu // ranges of all connected slave modules 3535285Sgblack@eecs.umich.edu assert(gotAllAddrRanges); 3545567Snate@binkert.org 3554111Sgblack@eecs.umich.edu // Check the cache 3567741Sgblack@eecs.umich.edu PortID dest_id = checkPortCache(addr); 3575286Sgblack@eecs.umich.edu if (dest_id != InvalidPortID) 3585286Sgblack@eecs.umich.edu return dest_id; 3595286Sgblack@eecs.umich.edu 3604111Sgblack@eecs.umich.edu // Check the address map interval tree 3617741Sgblack@eecs.umich.edu PortMapConstIter i = portMap.find(addr); 3624111Sgblack@eecs.umich.edu if (i != portMap.end()) { 3634111Sgblack@eecs.umich.edu dest_id = i->second; 3647741Sgblack@eecs.umich.edu updatePortCache(dest_id, i->first); 3657741Sgblack@eecs.umich.edu return dest_id; 3664111Sgblack@eecs.umich.edu } 3674111Sgblack@eecs.umich.edu 3684111Sgblack@eecs.umich.edu // Check if this matches the default range 3694111Sgblack@eecs.umich.edu if (useDefaultRange) { 3704111Sgblack@eecs.umich.edu if (defaultRange.contains(addr)) { 3715285Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, " found addr %#llx on default\n", 3727741Sgblack@eecs.umich.edu addr); 3735285Sgblack@eecs.umich.edu return defaultPortID; 3745286Sgblack@eecs.umich.edu } 3755286Sgblack@eecs.umich.edu } else if (defaultPortID != InvalidPortID) { 3765286Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " 3775286Sgblack@eecs.umich.edu "will use default port\n", addr); 3784111Sgblack@eecs.umich.edu return defaultPortID; 3794117Sgblack@eecs.umich.edu } 3804117Sgblack@eecs.umich.edu 3814111Sgblack@eecs.umich.edu // we should use the range for the default port and it did not 3824111Sgblack@eecs.umich.edu // match, or the default port is not set 3834111Sgblack@eecs.umich.edu fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 3847741Sgblack@eecs.umich.edu name()); 3857741Sgblack@eecs.umich.edu} 3867741Sgblack@eecs.umich.edu 3874111Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a range change.*/ 3885285Sgblack@eecs.umich.eduvoid 3894111Sgblack@eecs.umich.eduBaseBus::recvRangeChange(PortID master_port_id) 3905713Shsul@eecs.umich.edu{ 3917741Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Received range change from slave port %s\n", 3927741Sgblack@eecs.umich.edu masterPorts[master_port_id]->getSlavePort().name()); 3937741Sgblack@eecs.umich.edu 3947741Sgblack@eecs.umich.edu // remember that we got a range from this master port and thus the 3955713Shsul@eecs.umich.edu // connected slave module 3964111Sgblack@eecs.umich.edu gotAddrRanges[master_port_id] = true; 3975231Sgblack@eecs.umich.edu 3985231Sgblack@eecs.umich.edu // update the global flag 3995713Shsul@eecs.umich.edu if (!gotAllAddrRanges) { 4005231Sgblack@eecs.umich.edu // take a logical AND of all the ports and see if we got 4017720Sgblack@eecs.umich.edu // ranges from everyone 4024111Sgblack@eecs.umich.edu gotAllAddrRanges = true; 4037741Sgblack@eecs.umich.edu std::vector<bool>::const_iterator r = gotAddrRanges.begin(); 4044111Sgblack@eecs.umich.edu while (gotAllAddrRanges && r != gotAddrRanges.end()) { 4054111Sgblack@eecs.umich.edu gotAllAddrRanges &= *r++; 4064111Sgblack@eecs.umich.edu } 4074111Sgblack@eecs.umich.edu if (gotAllAddrRanges) 4085128Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n"); 4095285Sgblack@eecs.umich.edu } 4105285Sgblack@eecs.umich.edu 4115285Sgblack@eecs.umich.edu // note that we could get the range from the default port at any 4125285Sgblack@eecs.umich.edu // point in time, and we cannot assume that the default range is 4135285Sgblack@eecs.umich.edu // set before the other ones are, so we do additional checks once 4145285Sgblack@eecs.umich.edu // all ranges are provided 4155285Sgblack@eecs.umich.edu if (master_port_id == defaultPortID) { 4165285Sgblack@eecs.umich.edu // only update if we are indeed checking ranges for the 4175285Sgblack@eecs.umich.edu // default port since the port might not have a valid range 4185285Sgblack@eecs.umich.edu // otherwise 4195285Sgblack@eecs.umich.edu if (useDefaultRange) { 4205285Sgblack@eecs.umich.edu AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 4215285Sgblack@eecs.umich.edu 4225285Sgblack@eecs.umich.edu if (ranges.size() != 1) 4235285Sgblack@eecs.umich.edu fatal("Bus %s may only have a single default range", 4245285Sgblack@eecs.umich.edu name()); 4255285Sgblack@eecs.umich.edu 4265285Sgblack@eecs.umich.edu defaultRange = ranges.front(); 4275285Sgblack@eecs.umich.edu } 4285285Sgblack@eecs.umich.edu } else { 4295285Sgblack@eecs.umich.edu // the ports are allowed to update their address ranges 4305285Sgblack@eecs.umich.edu // dynamically, so remove any existing entries 4315285Sgblack@eecs.umich.edu if (gotAddrRanges[master_port_id]) { 4325285Sgblack@eecs.umich.edu for (PortMapIter p = portMap.begin(); p != portMap.end(); ) { 4335128Sgblack@eecs.umich.edu if (p->second == master_port_id) 4345128Sgblack@eecs.umich.edu // erasing invalidates the iterator, so advance it 4355128Sgblack@eecs.umich.edu // before the deletion takes place 4365128Sgblack@eecs.umich.edu portMap.erase(p++); 4375128Sgblack@eecs.umich.edu else 4385128Sgblack@eecs.umich.edu p++; 4395128Sgblack@eecs.umich.edu } 4405128Sgblack@eecs.umich.edu } 4417741Sgblack@eecs.umich.edu 4425128Sgblack@eecs.umich.edu AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 4435128Sgblack@eecs.umich.edu 4445128Sgblack@eecs.umich.edu for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) { 4455128Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Adding range %s for id %d\n", 4467741Sgblack@eecs.umich.edu r->to_string(), master_port_id); 4475128Sgblack@eecs.umich.edu if (portMap.insert(*r, master_port_id) == portMap.end()) { 4485128Sgblack@eecs.umich.edu PortID conflict_id = portMap.find(*r)->second; 4495287Sgblack@eecs.umich.edu fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 4505128Sgblack@eecs.umich.edu name(), 4515128Sgblack@eecs.umich.edu masterPorts[master_port_id]->getSlavePort().name(), 4525128Sgblack@eecs.umich.edu masterPorts[conflict_id]->getSlavePort().name()); 4535128Sgblack@eecs.umich.edu } 4545128Sgblack@eecs.umich.edu } 4555128Sgblack@eecs.umich.edu } 4565128Sgblack@eecs.umich.edu 4575128Sgblack@eecs.umich.edu // if we have received ranges from all our neighbouring slave 4585128Sgblack@eecs.umich.edu // modules, go ahead and tell our connected master modules in 4595128Sgblack@eecs.umich.edu // turn, this effectively assumes a tree structure of the system 4605128Sgblack@eecs.umich.edu if (gotAllAddrRanges) { 4615128Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Aggregating bus ranges\n"); 4625128Sgblack@eecs.umich.edu busRanges.clear(); 4635128Sgblack@eecs.umich.edu 4645128Sgblack@eecs.umich.edu // start out with the default range 4655128Sgblack@eecs.umich.edu if (useDefaultRange) { 4665128Sgblack@eecs.umich.edu if (!gotAddrRanges[defaultPortID]) 4677741Sgblack@eecs.umich.edu fatal("Bus %s uses default range, but none provided", 4687741Sgblack@eecs.umich.edu name()); 4695128Sgblack@eecs.umich.edu 4705128Sgblack@eecs.umich.edu busRanges.push_back(defaultRange); 4715128Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding default %s\n", 4725128Sgblack@eecs.umich.edu defaultRange.to_string()); 4735128Sgblack@eecs.umich.edu } 4745128Sgblack@eecs.umich.edu 4755128Sgblack@eecs.umich.edu // merge all interleaved ranges and add any range that is not 4767741Sgblack@eecs.umich.edu // a subset of the default range 4775128Sgblack@eecs.umich.edu std::vector<AddrRange> intlv_ranges; 4785128Sgblack@eecs.umich.edu for (AddrRangeMap<PortID>::const_iterator r = portMap.begin(); 4795128Sgblack@eecs.umich.edu r != portMap.end(); ++r) { 4805128Sgblack@eecs.umich.edu // if the range is interleaved then save it for now 4817741Sgblack@eecs.umich.edu if (r->first.interleaved()) { 4825128Sgblack@eecs.umich.edu // if we already got interleaved ranges that are not 4835128Sgblack@eecs.umich.edu // part of the same range, then first do a merge 4845128Sgblack@eecs.umich.edu // before we add the new one 4855128Sgblack@eecs.umich.edu if (!intlv_ranges.empty() && 4865128Sgblack@eecs.umich.edu !intlv_ranges.back().mergesWith(r->first)) { 4875128Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n", 4885128Sgblack@eecs.umich.edu intlv_ranges.size()); 4895128Sgblack@eecs.umich.edu AddrRange merged_range(intlv_ranges); 4905128Sgblack@eecs.umich.edu // next decide if we keep the merged range or not 4915128Sgblack@eecs.umich.edu if (!(useDefaultRange && 4925128Sgblack@eecs.umich.edu merged_range.isSubset(defaultRange))) { 4935128Sgblack@eecs.umich.edu busRanges.push_back(merged_range); 4945128Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding merged range %s\n", 4955128Sgblack@eecs.umich.edu merged_range.to_string()); 4965128Sgblack@eecs.umich.edu } 4975128Sgblack@eecs.umich.edu intlv_ranges.clear(); 4985128Sgblack@eecs.umich.edu } 4995128Sgblack@eecs.umich.edu intlv_ranges.push_back(r->first); 5005128Sgblack@eecs.umich.edu } else { 5015958Sgblack@eecs.umich.edu // keep the current range if not a subset of the default 5025958Sgblack@eecs.umich.edu if (!(useDefaultRange && 5036701Sgblack@eecs.umich.edu r->first.isSubset(defaultRange))) { 5045958Sgblack@eecs.umich.edu busRanges.push_back(r->first); 5055958Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding range %s\n", 5066701Sgblack@eecs.umich.edu r->first.to_string()); 5075958Sgblack@eecs.umich.edu } 5085958Sgblack@eecs.umich.edu } 5095958Sgblack@eecs.umich.edu } 5105958Sgblack@eecs.umich.edu 5115958Sgblack@eecs.umich.edu // if there is still interleaved ranges waiting to be merged, 5125958Sgblack@eecs.umich.edu // go ahead and do it 5135958Sgblack@eecs.umich.edu if (!intlv_ranges.empty()) { 5145958Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n", 5155958Sgblack@eecs.umich.edu intlv_ranges.size()); 5165958Sgblack@eecs.umich.edu AddrRange merged_range(intlv_ranges); 5176701Sgblack@eecs.umich.edu if (!(useDefaultRange && merged_range.isSubset(defaultRange))) { 5185958Sgblack@eecs.umich.edu busRanges.push_back(merged_range); 5195958Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding merged range %s\n", 5206701Sgblack@eecs.umich.edu merged_range.to_string()); 5215958Sgblack@eecs.umich.edu } 5225958Sgblack@eecs.umich.edu } 5235958Sgblack@eecs.umich.edu 5245958Sgblack@eecs.umich.edu // also check that no range partially overlaps with the 5255958Sgblack@eecs.umich.edu // default range, this has to be done after all ranges are set 5265958Sgblack@eecs.umich.edu // as there are no guarantees for when the default range is 5275958Sgblack@eecs.umich.edu // update with respect to the other ones 5285958Sgblack@eecs.umich.edu if (useDefaultRange) { 5295958Sgblack@eecs.umich.edu for (AddrRangeConstIter r = busRanges.begin(); 5305958Sgblack@eecs.umich.edu r != busRanges.end(); ++r) { 5315958Sgblack@eecs.umich.edu // see if the new range is partially 5325958Sgblack@eecs.umich.edu // overlapping the default range 5335958Sgblack@eecs.umich.edu if (r->intersects(defaultRange) && 5345958Sgblack@eecs.umich.edu !r->isSubset(defaultRange)) 5355958Sgblack@eecs.umich.edu fatal("Range %s intersects the " \ 5365958Sgblack@eecs.umich.edu "default range of %s but is not a " \ 5375958Sgblack@eecs.umich.edu "subset\n", r->to_string(), name()); 5385958Sgblack@eecs.umich.edu } 5395958Sgblack@eecs.umich.edu } 5405958Sgblack@eecs.umich.edu 5417741Sgblack@eecs.umich.edu // tell all our neighbouring master ports that our address 5425958Sgblack@eecs.umich.edu // ranges have changed 5435958Sgblack@eecs.umich.edu for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 5445958Sgblack@eecs.umich.edu ++s) 5455958Sgblack@eecs.umich.edu (*s)->sendRangeChange(); 5465958Sgblack@eecs.umich.edu } 5475958Sgblack@eecs.umich.edu 5485958Sgblack@eecs.umich.edu clearPortCache(); 5495958Sgblack@eecs.umich.edu} 5505958Sgblack@eecs.umich.edu 5515958Sgblack@eecs.umich.eduAddrRangeList 5527741Sgblack@eecs.umich.eduBaseBus::getAddrRanges() const 5535958Sgblack@eecs.umich.edu{ 5545958Sgblack@eecs.umich.edu // we should never be asked without first having sent a range 5555958Sgblack@eecs.umich.edu // change, and the latter is only done once we have all the ranges 5565958Sgblack@eecs.umich.edu // of the connected devices 5575958Sgblack@eecs.umich.edu assert(gotAllAddrRanges); 5585958Sgblack@eecs.umich.edu 5595958Sgblack@eecs.umich.edu // at the moment, this never happens, as there are no cycles in 5605958Sgblack@eecs.umich.edu // the range queries and no devices on the master side of a bus 561 // (CPU, cache, bridge etc) actually care about the ranges of the 562 // ports they are connected to 563 564 DPRINTF(BusAddrRanges, "Received address range request\n"); 565 566 return busRanges; 567} 568 569unsigned 570BaseBus::deviceBlockSize() const 571{ 572 return blockSize; 573} 574 575template <typename PortClass> 576unsigned int 577BaseBus::Layer<PortClass>::drain(DrainManager *dm) 578{ 579 //We should check that we're not "doing" anything, and that noone is 580 //waiting. We might be idle but have someone waiting if the device we 581 //contacted for a retry didn't actually retry. 582 if (!retryList.empty() || state != IDLE) { 583 DPRINTF(Drain, "Bus not drained\n"); 584 drainManager = dm; 585 return 1; 586 } 587 return 0; 588} 589 590/** 591 * Bus layer template instantiations. Could be removed with _impl.hh 592 * file, but since there are only two given options (MasterPort and 593 * SlavePort) it seems a bit excessive at this point. 594 */ 595template class BaseBus::Layer<SlavePort>; 596template class BaseBus::Layer<MasterPort>; 597