xbar.cc revision 9407
12568SN/A/* 210325Sgeoffrey.blake@arm.com * Copyright (c) 2011-2012 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 157636Ssteve.reinhardt@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 bus object. 482568SN/A */ 492568SN/A 503260Ssaidi@eecs.umich.edu#include "base/misc.hh" 518229Snate@binkert.org#include "base/trace.hh" 523260Ssaidi@eecs.umich.edu#include "debug/Bus.hh" 538229Snate@binkert.org#include "debug/BusAddrRanges.hh" 545314Sstever@gmail.com#include "debug/Drain.hh" 552590SN/A#include "mem/bus.hh" 563348Sbinkertn@umich.edu 572568SN/ABaseBus::BaseBus(const BaseBusParams *p) 582568SN/A : MemObject(p), 595735Snate@binkert.org headerCycles(p->header_cycles), width(p->width), 605735Snate@binkert.org gotAddrRanges(p->port_default_connection_count + 614022Sstever@eecs.umich.edu p->port_master_connection_count, false), 624022Sstever@eecs.umich.edu gotAllAddrRanges(false), defaultPortID(InvalidPortID), 634022Sstever@eecs.umich.edu useDefaultRange(p->use_default_range), 644022Sstever@eecs.umich.edu blockSize(p->block_size) 654022Sstever@eecs.umich.edu{} 664022Sstever@eecs.umich.edu 674022Sstever@eecs.umich.eduBaseBus::~BaseBus() 682641Sstever@eecs.umich.edu{ 694022Sstever@eecs.umich.edu for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); 704022Sstever@eecs.umich.edu ++m) { 712641Sstever@eecs.umich.edu delete *m; 724022Sstever@eecs.umich.edu } 734022Sstever@eecs.umich.edu 744022Sstever@eecs.umich.edu for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); 754022Sstever@eecs.umich.edu ++s) { 764473Sstever@eecs.umich.edu delete *s; 774473Sstever@eecs.umich.edu } 785319Sstever@gmail.com} 795319Sstever@gmail.com 805319Sstever@gmail.comvoid 814022Sstever@eecs.umich.eduBaseBus::init() 824626Sstever@eecs.umich.edu{ 834022Sstever@eecs.umich.edu // determine the maximum peer block size, look at both the 844022Sstever@eecs.umich.edu // connected master and slave modules 854626Sstever@eecs.umich.edu uint32_t peer_block_size = 0; 864022Sstever@eecs.umich.edu 874628Sstever@eecs.umich.edu for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); 884628Sstever@eecs.umich.edu ++m) { 894022Sstever@eecs.umich.edu peer_block_size = std::max((*m)->peerBlockSize(), peer_block_size); 904022Sstever@eecs.umich.edu } 914022Sstever@eecs.umich.edu 924022Sstever@eecs.umich.edu for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 934022Sstever@eecs.umich.edu ++s) { 944022Sstever@eecs.umich.edu peer_block_size = std::max((*s)->peerBlockSize(), peer_block_size); 954022Sstever@eecs.umich.edu } 964022Sstever@eecs.umich.edu 974022Sstever@eecs.umich.edu // if the peers do not have a block size, use the default value 984022Sstever@eecs.umich.edu // set through the bus parameters 994022Sstever@eecs.umich.edu if (peer_block_size != 0) 1004022Sstever@eecs.umich.edu blockSize = peer_block_size; 10110345SCurtis.Dunham@arm.com 1024626Sstever@eecs.umich.edu // check if the block size is a value known to work 1034626Sstever@eecs.umich.edu if (!(blockSize == 16 || blockSize == 32 || blockSize == 64 || 1044022Sstever@eecs.umich.edu blockSize == 128)) 10510345SCurtis.Dunham@arm.com warn_once("Block size is neither 16, 32, 64 or 128 bytes.\n"); 1065319Sstever@gmail.com} 1074022Sstever@eecs.umich.edu 1084022Sstever@eecs.umich.eduBaseMasterPort & 1097465Ssteve.reinhardt@amd.comBaseBus::getMasterPort(const std::string &if_name, PortID idx) 1104628Sstever@eecs.umich.edu{ 1117465Ssteve.reinhardt@amd.com if (if_name == "master" && idx < masterPorts.size()) { 1127465Ssteve.reinhardt@amd.com // the master port index translates directly to the vector position 1137465Ssteve.reinhardt@amd.com return *masterPorts[idx]; 1147465Ssteve.reinhardt@amd.com } else if (if_name == "default") { 1154628Sstever@eecs.umich.edu return *masterPorts[defaultPortID]; 1167465Ssteve.reinhardt@amd.com } else { 1177465Ssteve.reinhardt@amd.com return MemObject::getMasterPort(if_name, idx); 11810325Sgeoffrey.blake@arm.com } 11910325Sgeoffrey.blake@arm.com} 12010325Sgeoffrey.blake@arm.com 1217465Ssteve.reinhardt@amd.comBaseSlavePort & 12210325Sgeoffrey.blake@arm.comBaseBus::getSlavePort(const std::string &if_name, PortID idx) 12310325Sgeoffrey.blake@arm.com{ 12410325Sgeoffrey.blake@arm.com if (if_name == "slave" && idx < slavePorts.size()) { 1257465Ssteve.reinhardt@amd.com // the slave port index translates directly to the vector position 1264022Sstever@eecs.umich.edu return *slavePorts[idx]; 1274626Sstever@eecs.umich.edu } else { 1284022Sstever@eecs.umich.edu return MemObject::getSlavePort(if_name, idx); 1294022Sstever@eecs.umich.edu } 1305319Sstever@gmail.com} 1314040Ssaidi@eecs.umich.edu 1325507Sstever@gmail.comTick 1335507Sstever@gmail.comBaseBus::calcPacketTiming(PacketPtr pkt) 1346076Sgblack@eecs.umich.edu{ 1355507Sstever@gmail.com // determine the current time rounded to the closest following 1364626Sstever@eecs.umich.edu // clock edge 1376076Sgblack@eecs.umich.edu Tick now = nextCycle(); 1384626Sstever@eecs.umich.edu 1394626Sstever@eecs.umich.edu Tick headerTime = now + headerCycles * clock; 14010325Sgeoffrey.blake@arm.com 1417669Ssteve.reinhardt@amd.com // The packet will be sent. Figure out how long it occupies the bus, and 1427669Ssteve.reinhardt@amd.com // how much of that time is for the first "word", aka bus width. 1437669Ssteve.reinhardt@amd.com int numCycles = 0; 1444626Sstever@eecs.umich.edu if (pkt->hasData()) { 1456076Sgblack@eecs.umich.edu // If a packet has data, it needs ceil(size/width) cycles to send it 1464626Sstever@eecs.umich.edu int dataSize = pkt->getSize(); 1474040Ssaidi@eecs.umich.edu numCycles += dataSize/width; 1484626Sstever@eecs.umich.edu if (dataSize % width) 1494040Ssaidi@eecs.umich.edu numCycles++; 1504040Ssaidi@eecs.umich.edu } 1514626Sstever@eecs.umich.edu 1524870Sstever@eecs.umich.edu // The first word will be delivered after the current tick, the delivery 1535650Sgblack@eecs.umich.edu // of the address if any, and one bus cycle to deliver the data 1545650Sgblack@eecs.umich.edu pkt->firstWordTime = headerTime + clock; 1556063Sgblack@eecs.umich.edu 1565650Sgblack@eecs.umich.edu pkt->finishTime = headerTime + numCycles * clock; 1576063Sgblack@eecs.umich.edu 1584870Sstever@eecs.umich.edu return headerTime; 1594986Ssaidi@eecs.umich.edu} 1604870Sstever@eecs.umich.edu 1615314Sstever@gmail.comtemplate <typename PortClass> 1628436SBrad.Beckmann@amd.comBaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name, 1638436SBrad.Beckmann@amd.com Tick _clock) : 1648436SBrad.Beckmann@amd.com Drainable(), 1658436SBrad.Beckmann@amd.com bus(_bus), _name(_name), state(IDLE), clock(_clock), drainManager(NULL), 1665314Sstever@gmail.com releaseEvent(this) 1678184Ssomayeh@cs.wisc.edu{ 1688184Ssomayeh@cs.wisc.edu} 1698436SBrad.Beckmann@amd.com 1708716Snilay@cs.wisc.edutemplate <typename PortClass> 1718716Snilay@cs.wisc.eduvoid BaseBus::Layer<PortClass>::occupyLayer(Tick until) 1728716Snilay@cs.wisc.edu{ 1734022Sstever@eecs.umich.edu // ensure the state is busy or in retry and never idle at this 1742592SN/A // point, as the bus should transition from idle as soon as it has 1753607Srdreslin@umich.edu // decided to forward the packet to prevent any follow-on calls to 17610028SGiacomo.Gabrielli@arm.com // sendTiming seeing an unoccupied bus 17710028SGiacomo.Gabrielli@arm.com assert(state != IDLE); 1782641Sstever@eecs.umich.edu 1794626Sstever@eecs.umich.edu // note that we do not change the bus state here, if we are going 1804626Sstever@eecs.umich.edu // from idle to busy it is handled by tryTiming, and if we 1814626Sstever@eecs.umich.edu // are in retry we should remain in retry such that 1824626Sstever@eecs.umich.edu // succeededTiming still sees the accurate state 1833260Ssaidi@eecs.umich.edu 18410028SGiacomo.Gabrielli@arm.com // until should never be 0 as express snoops never occupy the bus 18510028SGiacomo.Gabrielli@arm.com assert(until != 0); 1864626Sstever@eecs.umich.edu bus.schedule(releaseEvent, until); 1874626Sstever@eecs.umich.edu 1884626Sstever@eecs.umich.edu DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", 1893260Ssaidi@eecs.umich.edu curTick(), until); 1905314Sstever@gmail.com} 1915314Sstever@gmail.com 19210376Sandreas.hansson@arm.comtemplate <typename PortClass> 1935314Sstever@gmail.combool 1945314Sstever@gmail.comBaseBus::Layer<PortClass>::tryTiming(PortClass* port) 1955314Sstever@gmail.com{ 1965314Sstever@gmail.com // first we see if the bus is busy, next we check if we are in a 1975314Sstever@gmail.com // retry with a port other than the current one 1985314Sstever@gmail.com if (state == BUSY || (state == RETRY && port != retryList.front())) { 1995314Sstever@gmail.com // put the port at the end of the retry list 2005314Sstever@gmail.com retryList.push_back(port); 2014626Sstever@eecs.umich.edu return false; 2024626Sstever@eecs.umich.edu } 2034626Sstever@eecs.umich.edu 2043260Ssaidi@eecs.umich.edu // update the state which is shared for request, response and 2054626Sstever@eecs.umich.edu // snoop responses, if we were idle we are now busy, if we are in 2064626Sstever@eecs.umich.edu // a retry, then do not change 2074626Sstever@eecs.umich.edu if (state == IDLE) 2085735Snate@binkert.org state = BUSY; 2094626Sstever@eecs.umich.edu 2103260Ssaidi@eecs.umich.edu return true; 2118668Sgeoffrey.blake@arm.com} 2128668Sgeoffrey.blake@arm.com 2138668Sgeoffrey.blake@arm.comtemplate <typename PortClass> 2148668Sgeoffrey.blake@arm.comvoid 2158668Sgeoffrey.blake@arm.comBaseBus::Layer<PortClass>::succeededTiming(Tick busy_time) 2168668Sgeoffrey.blake@arm.com{ 2178668Sgeoffrey.blake@arm.com // if a retrying port succeeded, also take it off the retry list 2188668Sgeoffrey.blake@arm.com if (state == RETRY) { 2198668Sgeoffrey.blake@arm.com DPRINTF(BaseBus, "Remove retry from list %s\n", 2208668Sgeoffrey.blake@arm.com retryList.front()->name()); 2218668Sgeoffrey.blake@arm.com retryList.pop_front(); 2228668Sgeoffrey.blake@arm.com state = BUSY; 2238668Sgeoffrey.blake@arm.com } 2248668Sgeoffrey.blake@arm.com 2258668Sgeoffrey.blake@arm.com // we should either have gone from idle to busy in the 2268668Sgeoffrey.blake@arm.com // tryTiming test, or just gone from a retry to busy 2278668Sgeoffrey.blake@arm.com assert(state == BUSY); 2288668Sgeoffrey.blake@arm.com 2298668Sgeoffrey.blake@arm.com // occupy the bus accordingly 2308668Sgeoffrey.blake@arm.com occupyLayer(busy_time); 2318668Sgeoffrey.blake@arm.com} 2328668Sgeoffrey.blake@arm.com 2338668Sgeoffrey.blake@arm.comtemplate <typename PortClass> 2348668Sgeoffrey.blake@arm.comvoid 2358668Sgeoffrey.blake@arm.comBaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time) 2368668Sgeoffrey.blake@arm.com{ 2378668Sgeoffrey.blake@arm.com // if we are not in a retry, i.e. busy (but never idle), or we are 2388668Sgeoffrey.blake@arm.com // in a retry but not for the current port, then add the port at 2398668Sgeoffrey.blake@arm.com // the end of the retry list 2408668Sgeoffrey.blake@arm.com if (state != RETRY || port != retryList.front()) { 2418668Sgeoffrey.blake@arm.com retryList.push_back(port); 2428668Sgeoffrey.blake@arm.com } 2438668Sgeoffrey.blake@arm.com 2448668Sgeoffrey.blake@arm.com // even if we retried the current one and did not succeed, 2458668Sgeoffrey.blake@arm.com // we are no longer retrying but instead busy 2468668Sgeoffrey.blake@arm.com state = BUSY; 2478668Sgeoffrey.blake@arm.com 2488668Sgeoffrey.blake@arm.com // occupy the bus accordingly 2498668Sgeoffrey.blake@arm.com occupyLayer(busy_time); 2508668Sgeoffrey.blake@arm.com} 2518668Sgeoffrey.blake@arm.com 2528668Sgeoffrey.blake@arm.comtemplate <typename PortClass> 2538668Sgeoffrey.blake@arm.comvoid 2548668Sgeoffrey.blake@arm.comBaseBus::Layer<PortClass>::releaseLayer() 2558668Sgeoffrey.blake@arm.com{ 2568668Sgeoffrey.blake@arm.com // releasing the bus means we should now be idle 2578668Sgeoffrey.blake@arm.com assert(state == BUSY); 2588668Sgeoffrey.blake@arm.com assert(!releaseEvent.scheduled()); 2598668Sgeoffrey.blake@arm.com 2608668Sgeoffrey.blake@arm.com // update the state 2618668Sgeoffrey.blake@arm.com state = IDLE; 2628668Sgeoffrey.blake@arm.com 2638668Sgeoffrey.blake@arm.com // bus is now idle, so if someone is waiting we can retry 2648668Sgeoffrey.blake@arm.com if (!retryList.empty()) { 2658668Sgeoffrey.blake@arm.com // note that we block (return false on recvTiming) both 2668668Sgeoffrey.blake@arm.com // because the bus is busy and because the destination is 2678668Sgeoffrey.blake@arm.com // busy, and in the latter case the bus may be released before 2688668Sgeoffrey.blake@arm.com // we see a retry from the destination 2698668Sgeoffrey.blake@arm.com retryWaiting(); 2708668Sgeoffrey.blake@arm.com } else if (drainManager) { 2718668Sgeoffrey.blake@arm.com DPRINTF(Drain, "Bus done draining, signaling drain manager\n"); 2728668Sgeoffrey.blake@arm.com //If we weren't able to drain before, do it now. 2738668Sgeoffrey.blake@arm.com drainManager->signalDrainDone(); 2748668Sgeoffrey.blake@arm.com // Clear the drain event once we're done with it. 2758668Sgeoffrey.blake@arm.com drainManager = NULL; 2768668Sgeoffrey.blake@arm.com } 2778668Sgeoffrey.blake@arm.com} 2788668Sgeoffrey.blake@arm.com 2798668Sgeoffrey.blake@arm.comtemplate <typename PortClass> 2808668Sgeoffrey.blake@arm.comvoid 2818668Sgeoffrey.blake@arm.comBaseBus::Layer<PortClass>::retryWaiting() 2828668Sgeoffrey.blake@arm.com{ 2838668Sgeoffrey.blake@arm.com // this should never be called with an empty retry list 2848668Sgeoffrey.blake@arm.com assert(!retryList.empty()); 2858668Sgeoffrey.blake@arm.com 2868668Sgeoffrey.blake@arm.com // we always go to retrying from idle 2878668Sgeoffrey.blake@arm.com assert(state == IDLE); 2888668Sgeoffrey.blake@arm.com 2898668Sgeoffrey.blake@arm.com // update the state which is shared for request, response and 2908668Sgeoffrey.blake@arm.com // snoop responses 2918668Sgeoffrey.blake@arm.com state = RETRY; 2928668Sgeoffrey.blake@arm.com 2938692Ssaidi@eecs.umich.edu // note that we might have blocked on the receiving port being 2948668Sgeoffrey.blake@arm.com // busy (rather than the bus itself) and now call retry before the 2958668Sgeoffrey.blake@arm.com // destination called retry on the bus 2968668Sgeoffrey.blake@arm.com retryList.front()->sendRetry(); 2978668Sgeoffrey.blake@arm.com 2988668Sgeoffrey.blake@arm.com // If the bus is still in the retry state, sendTiming wasn't 2998668Sgeoffrey.blake@arm.com // called in zero time (e.g. the cache does this) 3008668Sgeoffrey.blake@arm.com if (state == RETRY) { 3018668Sgeoffrey.blake@arm.com retryList.pop_front(); 3028668Sgeoffrey.blake@arm.com 3033260Ssaidi@eecs.umich.edu //Burn a cycle for the missed grant. 3044626Sstever@eecs.umich.edu 3054626Sstever@eecs.umich.edu // update the state which is shared for request, response and 3065735Snate@binkert.org // snoop responses 3075735Snate@binkert.org state = BUSY; 3085735Snate@binkert.org 3095735Snate@binkert.org // determine the current time rounded to the closest following 3105735Snate@binkert.org // clock edge 3115735Snate@binkert.org Tick now = bus.nextCycle(); 3123260Ssaidi@eecs.umich.edu 3135314Sstever@gmail.com occupyLayer(now + clock); 3144626Sstever@eecs.umich.edu } 3155314Sstever@gmail.com} 3165314Sstever@gmail.com 3175314Sstever@gmail.comtemplate <typename PortClass> 3185314Sstever@gmail.comvoid 3192641Sstever@eecs.umich.eduBaseBus::Layer<PortClass>::recvRetry() 3203260Ssaidi@eecs.umich.edu{ 3215314Sstever@gmail.com // we got a retry from a peer that we tried to send something to 3229542Sandreas.hansson@arm.com // and failed, but we sent it on the account of someone else, and 3239542Sandreas.hansson@arm.com // that source port should be on our retry list, however if the 3249542Sandreas.hansson@arm.com // bus layer is released before this happens and the retry (from 3259542Sandreas.hansson@arm.com // the bus point of view) is successful then this no longer holds 3269542Sandreas.hansson@arm.com // and we could in fact have an empty retry list 3279542Sandreas.hansson@arm.com if (retryList.empty()) 3289542Sandreas.hansson@arm.com return; 3299542Sandreas.hansson@arm.com 3309542Sandreas.hansson@arm.com // if the bus layer is idle 3319542Sandreas.hansson@arm.com if (state == IDLE) { 3329542Sandreas.hansson@arm.com // note that we do not care who told us to retry at the moment, we 3339542Sandreas.hansson@arm.com // merely let the first one on the retry list go 3349542Sandreas.hansson@arm.com retryWaiting(); 3359542Sandreas.hansson@arm.com } 3369542Sandreas.hansson@arm.com} 3379542Sandreas.hansson@arm.com 3389542Sandreas.hansson@arm.comPortID 3399542Sandreas.hansson@arm.comBaseBus::findPort(Addr addr) 3405735Snate@binkert.org{ 3413260Ssaidi@eecs.umich.edu // we should never see any address lookups before we've got the 3425314Sstever@gmail.com // ranges of all connected slave modules 3435314Sstever@gmail.com assert(gotAllAddrRanges); 3443260Ssaidi@eecs.umich.edu 3453260Ssaidi@eecs.umich.edu // Check the cache 3469663Suri.wiener@arm.com PortID dest_id = checkPortCache(addr); 3479663Suri.wiener@arm.com if (dest_id != InvalidPortID) 3489663Suri.wiener@arm.com return dest_id; 3499663Suri.wiener@arm.com 3509663Suri.wiener@arm.com // Check the address map interval tree 3519663Suri.wiener@arm.com PortMapConstIter i = portMap.find(addr); 3529663Suri.wiener@arm.com if (i != portMap.end()) { 3535735Snate@binkert.org dest_id = i->second; 3545735Snate@binkert.org updatePortCache(dest_id, i->first); 3555314Sstever@gmail.com return dest_id; 3565314Sstever@gmail.com } 3575314Sstever@gmail.com 3585314Sstever@gmail.com // Check if this matches the default range 3595314Sstever@gmail.com if (useDefaultRange) { 3605314Sstever@gmail.com if (defaultRange.contains(addr)) { 3615314Sstever@gmail.com DPRINTF(BusAddrRanges, " found addr %#llx on default\n", 3625314Sstever@gmail.com addr); 3635314Sstever@gmail.com return defaultPortID; 3645314Sstever@gmail.com } 3655314Sstever@gmail.com } else if (defaultPortID != InvalidPortID) { 3665314Sstever@gmail.com DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " 3675735Snate@binkert.org "will use default port\n", addr); 3685314Sstever@gmail.com return defaultPortID; 3695314Sstever@gmail.com } 3705314Sstever@gmail.com 3715314Sstever@gmail.com // we should use the range for the default port and it did not 3725314Sstever@gmail.com // match, or the default port is not set 3735735Snate@binkert.org fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 3745314Sstever@gmail.com name()); 3755314Sstever@gmail.com} 3765735Snate@binkert.org 3775314Sstever@gmail.com/** Function called by the port when the bus is receiving a range change.*/ 3785314Sstever@gmail.comvoid 3795314Sstever@gmail.comBaseBus::recvRangeChange(PortID master_port_id) 3805314Sstever@gmail.com{ 3815314Sstever@gmail.com DPRINTF(BusAddrRanges, "Received range change from slave port %s\n", 3825314Sstever@gmail.com masterPorts[master_port_id]->getSlavePort().name()); 3835314Sstever@gmail.com 3845314Sstever@gmail.com // remember that we got a range from this master port and thus the 3855314Sstever@gmail.com // connected slave module 3865314Sstever@gmail.com gotAddrRanges[master_port_id] = true; 3875314Sstever@gmail.com 3885314Sstever@gmail.com // update the global flag 3895314Sstever@gmail.com if (!gotAllAddrRanges) { 3905314Sstever@gmail.com // take a logical AND of all the ports and see if we got 3915314Sstever@gmail.com // ranges from everyone 3925314Sstever@gmail.com gotAllAddrRanges = true; 3935314Sstever@gmail.com std::vector<bool>::const_iterator r = gotAddrRanges.begin(); 3945314Sstever@gmail.com while (gotAllAddrRanges && r != gotAddrRanges.end()) { 3955314Sstever@gmail.com gotAllAddrRanges &= *r++; 3965314Sstever@gmail.com } 3975314Sstever@gmail.com if (gotAllAddrRanges) 3985314Sstever@gmail.com DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n"); 3995314Sstever@gmail.com } 4005314Sstever@gmail.com 4015314Sstever@gmail.com // note that we could get the range from the default port at any 4025314Sstever@gmail.com // point in time, and we cannot assume that the default range is 4035314Sstever@gmail.com // set before the other ones are, so we do additional checks once 4045314Sstever@gmail.com // all ranges are provided 4055314Sstever@gmail.com if (master_port_id == defaultPortID) { 4065314Sstever@gmail.com // only update if we are indeed checking ranges for the 4075314Sstever@gmail.com // default port since the port might not have a valid range 4085314Sstever@gmail.com // otherwise 4095314Sstever@gmail.com if (useDefaultRange) { 4105314Sstever@gmail.com AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 4115314Sstever@gmail.com 412 if (ranges.size() != 1) 413 fatal("Bus %s may only have a single default range", 414 name()); 415 416 defaultRange = ranges.front(); 417 } 418 } else { 419 // the ports are allowed to update their address ranges 420 // dynamically, so remove any existing entries 421 if (gotAddrRanges[master_port_id]) { 422 for (PortMapIter p = portMap.begin(); p != portMap.end(); ) { 423 if (p->second == master_port_id) 424 // erasing invalidates the iterator, so advance it 425 // before the deletion takes place 426 portMap.erase(p++); 427 else 428 p++; 429 } 430 } 431 432 AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 433 434 for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) { 435 DPRINTF(BusAddrRanges, "Adding range %s for id %d\n", 436 r->to_string(), master_port_id); 437 if (portMap.insert(*r, master_port_id) == portMap.end()) { 438 PortID conflict_id = portMap.find(*r)->second; 439 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 440 name(), 441 masterPorts[master_port_id]->getSlavePort().name(), 442 masterPorts[conflict_id]->getSlavePort().name()); 443 } 444 } 445 } 446 447 // if we have received ranges from all our neighbouring slave 448 // modules, go ahead and tell our connected master modules in 449 // turn, this effectively assumes a tree structure of the system 450 if (gotAllAddrRanges) { 451 // also check that no range partially overlaps with the 452 // default range, this has to be done after all ranges are set 453 // as there are no guarantees for when the default range is 454 // update with respect to the other ones 455 if (useDefaultRange) { 456 for (PortID port_id = 0; port_id < masterPorts.size(); ++port_id) { 457 if (port_id == defaultPortID) { 458 if (!gotAddrRanges[port_id]) 459 fatal("Bus %s uses default range, but none provided", 460 name()); 461 } else { 462 AddrRangeList ranges = 463 masterPorts[port_id]->getAddrRanges(); 464 465 for (AddrRangeConstIter r = ranges.begin(); 466 r != ranges.end(); ++r) { 467 // see if the new range is partially 468 // overlapping the default range 469 if (r->intersects(defaultRange) && 470 !r->isSubset(defaultRange)) 471 fatal("Range %s intersects the " \ 472 "default range of %s but is not a " \ 473 "subset\n", r->to_string(), name()); 474 } 475 } 476 } 477 } 478 479 // tell all our neighbouring master ports that our address 480 // ranges have changed 481 for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 482 ++s) 483 (*s)->sendRangeChange(); 484 } 485 486 clearPortCache(); 487} 488 489AddrRangeList 490BaseBus::getAddrRanges() const 491{ 492 // we should never be asked without first having sent a range 493 // change, and the latter is only done once we have all the ranges 494 // of the connected devices 495 assert(gotAllAddrRanges); 496 497 // at the moment, this never happens, as there are no cycles in 498 // the range queries and no devices on the master side of a bus 499 // (CPU, cache, bridge etc) actually care about the ranges of the 500 // ports they are connected to 501 502 DPRINTF(BusAddrRanges, "Received address range request, returning:\n"); 503 504 // start out with the default range 505 AddrRangeList ranges; 506 if (useDefaultRange) { 507 ranges.push_back(defaultRange); 508 DPRINTF(BusAddrRanges, " -- Default %s\n", defaultRange.to_string()); 509 } 510 511 // add any range that is not a subset of the default range 512 for (PortMapConstIter p = portMap.begin(); p != portMap.end(); ++p) { 513 if (useDefaultRange && p->first.isSubset(defaultRange)) { 514 DPRINTF(BusAddrRanges, " -- %s is a subset of default\n", 515 p->first.to_string()); 516 } else { 517 ranges.push_back(p->first); 518 DPRINTF(BusAddrRanges, " -- %s\n", p->first.to_string()); 519 } 520 } 521 522 return ranges; 523} 524 525unsigned 526BaseBus::deviceBlockSize() const 527{ 528 return blockSize; 529} 530 531template <typename PortClass> 532unsigned int 533BaseBus::Layer<PortClass>::drain(DrainManager *dm) 534{ 535 //We should check that we're not "doing" anything, and that noone is 536 //waiting. We might be idle but have someone waiting if the device we 537 //contacted for a retry didn't actually retry. 538 if (!retryList.empty() || state != IDLE) { 539 DPRINTF(Drain, "Bus not drained\n"); 540 drainManager = dm; 541 return 1; 542 } 543 return 0; 544} 545 546/** 547 * Bus layer template instantiations. Could be removed with _impl.hh 548 * file, but since there are only two given options (MasterPort and 549 * SlavePort) it seems a bit excessive at this point. 550 */ 551template class BaseBus::Layer<SlavePort>; 552template class BaseBus::Layer<MasterPort>; 553