xbar.cc revision 9278
12381SN/A/* 22592SN/A * Copyright (c) 2011-2012 ARM Limited 32381SN/A * All rights reserved 42381SN/A * 52381SN/A * The license below extends only to copyright in the software and shall 62381SN/A * not be construed as granting a license to any other intellectual 72381SN/A * property including but not limited to intellectual property relating 82381SN/A * to a hardware implementation of the functionality of the software 92381SN/A * licensed hereunder. You may use the software subject to the license 102381SN/A * terms below provided that you ensure that this notice is replicated 112381SN/A * unmodified and in its entirety in all distributions of the software, 122381SN/A * modified or unmodified, in source code or in binary form. 132381SN/A * 142381SN/A * Copyright (c) 2006 The Regents of The University of Michigan 152381SN/A * All rights reserved. 162381SN/A * 172381SN/A * Redistribution and use in source and binary forms, with or without 182381SN/A * modification, are permitted provided that the following conditions are 192381SN/A * met: redistributions of source code must retain the above copyright 202381SN/A * notice, this list of conditions and the following disclaimer; 212381SN/A * redistributions in binary form must reproduce the above copyright 222381SN/A * notice, this list of conditions and the following disclaimer in the 232381SN/A * documentation and/or other materials provided with the distribution; 242381SN/A * neither the name of the copyright holders nor the names of its 252381SN/A * contributors may be used to endorse or promote products derived from 262381SN/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 302665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312381SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322381SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332381SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342381SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352662Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362381SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372381SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382381SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392381SN/A * 402381SN/A * Authors: Ali Saidi 412392SN/A * Andreas Hansson 422980Sgblack@eecs.umich.edu * William Wang 432394SN/A */ 442812Srdreslin@umich.edu 452989Ssaidi@eecs.umich.edu/** 462394SN/A * @file 472394SN/A * Definition of a bus object. 482394SN/A */ 492394SN/A 502812Srdreslin@umich.edu#include "base/misc.hh" 512812Srdreslin@umich.edu#include "base/trace.hh" 522812Srdreslin@umich.edu#include "debug/Bus.hh" 532812Srdreslin@umich.edu#include "debug/BusAddrRanges.hh" 542812Srdreslin@umich.edu#include "debug/Drain.hh" 552812Srdreslin@umich.edu#include "mem/bus.hh" 562813Srdreslin@umich.edu 572813Srdreslin@umich.eduBaseBus::BaseBus(const BaseBusParams *p) 582813Srdreslin@umich.edu : MemObject(p), 593074Srdreslin@umich.edu headerCycles(p->header_cycles), width(p->width), 602382SN/A defaultPortID(InvalidPortID), 612381SN/A useDefaultRange(p->use_default_range), 622662Sstever@eecs.umich.edu blockSize(p->block_size) 632662Sstever@eecs.umich.edu{} 642662Sstever@eecs.umich.edu 652662Sstever@eecs.umich.eduBaseBus::~BaseBus() 662662Sstever@eecs.umich.edu{ 672381SN/A for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); 682641Sstever@eecs.umich.edu ++m) { 692381SN/A delete *m; 702813Srdreslin@umich.edu } 712813Srdreslin@umich.edu 722813Srdreslin@umich.edu for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); 732813Srdreslin@umich.edu ++s) { 742566SN/A delete *s; 752662Sstever@eecs.umich.edu } 762662Sstever@eecs.umich.edu} 772662Sstever@eecs.umich.edu 782662Sstever@eecs.umich.eduvoid 792662Sstever@eecs.umich.eduBaseBus::init() 802566SN/A{ 812566SN/A // determine the maximum peer block size, look at both the 822566SN/A // connected master and slave modules 832662Sstever@eecs.umich.edu uint32_t peer_block_size = 0; 842662Sstever@eecs.umich.edu 852566SN/A for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); 862662Sstever@eecs.umich.edu ++m) { 872662Sstever@eecs.umich.edu peer_block_size = std::max((*m)->peerBlockSize(), peer_block_size); 882566SN/A } 892662Sstever@eecs.umich.edu 902662Sstever@eecs.umich.edu for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 912566SN/A ++s) { 922566SN/A peer_block_size = std::max((*s)->peerBlockSize(), peer_block_size); 932662Sstever@eecs.umich.edu } 942662Sstever@eecs.umich.edu 952381SN/A // if the peers do not have a block size, use the default value 962381SN/A // set through the bus parameters 972662Sstever@eecs.umich.edu if (peer_block_size != 0) 982381SN/A blockSize = peer_block_size; 992381SN/A 1002662Sstever@eecs.umich.edu // check if the block size is a value known to work 1012662Sstever@eecs.umich.edu if (blockSize != 16 || blockSize != 32 || blockSize != 64 || 1022662Sstever@eecs.umich.edu blockSize != 128) 1032662Sstever@eecs.umich.edu warn_once("Block size is neither 16, 32, 64 or 128 bytes.\n"); 1042381SN/A} 1052381SN/A 1062662Sstever@eecs.umich.eduMasterPort & 1072662Sstever@eecs.umich.eduBaseBus::getMasterPort(const std::string &if_name, int idx) 1082662Sstever@eecs.umich.edu{ 1092662Sstever@eecs.umich.edu if (if_name == "master" && idx < masterPorts.size()) { 1102662Sstever@eecs.umich.edu // the master port index translates directly to the vector position 1112641Sstever@eecs.umich.edu return *masterPorts[idx]; 1122641Sstever@eecs.umich.edu } else if (if_name == "default") { 1132663Sstever@eecs.umich.edu return *masterPorts[defaultPortID]; 1142663Sstever@eecs.umich.edu } else { 1152662Sstever@eecs.umich.edu return MemObject::getMasterPort(if_name, idx); 1162641Sstever@eecs.umich.edu } 1172813Srdreslin@umich.edu} 1182641Sstever@eecs.umich.edu 1192641Sstever@eecs.umich.eduSlavePort & 1202641Sstever@eecs.umich.eduBaseBus::getSlavePort(const std::string &if_name, int idx) 1212811Srdreslin@umich.edu{ 1222811Srdreslin@umich.edu if (if_name == "slave" && idx < slavePorts.size()) { 1232811Srdreslin@umich.edu // the slave port index translates directly to the vector position 1243218Sgblack@eecs.umich.edu return *slavePorts[idx]; 1253218Sgblack@eecs.umich.edu } else { 1263218Sgblack@eecs.umich.edu return MemObject::getSlavePort(if_name, idx); 1273218Sgblack@eecs.umich.edu } 1283218Sgblack@eecs.umich.edu} 1293218Sgblack@eecs.umich.edu 1302662Sstever@eecs.umich.eduTick 1312662Sstever@eecs.umich.eduBaseBus::calcPacketTiming(PacketPtr pkt) 1322623SN/A{ 1332623SN/A // determine the current time rounded to the closest following 1342662Sstever@eecs.umich.edu // clock edge 1352641Sstever@eecs.umich.edu Tick now = nextCycle(); 1362641Sstever@eecs.umich.edu 1372662Sstever@eecs.umich.edu Tick headerTime = now + headerCycles * clock; 1382662Sstever@eecs.umich.edu 1392662Sstever@eecs.umich.edu // The packet will be sent. Figure out how long it occupies the bus, and 1402641Sstever@eecs.umich.edu // how much of that time is for the first "word", aka bus width. 1412641Sstever@eecs.umich.edu int numCycles = 0; 1422641Sstever@eecs.umich.edu if (pkt->hasData()) { 1432641Sstever@eecs.umich.edu // If a packet has data, it needs ceil(size/width) cycles to send it 1442641Sstever@eecs.umich.edu int dataSize = pkt->getSize(); 1452662Sstever@eecs.umich.edu numCycles += dataSize/width; 1462662Sstever@eecs.umich.edu if (dataSize % width) 1472662Sstever@eecs.umich.edu numCycles++; 1482662Sstever@eecs.umich.edu } 1492641Sstever@eecs.umich.edu 1502662Sstever@eecs.umich.edu // The first word will be delivered after the current tick, the delivery 1512662Sstever@eecs.umich.edu // of the address if any, and one bus cycle to deliver the data 1522662Sstever@eecs.umich.edu pkt->firstWordTime = headerTime + clock; 1532662Sstever@eecs.umich.edu 1542662Sstever@eecs.umich.edu pkt->finishTime = headerTime + numCycles * clock; 1552662Sstever@eecs.umich.edu 1562662Sstever@eecs.umich.edu return headerTime; 1572641Sstever@eecs.umich.edu} 1582641Sstever@eecs.umich.edu 1592641Sstever@eecs.umich.edutemplate <typename PortClass> 1602641Sstever@eecs.umich.eduBaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name, 1612641Sstever@eecs.umich.edu Tick _clock) : 1622662Sstever@eecs.umich.edu bus(_bus), _name(_name), state(IDLE), clock(_clock), drainEvent(NULL), 1632662Sstever@eecs.umich.edu releaseEvent(this) 1642662Sstever@eecs.umich.edu{ 1652641Sstever@eecs.umich.edu} 1662641Sstever@eecs.umich.edu 1672641Sstever@eecs.umich.edutemplate <typename PortClass> 1683158Sgblack@eecs.umich.eduvoid BaseBus::Layer<PortClass>::occupyLayer(Tick until) 1693158Sgblack@eecs.umich.edu{ 1702641Sstever@eecs.umich.edu // ensure the state is busy or in retry and never idle at this 1712641Sstever@eecs.umich.edu // point, as the bus should transition from idle as soon as it has 1722641Sstever@eecs.umich.edu // decided to forward the packet to prevent any follow-on calls to 1732641Sstever@eecs.umich.edu // sendTiming seeing an unoccupied bus 1742641Sstever@eecs.umich.edu assert(state != IDLE); 1752641Sstever@eecs.umich.edu 1762641Sstever@eecs.umich.edu // note that we do not change the bus state here, if we are going 1772641Sstever@eecs.umich.edu // from idle to busy it is handled by tryTiming, and if we 1782641Sstever@eecs.umich.edu // are in retry we should remain in retry such that 1792811Srdreslin@umich.edu // succeededTiming still sees the accurate state 1803156Sgblack@eecs.umich.edu 1813156Sgblack@eecs.umich.edu // until should never be 0 as express snoops never occupy the bus 1822641Sstever@eecs.umich.edu assert(until != 0); 1832641Sstever@eecs.umich.edu bus.schedule(releaseEvent, until); 1843158Sgblack@eecs.umich.edu 1853158Sgblack@eecs.umich.edu DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", 1863158Sgblack@eecs.umich.edu curTick(), until); 1873158Sgblack@eecs.umich.edu} 1882641Sstever@eecs.umich.edu 1892641Sstever@eecs.umich.edutemplate <typename PortClass> 1902641Sstever@eecs.umich.edubool 1912641Sstever@eecs.umich.eduBaseBus::Layer<PortClass>::tryTiming(PortClass* port) 1922813Srdreslin@umich.edu{ 1932641Sstever@eecs.umich.edu // first we see if the bus is busy, next we check if we are in a 1943158Sgblack@eecs.umich.edu // retry with a port other than the current one 1953158Sgblack@eecs.umich.edu if (state == BUSY || (state == RETRY && port != retryList.front())) { 1963158Sgblack@eecs.umich.edu // put the port at the end of the retry list 1972855Srdreslin@umich.edu retryList.push_back(port); 1983158Sgblack@eecs.umich.edu return false; 1992811Srdreslin@umich.edu } 2002811Srdreslin@umich.edu 2013156Sgblack@eecs.umich.edu // update the state which is shared for request, response and 2023158Sgblack@eecs.umich.edu // snoop responses, if we were idle we are now busy, if we are in 2033156Sgblack@eecs.umich.edu // a retry, then do not change 2043158Sgblack@eecs.umich.edu if (state == IDLE) 2052812Srdreslin@umich.edu state = BUSY; 2063158Sgblack@eecs.umich.edu 2073206Srdreslin@umich.edu return true; 2082855Srdreslin@umich.edu} 2093156Sgblack@eecs.umich.edu 2103158Sgblack@eecs.umich.edutemplate <typename PortClass> 2112641Sstever@eecs.umich.eduvoid 2122641Sstever@eecs.umich.eduBaseBus::Layer<PortClass>::succeededTiming(Tick busy_time) 2132662Sstever@eecs.umich.edu{ 2142662Sstever@eecs.umich.edu // if a retrying port succeeded, also take it off the retry list 2152641Sstever@eecs.umich.edu if (state == RETRY) { 2162381SN/A DPRINTF(BaseBus, "Remove retry from list %s\n", 2172811Srdreslin@umich.edu retryList.front()->name()); 2182811Srdreslin@umich.edu retryList.pop_front(); 2192811Srdreslin@umich.edu state = BUSY; 2202811Srdreslin@umich.edu } 2212811Srdreslin@umich.edu 2222811Srdreslin@umich.edu // we should either have gone from idle to busy in the 2232662Sstever@eecs.umich.edu // tryTiming test, or just gone from a retry to busy 2242381SN/A assert(state == BUSY); 2252381SN/A 2262641Sstever@eecs.umich.edu // occupy the bus accordingly 2272812Srdreslin@umich.edu occupyLayer(busy_time); 2282641Sstever@eecs.umich.edu} 2292641Sstever@eecs.umich.edu 2302641Sstever@eecs.umich.edutemplate <typename PortClass> 2313013Srdreslin@umich.eduvoid 2323156Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time) 2332812Srdreslin@umich.edu{ 2342813Srdreslin@umich.edu // if we are not in a retry, i.e. busy (but never idle), or we are 2352813Srdreslin@umich.edu // in a retry but not for the current port, then add the port at 2362814Srdreslin@umich.edu // the end of the retry list 2372814Srdreslin@umich.edu if (state != RETRY || port != retryList.front()) { 2383039Sstever@eecs.umich.edu retryList.push_back(port); 2392641Sstever@eecs.umich.edu } 2402662Sstever@eecs.umich.edu 2412641Sstever@eecs.umich.edu // even if we retried the current one and did not succeed, 2422641Sstever@eecs.umich.edu // we are no longer retrying but instead busy 2432641Sstever@eecs.umich.edu state = BUSY; 2442641Sstever@eecs.umich.edu 2452685Ssaidi@eecs.umich.edu // occupy the bus accordingly 2462641Sstever@eecs.umich.edu occupyLayer(busy_time); 2472641Sstever@eecs.umich.edu} 2482641Sstever@eecs.umich.edu 2492662Sstever@eecs.umich.edutemplate <typename PortClass> 2502641Sstever@eecs.umich.eduvoid 2512381SN/ABaseBus::Layer<PortClass>::releaseLayer() 2522381SN/A{ 2532641Sstever@eecs.umich.edu // releasing the bus means we should now be idle 2542641Sstever@eecs.umich.edu assert(state == BUSY); 2552381SN/A assert(!releaseEvent.scheduled()); 2562381SN/A 2572381SN/A // update the state 2582381SN/A state = IDLE; 2592641Sstever@eecs.umich.edu 2602549SN/A // bus is now idle, so if someone is waiting we can retry 2612663Sstever@eecs.umich.edu if (!retryList.empty()) { 2622663Sstever@eecs.umich.edu // note that we block (return false on recvTiming) both 2632883Srdreslin@umich.edu // because the bus is busy and because the destination is 2642813Srdreslin@umich.edu // busy, and in the latter case the bus may be released before 2652813Srdreslin@umich.edu // we see a retry from the destination 2662813Srdreslin@umich.edu retryWaiting(); 2672641Sstever@eecs.umich.edu } else if (drainEvent) { 2682662Sstever@eecs.umich.edu DPRINTF(Drain, "Bus done draining, processing drain event\n"); 2692662Sstever@eecs.umich.edu //If we weren't able to drain before, do it now. 2702662Sstever@eecs.umich.edu drainEvent->process(); 2712662Sstever@eecs.umich.edu // Clear the drain event once we're done with it. 2722641Sstever@eecs.umich.edu drainEvent = NULL; 2732566SN/A } 2742641Sstever@eecs.umich.edu} 2752663Sstever@eecs.umich.edu 2762814Srdreslin@umich.edutemplate <typename PortClass> 2772641Sstever@eecs.umich.eduvoid 2782662Sstever@eecs.umich.eduBaseBus::Layer<PortClass>::retryWaiting() 2792641Sstever@eecs.umich.edu{ 2802813Srdreslin@umich.edu // this should never be called with an empty retry list 2813018Srdreslin@umich.edu assert(!retryList.empty()); 2822813Srdreslin@umich.edu 2832813Srdreslin@umich.edu // we always go to retrying from idle 2842813Srdreslin@umich.edu assert(state == IDLE); 2852813Srdreslin@umich.edu 2862813Srdreslin@umich.edu // update the state which is shared for request, response and 2872813Srdreslin@umich.edu // snoop responses 2882813Srdreslin@umich.edu state = RETRY; 2892813Srdreslin@umich.edu 2902814Srdreslin@umich.edu // note that we might have blocked on the receiving port being 2912814Srdreslin@umich.edu // busy (rather than the bus itself) and now call retry before the 2922813Srdreslin@umich.edu // destination called retry on the bus 2932813Srdreslin@umich.edu retryList.front()->sendRetry(); 2942813Srdreslin@umich.edu 2952813Srdreslin@umich.edu // If the bus is still in the retry state, sendTiming wasn't 2963018Srdreslin@umich.edu // called in zero time (e.g. the cache does this) 2972641Sstever@eecs.umich.edu if (state == RETRY) { 2982549SN/A retryList.pop_front(); 2992662Sstever@eecs.umich.edu 3002566SN/A //Burn a cycle for the missed grant. 3012566SN/A 3022566SN/A // update the state which is shared for request, response and 3032662Sstever@eecs.umich.edu // snoop responses 3042662Sstever@eecs.umich.edu state = BUSY; 3052662Sstever@eecs.umich.edu 3062662Sstever@eecs.umich.edu // determine the current time rounded to the closest following 3072662Sstever@eecs.umich.edu // clock edge 3082662Sstever@eecs.umich.edu Tick now = bus.nextCycle(); 3092662Sstever@eecs.umich.edu 3102663Sstever@eecs.umich.edu occupyLayer(now + clock); 3112663Sstever@eecs.umich.edu } 3123018Srdreslin@umich.edu} 3132663Sstever@eecs.umich.edu 3142662Sstever@eecs.umich.edutemplate <typename PortClass> 3152662Sstever@eecs.umich.eduvoid 3162662Sstever@eecs.umich.eduBaseBus::Layer<PortClass>::recvRetry() 3172662Sstever@eecs.umich.edu{ 3182662Sstever@eecs.umich.edu // we got a retry from a peer that we tried to send something to 3192662Sstever@eecs.umich.edu // and failed, but we sent it on the account of someone else, and 3202662Sstever@eecs.umich.edu // that source port should be on our retry list, however if the 3212566SN/A // bus layer is released before this happens and the retry (from 3222662Sstever@eecs.umich.edu // the bus point of view) is successful then this no longer holds 3232662Sstever@eecs.umich.edu // and we could in fact have an empty retry list 3242662Sstever@eecs.umich.edu if (retryList.empty()) 3252662Sstever@eecs.umich.edu return; 3263135Srdreslin@umich.edu 3272662Sstever@eecs.umich.edu // if the bus layer is idle 3282662Sstever@eecs.umich.edu if (state == IDLE) { 3292662Sstever@eecs.umich.edu // note that we do not care who told us to retry at the moment, we 3302855Srdreslin@umich.edu // merely let the first one on the retry list go 3312662Sstever@eecs.umich.edu retryWaiting(); 3322855Srdreslin@umich.edu } 3332662Sstever@eecs.umich.edu} 3342662Sstever@eecs.umich.edu 3352662Sstever@eecs.umich.eduPortID 3362662Sstever@eecs.umich.eduBaseBus::findPort(Addr addr) 3372641Sstever@eecs.umich.edu{ 3382641Sstever@eecs.umich.edu /* An interval tree would be a better way to do this. --ali. */ 3393135Srdreslin@umich.edu PortID dest_id = checkPortCache(addr); 3403135Srdreslin@umich.edu if (dest_id != InvalidPortID) 3413135Srdreslin@umich.edu return dest_id; 3423135Srdreslin@umich.edu 3433135Srdreslin@umich.edu // Check normal port ranges 3443135Srdreslin@umich.edu PortMapConstIter i = portMap.find(RangeSize(addr,1)); 3453135Srdreslin@umich.edu if (i != portMap.end()) { 3463135Srdreslin@umich.edu dest_id = i->second; 3473135Srdreslin@umich.edu updatePortCache(dest_id, i->first.start, i->first.end); 3483135Srdreslin@umich.edu return dest_id; 3493135Srdreslin@umich.edu } 3503135Srdreslin@umich.edu 3512685Ssaidi@eecs.umich.edu // Check if this matches the default range 3522685Ssaidi@eecs.umich.edu if (useDefaultRange) { 3532685Ssaidi@eecs.umich.edu AddrRangeConstIter a_end = defaultRange.end(); 3542685Ssaidi@eecs.umich.edu for (AddrRangeConstIter i = defaultRange.begin(); i != a_end; i++) { 3552685Ssaidi@eecs.umich.edu if (*i == addr) { 3562685Ssaidi@eecs.umich.edu DPRINTF(BusAddrRanges, " found addr %#llx on default\n", 3572685Ssaidi@eecs.umich.edu addr); 3582685Ssaidi@eecs.umich.edu return defaultPortID; 3592685Ssaidi@eecs.umich.edu } 3602685Ssaidi@eecs.umich.edu } 3612566SN/A } else if (defaultPortID != InvalidPortID) { 3622566SN/A DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " 3632592SN/A "will use default port\n", addr); 3642566SN/A return defaultPortID; 3652566SN/A } 3662566SN/A 3672566SN/A // we should use the range for the default port and it did not 3682592SN/A // match, or the default port is not set 3692566SN/A fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 3702566SN/A name()); 3712566SN/A} 3722592SN/A 3732566SN/A/** Function called by the port when the bus is receiving a range change.*/ 3742566SN/Avoid 3752566SN/ABaseBus::recvRangeChange(PortID master_port_id) 3762592SN/A{ 3772566SN/A AddrRangeIter iter; 3782566SN/A 3792566SN/A if (inRecvRangeChange.count(master_port_id)) 3802592SN/A return; 3812566SN/A inRecvRangeChange.insert(master_port_id); 3822566SN/A 3832566SN/A DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", 3842592SN/A master_port_id); 3852566SN/A 3862566SN/A clearPortCache(); 3872566SN/A if (master_port_id == defaultPortID) { 3882592SN/A defaultRange.clear(); 3892566SN/A // Only try to update these ranges if the user set a default responder. 3902566SN/A if (useDefaultRange) { 3912592SN/A // get the address ranges of the connected slave port 3922568SN/A AddrRangeList ranges = 3932568SN/A masterPorts[master_port_id]->getAddrRanges(); 3942592SN/A for(iter = ranges.begin(); iter != ranges.end(); iter++) { 3952381SN/A defaultRange.push_back(*iter); 3962381SN/A DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 3972630SN/A iter->start, iter->end); 3982381SN/A } 399 } 400 } else { 401 402 assert(master_port_id < masterPorts.size() && master_port_id >= 0); 403 MasterPort *port = masterPorts[master_port_id]; 404 405 // Clean out any previously existent ids 406 for (PortMapIter portIter = portMap.begin(); 407 portIter != portMap.end(); ) { 408 if (portIter->second == master_port_id) 409 portMap.erase(portIter++); 410 else 411 portIter++; 412 } 413 414 // get the address ranges of the connected slave port 415 AddrRangeList ranges = port->getAddrRanges(); 416 417 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 418 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 419 iter->start, iter->end, master_port_id); 420 if (portMap.insert(*iter, master_port_id) == portMap.end()) { 421 PortID conflict_id = portMap.find(*iter)->second; 422 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 423 name(), 424 masterPorts[master_port_id]->getSlavePort().name(), 425 masterPorts[conflict_id]->getSlavePort().name()); 426 } 427 } 428 } 429 DPRINTF(BusAddrRanges, "port list has %d entries\n", portMap.size()); 430 431 // tell all our neighbouring master ports that our address range 432 // has changed 433 for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); 434 ++p) 435 (*p)->sendRangeChange(); 436 437 inRecvRangeChange.erase(master_port_id); 438} 439 440AddrRangeList 441BaseBus::getAddrRanges() const 442{ 443 AddrRangeList ranges; 444 445 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 446 447 for (AddrRangeConstIter dflt_iter = defaultRange.begin(); 448 dflt_iter != defaultRange.end(); dflt_iter++) { 449 ranges.push_back(*dflt_iter); 450 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 451 dflt_iter->end); 452 } 453 for (PortMapConstIter portIter = portMap.begin(); 454 portIter != portMap.end(); portIter++) { 455 bool subset = false; 456 for (AddrRangeConstIter dflt_iter = defaultRange.begin(); 457 dflt_iter != defaultRange.end(); dflt_iter++) { 458 if ((portIter->first.start < dflt_iter->start && 459 portIter->first.end >= dflt_iter->start) || 460 (portIter->first.start < dflt_iter->end && 461 portIter->first.end >= dflt_iter->end)) 462 fatal("Devices can not set ranges that itersect the default set\ 463 but are not a subset of the default set.\n"); 464 if (portIter->first.start >= dflt_iter->start && 465 portIter->first.end <= dflt_iter->end) { 466 subset = true; 467 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 468 portIter->first.start, portIter->first.end); 469 } 470 } 471 if (!subset) { 472 ranges.push_back(portIter->first); 473 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 474 portIter->first.start, portIter->first.end); 475 } 476 } 477 478 return ranges; 479} 480 481unsigned 482BaseBus::deviceBlockSize() const 483{ 484 return blockSize; 485} 486 487template <typename PortClass> 488unsigned int 489BaseBus::Layer<PortClass>::drain(Event * de) 490{ 491 //We should check that we're not "doing" anything, and that noone is 492 //waiting. We might be idle but have someone waiting if the device we 493 //contacted for a retry didn't actually retry. 494 if (!retryList.empty() || state != IDLE) { 495 DPRINTF(Drain, "Bus not drained\n"); 496 drainEvent = de; 497 return 1; 498 } 499 return 0; 500} 501 502/** 503 * Bus layer template instantiations. Could be removed with _impl.hh 504 * file, but since there are only two given options (MasterPort and 505 * SlavePort) it seems a bit excessive at this point. 506 */ 507template class BaseBus::Layer<SlavePort>; 508template class BaseBus::Layer<MasterPort>; 509