xbar.cc revision 9279
12810Srdreslin@umich.edu/* 211051Sandreas.hansson@arm.com * Copyright (c) 2011-2012 ARM Limited 311051Sandreas.hansson@arm.com * All rights reserved 411051Sandreas.hansson@arm.com * 511051Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall 611051Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual 711051Sandreas.hansson@arm.com * property including but not limited to intellectual property relating 811051Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software 911051Sandreas.hansson@arm.com * licensed hereunder. You may use the software subject to the license 1011051Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated 1111051Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software, 1211051Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form. 1311051Sandreas.hansson@arm.com * 1411051Sandreas.hansson@arm.com * Copyright (c) 2006 The Regents of The University of Michigan 1511051Sandreas.hansson@arm.com * All rights reserved. 162810Srdreslin@umich.edu * 172810Srdreslin@umich.edu * Redistribution and use in source and binary forms, with or without 182810Srdreslin@umich.edu * modification, are permitted provided that the following conditions are 192810Srdreslin@umich.edu * met: redistributions of source code must retain the above copyright 202810Srdreslin@umich.edu * notice, this list of conditions and the following disclaimer; 212810Srdreslin@umich.edu * redistributions in binary form must reproduce the above copyright 222810Srdreslin@umich.edu * notice, this list of conditions and the following disclaimer in the 232810Srdreslin@umich.edu * documentation and/or other materials provided with the distribution; 242810Srdreslin@umich.edu * neither the name of the copyright holders nor the names of its 252810Srdreslin@umich.edu * contributors may be used to endorse or promote products derived from 262810Srdreslin@umich.edu * this software without specific prior written permission. 272810Srdreslin@umich.edu * 282810Srdreslin@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292810Srdreslin@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302810Srdreslin@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312810Srdreslin@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322810Srdreslin@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332810Srdreslin@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342810Srdreslin@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352810Srdreslin@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362810Srdreslin@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372810Srdreslin@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382810Srdreslin@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392810Srdreslin@umich.edu * 402810Srdreslin@umich.edu * Authors: Ali Saidi 412810Srdreslin@umich.edu * Andreas Hansson 4211051Sandreas.hansson@arm.com * William Wang 4311051Sandreas.hansson@arm.com */ 442810Srdreslin@umich.edu 4511051Sandreas.hansson@arm.com/** 4611051Sandreas.hansson@arm.com * @file 472810Srdreslin@umich.edu * Definition of a bus object. 482810Srdreslin@umich.edu */ 492810Srdreslin@umich.edu 502810Srdreslin@umich.edu#include "base/misc.hh" 5111051Sandreas.hansson@arm.com#include "base/trace.hh" 522810Srdreslin@umich.edu#include "debug/Bus.hh" 532810Srdreslin@umich.edu#include "debug/BusAddrRanges.hh" 5411051Sandreas.hansson@arm.com#include "debug/Drain.hh" 552810Srdreslin@umich.edu#include "mem/bus.hh" 5611051Sandreas.hansson@arm.com 5711051Sandreas.hansson@arm.comBaseBus::BaseBus(const BaseBusParams *p) 5811051Sandreas.hansson@arm.com : MemObject(p), 5911051Sandreas.hansson@arm.com headerCycles(p->header_cycles), width(p->width), 6011051Sandreas.hansson@arm.com gotAddrRanges(p->port_default_connection_count + 6111051Sandreas.hansson@arm.com p->port_master_connection_count, false), 6211051Sandreas.hansson@arm.com gotAllAddrRanges(false), defaultPortID(InvalidPortID), 6311051Sandreas.hansson@arm.com useDefaultRange(p->use_default_range), 6411051Sandreas.hansson@arm.com blockSize(p->block_size) 6511051Sandreas.hansson@arm.com{} 6611053Sandreas.hansson@arm.com 6711053Sandreas.hansson@arm.comBaseBus::~BaseBus() 6811051Sandreas.hansson@arm.com{ 6911051Sandreas.hansson@arm.com for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); 7011051Sandreas.hansson@arm.com ++m) { 7111051Sandreas.hansson@arm.com delete *m; 7211051Sandreas.hansson@arm.com } 7311051Sandreas.hansson@arm.com 7411051Sandreas.hansson@arm.com for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); 7511051Sandreas.hansson@arm.com ++s) { 7611051Sandreas.hansson@arm.com delete *s; 7711051Sandreas.hansson@arm.com } 7811051Sandreas.hansson@arm.com} 7911051Sandreas.hansson@arm.com 8011051Sandreas.hansson@arm.comvoid 8111051Sandreas.hansson@arm.comBaseBus::init() 8211051Sandreas.hansson@arm.com{ 8311051Sandreas.hansson@arm.com // determine the maximum peer block size, look at both the 8411051Sandreas.hansson@arm.com // connected master and slave modules 8511051Sandreas.hansson@arm.com uint32_t peer_block_size = 0; 8611051Sandreas.hansson@arm.com 8711051Sandreas.hansson@arm.com for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); 8811051Sandreas.hansson@arm.com ++m) { 8911051Sandreas.hansson@arm.com peer_block_size = std::max((*m)->peerBlockSize(), peer_block_size); 9011051Sandreas.hansson@arm.com } 9111051Sandreas.hansson@arm.com 9211051Sandreas.hansson@arm.com for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 9311051Sandreas.hansson@arm.com ++s) { 9411051Sandreas.hansson@arm.com peer_block_size = std::max((*s)->peerBlockSize(), peer_block_size); 9511051Sandreas.hansson@arm.com } 9611051Sandreas.hansson@arm.com 9711051Sandreas.hansson@arm.com // if the peers do not have a block size, use the default value 9811051Sandreas.hansson@arm.com // set through the bus parameters 9911051Sandreas.hansson@arm.com if (peer_block_size != 0) 10011051Sandreas.hansson@arm.com blockSize = peer_block_size; 10111051Sandreas.hansson@arm.com 10211051Sandreas.hansson@arm.com // check if the block size is a value known to work 10311051Sandreas.hansson@arm.com if (blockSize != 16 || blockSize != 32 || blockSize != 64 || 10411051Sandreas.hansson@arm.com blockSize != 128) 10511051Sandreas.hansson@arm.com warn_once("Block size is neither 16, 32, 64 or 128 bytes.\n"); 10611051Sandreas.hansson@arm.com} 10711051Sandreas.hansson@arm.com 10811051Sandreas.hansson@arm.comMasterPort & 10911051Sandreas.hansson@arm.comBaseBus::getMasterPort(const std::string &if_name, int idx) 11011051Sandreas.hansson@arm.com{ 11111051Sandreas.hansson@arm.com if (if_name == "master" && idx < masterPorts.size()) { 11211051Sandreas.hansson@arm.com // the master port index translates directly to the vector position 11311051Sandreas.hansson@arm.com return *masterPorts[idx]; 11411051Sandreas.hansson@arm.com } else if (if_name == "default") { 11511051Sandreas.hansson@arm.com return *masterPorts[defaultPortID]; 11611051Sandreas.hansson@arm.com } else { 11711051Sandreas.hansson@arm.com return MemObject::getMasterPort(if_name, idx); 11811051Sandreas.hansson@arm.com } 11911051Sandreas.hansson@arm.com} 12011051Sandreas.hansson@arm.com 12111051Sandreas.hansson@arm.comSlavePort & 12211051Sandreas.hansson@arm.comBaseBus::getSlavePort(const std::string &if_name, int idx) 12311051Sandreas.hansson@arm.com{ 12411051Sandreas.hansson@arm.com if (if_name == "slave" && idx < slavePorts.size()) { 12511051Sandreas.hansson@arm.com // the slave port index translates directly to the vector position 12611051Sandreas.hansson@arm.com return *slavePorts[idx]; 12711051Sandreas.hansson@arm.com } else { 12811051Sandreas.hansson@arm.com return MemObject::getSlavePort(if_name, idx); 12911051Sandreas.hansson@arm.com } 13011051Sandreas.hansson@arm.com} 13111051Sandreas.hansson@arm.com 13211051Sandreas.hansson@arm.comTick 13311051Sandreas.hansson@arm.comBaseBus::calcPacketTiming(PacketPtr pkt) 13411051Sandreas.hansson@arm.com{ 13511051Sandreas.hansson@arm.com // determine the current time rounded to the closest following 13611051Sandreas.hansson@arm.com // clock edge 13711051Sandreas.hansson@arm.com Tick now = nextCycle(); 13811051Sandreas.hansson@arm.com 13911051Sandreas.hansson@arm.com Tick headerTime = now + headerCycles * clock; 14011051Sandreas.hansson@arm.com 14111051Sandreas.hansson@arm.com // The packet will be sent. Figure out how long it occupies the bus, and 14211051Sandreas.hansson@arm.com // how much of that time is for the first "word", aka bus width. 14311051Sandreas.hansson@arm.com int numCycles = 0; 14411051Sandreas.hansson@arm.com if (pkt->hasData()) { 14511051Sandreas.hansson@arm.com // If a packet has data, it needs ceil(size/width) cycles to send it 14611051Sandreas.hansson@arm.com int dataSize = pkt->getSize(); 14711051Sandreas.hansson@arm.com numCycles += dataSize/width; 14811051Sandreas.hansson@arm.com if (dataSize % width) 14911051Sandreas.hansson@arm.com numCycles++; 15011051Sandreas.hansson@arm.com } 15111051Sandreas.hansson@arm.com 15211051Sandreas.hansson@arm.com // The first word will be delivered after the current tick, the delivery 15311051Sandreas.hansson@arm.com // of the address if any, and one bus cycle to deliver the data 15411051Sandreas.hansson@arm.com pkt->firstWordTime = headerTime + clock; 15511051Sandreas.hansson@arm.com 15611051Sandreas.hansson@arm.com pkt->finishTime = headerTime + numCycles * clock; 15711051Sandreas.hansson@arm.com 15811051Sandreas.hansson@arm.com return headerTime; 15911051Sandreas.hansson@arm.com} 16011051Sandreas.hansson@arm.com 16111051Sandreas.hansson@arm.comtemplate <typename PortClass> 16211051Sandreas.hansson@arm.comBaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name, 16311051Sandreas.hansson@arm.com Tick _clock) : 16411051Sandreas.hansson@arm.com bus(_bus), _name(_name), state(IDLE), clock(_clock), drainEvent(NULL), 16511051Sandreas.hansson@arm.com releaseEvent(this) 16611051Sandreas.hansson@arm.com{ 16711051Sandreas.hansson@arm.com} 16811051Sandreas.hansson@arm.com 16911051Sandreas.hansson@arm.comtemplate <typename PortClass> 17011051Sandreas.hansson@arm.comvoid BaseBus::Layer<PortClass>::occupyLayer(Tick until) 17111051Sandreas.hansson@arm.com{ 17211051Sandreas.hansson@arm.com // ensure the state is busy or in retry and never idle at this 17311051Sandreas.hansson@arm.com // point, as the bus should transition from idle as soon as it has 17411051Sandreas.hansson@arm.com // decided to forward the packet to prevent any follow-on calls to 17511051Sandreas.hansson@arm.com // sendTiming seeing an unoccupied bus 17611051Sandreas.hansson@arm.com assert(state != IDLE); 17711051Sandreas.hansson@arm.com 17811051Sandreas.hansson@arm.com // note that we do not change the bus state here, if we are going 17911051Sandreas.hansson@arm.com // from idle to busy it is handled by tryTiming, and if we 18011051Sandreas.hansson@arm.com // are in retry we should remain in retry such that 18111051Sandreas.hansson@arm.com // succeededTiming still sees the accurate state 18211051Sandreas.hansson@arm.com 18311051Sandreas.hansson@arm.com // until should never be 0 as express snoops never occupy the bus 18411051Sandreas.hansson@arm.com assert(until != 0); 18511051Sandreas.hansson@arm.com bus.schedule(releaseEvent, until); 18611051Sandreas.hansson@arm.com 18711051Sandreas.hansson@arm.com DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", 18811051Sandreas.hansson@arm.com curTick(), until); 18911051Sandreas.hansson@arm.com} 19011051Sandreas.hansson@arm.com 19111051Sandreas.hansson@arm.comtemplate <typename PortClass> 19211051Sandreas.hansson@arm.combool 19311051Sandreas.hansson@arm.comBaseBus::Layer<PortClass>::tryTiming(PortClass* port) 19411051Sandreas.hansson@arm.com{ 19511051Sandreas.hansson@arm.com // first we see if the bus is busy, next we check if we are in a 19611051Sandreas.hansson@arm.com // retry with a port other than the current one 19711051Sandreas.hansson@arm.com if (state == BUSY || (state == RETRY && port != retryList.front())) { 19811051Sandreas.hansson@arm.com // put the port at the end of the retry list 19911051Sandreas.hansson@arm.com retryList.push_back(port); 20011051Sandreas.hansson@arm.com return false; 20111051Sandreas.hansson@arm.com } 20211051Sandreas.hansson@arm.com 20311051Sandreas.hansson@arm.com // update the state which is shared for request, response and 20411051Sandreas.hansson@arm.com // snoop responses, if we were idle we are now busy, if we are in 20511051Sandreas.hansson@arm.com // a retry, then do not change 20611051Sandreas.hansson@arm.com if (state == IDLE) 20711051Sandreas.hansson@arm.com state = BUSY; 20811051Sandreas.hansson@arm.com 20911051Sandreas.hansson@arm.com return true; 21011051Sandreas.hansson@arm.com} 21111051Sandreas.hansson@arm.com 21211051Sandreas.hansson@arm.comtemplate <typename PortClass> 21311051Sandreas.hansson@arm.comvoid 21411051Sandreas.hansson@arm.comBaseBus::Layer<PortClass>::succeededTiming(Tick busy_time) 21511051Sandreas.hansson@arm.com{ 21611051Sandreas.hansson@arm.com // if a retrying port succeeded, also take it off the retry list 21711051Sandreas.hansson@arm.com if (state == RETRY) { 21811051Sandreas.hansson@arm.com DPRINTF(BaseBus, "Remove retry from list %s\n", 21911051Sandreas.hansson@arm.com retryList.front()->name()); 22011051Sandreas.hansson@arm.com retryList.pop_front(); 22111051Sandreas.hansson@arm.com state = BUSY; 22211051Sandreas.hansson@arm.com } 22311051Sandreas.hansson@arm.com 22411051Sandreas.hansson@arm.com // we should either have gone from idle to busy in the 22511051Sandreas.hansson@arm.com // tryTiming test, or just gone from a retry to busy 22611051Sandreas.hansson@arm.com assert(state == BUSY); 22711051Sandreas.hansson@arm.com 22811051Sandreas.hansson@arm.com // occupy the bus accordingly 22911051Sandreas.hansson@arm.com occupyLayer(busy_time); 23011051Sandreas.hansson@arm.com} 23111051Sandreas.hansson@arm.com 23211051Sandreas.hansson@arm.comtemplate <typename PortClass> 23311051Sandreas.hansson@arm.comvoid 23411051Sandreas.hansson@arm.comBaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time) 23511051Sandreas.hansson@arm.com{ 23611051Sandreas.hansson@arm.com // if we are not in a retry, i.e. busy (but never idle), or we are 23711051Sandreas.hansson@arm.com // in a retry but not for the current port, then add the port at 23811051Sandreas.hansson@arm.com // the end of the retry list 23911051Sandreas.hansson@arm.com if (state != RETRY || port != retryList.front()) { 24011051Sandreas.hansson@arm.com retryList.push_back(port); 24111051Sandreas.hansson@arm.com } 24211051Sandreas.hansson@arm.com 24311051Sandreas.hansson@arm.com // even if we retried the current one and did not succeed, 24411051Sandreas.hansson@arm.com // we are no longer retrying but instead busy 24511051Sandreas.hansson@arm.com state = BUSY; 24611051Sandreas.hansson@arm.com 24711051Sandreas.hansson@arm.com // occupy the bus accordingly 24811051Sandreas.hansson@arm.com occupyLayer(busy_time); 24911051Sandreas.hansson@arm.com} 25011051Sandreas.hansson@arm.com 25111051Sandreas.hansson@arm.comtemplate <typename PortClass> 25211051Sandreas.hansson@arm.comvoid 25311051Sandreas.hansson@arm.comBaseBus::Layer<PortClass>::releaseLayer() 25411051Sandreas.hansson@arm.com{ 25511051Sandreas.hansson@arm.com // releasing the bus means we should now be idle 25611051Sandreas.hansson@arm.com assert(state == BUSY); 25711051Sandreas.hansson@arm.com assert(!releaseEvent.scheduled()); 25811051Sandreas.hansson@arm.com 25911051Sandreas.hansson@arm.com // update the state 26011051Sandreas.hansson@arm.com state = IDLE; 26111051Sandreas.hansson@arm.com 26211051Sandreas.hansson@arm.com // bus is now idle, so if someone is waiting we can retry 26311051Sandreas.hansson@arm.com if (!retryList.empty()) { 26411051Sandreas.hansson@arm.com // note that we block (return false on recvTiming) both 26511051Sandreas.hansson@arm.com // because the bus is busy and because the destination is 26611051Sandreas.hansson@arm.com // busy, and in the latter case the bus may be released before 26711051Sandreas.hansson@arm.com // we see a retry from the destination 26811051Sandreas.hansson@arm.com retryWaiting(); 26911051Sandreas.hansson@arm.com } else if (drainEvent) { 27011051Sandreas.hansson@arm.com DPRINTF(Drain, "Bus done draining, processing drain event\n"); 27111051Sandreas.hansson@arm.com //If we weren't able to drain before, do it now. 27211051Sandreas.hansson@arm.com drainEvent->process(); 27311051Sandreas.hansson@arm.com // Clear the drain event once we're done with it. 27411051Sandreas.hansson@arm.com drainEvent = NULL; 27511051Sandreas.hansson@arm.com } 27611051Sandreas.hansson@arm.com} 27711051Sandreas.hansson@arm.com 27811051Sandreas.hansson@arm.comtemplate <typename PortClass> 27911051Sandreas.hansson@arm.comvoid 28011051Sandreas.hansson@arm.comBaseBus::Layer<PortClass>::retryWaiting() 28111051Sandreas.hansson@arm.com{ 28211051Sandreas.hansson@arm.com // this should never be called with an empty retry list 28311051Sandreas.hansson@arm.com assert(!retryList.empty()); 28411051Sandreas.hansson@arm.com 28511051Sandreas.hansson@arm.com // we always go to retrying from idle 28611051Sandreas.hansson@arm.com assert(state == IDLE); 28711051Sandreas.hansson@arm.com 28811051Sandreas.hansson@arm.com // update the state which is shared for request, response and 28911051Sandreas.hansson@arm.com // snoop responses 29011051Sandreas.hansson@arm.com state = RETRY; 29111051Sandreas.hansson@arm.com 29211051Sandreas.hansson@arm.com // note that we might have blocked on the receiving port being 29311051Sandreas.hansson@arm.com // busy (rather than the bus itself) and now call retry before the 29411051Sandreas.hansson@arm.com // destination called retry on the bus 29511051Sandreas.hansson@arm.com retryList.front()->sendRetry(); 29611051Sandreas.hansson@arm.com 29711051Sandreas.hansson@arm.com // If the bus is still in the retry state, sendTiming wasn't 29811051Sandreas.hansson@arm.com // called in zero time (e.g. the cache does this) 29911051Sandreas.hansson@arm.com if (state == RETRY) { 30011051Sandreas.hansson@arm.com retryList.pop_front(); 30111051Sandreas.hansson@arm.com 30211051Sandreas.hansson@arm.com //Burn a cycle for the missed grant. 30311051Sandreas.hansson@arm.com 30411051Sandreas.hansson@arm.com // update the state which is shared for request, response and 30511051Sandreas.hansson@arm.com // snoop responses 30611051Sandreas.hansson@arm.com state = BUSY; 30711051Sandreas.hansson@arm.com 30811051Sandreas.hansson@arm.com // determine the current time rounded to the closest following 30911051Sandreas.hansson@arm.com // clock edge 31011051Sandreas.hansson@arm.com Tick now = bus.nextCycle(); 31111051Sandreas.hansson@arm.com 31211051Sandreas.hansson@arm.com occupyLayer(now + clock); 31311051Sandreas.hansson@arm.com } 31411051Sandreas.hansson@arm.com} 31511051Sandreas.hansson@arm.com 31611051Sandreas.hansson@arm.comtemplate <typename PortClass> 31711051Sandreas.hansson@arm.comvoid 31811051Sandreas.hansson@arm.comBaseBus::Layer<PortClass>::recvRetry() 31911051Sandreas.hansson@arm.com{ 32011051Sandreas.hansson@arm.com // we got a retry from a peer that we tried to send something to 32111051Sandreas.hansson@arm.com // and failed, but we sent it on the account of someone else, and 32211051Sandreas.hansson@arm.com // that source port should be on our retry list, however if the 32311051Sandreas.hansson@arm.com // bus layer is released before this happens and the retry (from 32411051Sandreas.hansson@arm.com // the bus point of view) is successful then this no longer holds 32511051Sandreas.hansson@arm.com // and we could in fact have an empty retry list 32611051Sandreas.hansson@arm.com if (retryList.empty()) 32711051Sandreas.hansson@arm.com return; 32811051Sandreas.hansson@arm.com 32911051Sandreas.hansson@arm.com // if the bus layer is idle 33011051Sandreas.hansson@arm.com if (state == IDLE) { 33111051Sandreas.hansson@arm.com // note that we do not care who told us to retry at the moment, we 33211051Sandreas.hansson@arm.com // merely let the first one on the retry list go 33311051Sandreas.hansson@arm.com retryWaiting(); 33411051Sandreas.hansson@arm.com } 33511051Sandreas.hansson@arm.com} 33611051Sandreas.hansson@arm.com 33711051Sandreas.hansson@arm.comPortID 33811051Sandreas.hansson@arm.comBaseBus::findPort(Addr addr) 33911051Sandreas.hansson@arm.com{ 34011051Sandreas.hansson@arm.com // we should never see any address lookups before we've got the 34111051Sandreas.hansson@arm.com // ranges of all connected slave modules 34211051Sandreas.hansson@arm.com assert(gotAllAddrRanges); 34311051Sandreas.hansson@arm.com 34411051Sandreas.hansson@arm.com // Check the cache 34511051Sandreas.hansson@arm.com PortID dest_id = checkPortCache(addr); 34611051Sandreas.hansson@arm.com if (dest_id != InvalidPortID) 34711051Sandreas.hansson@arm.com return dest_id; 34811051Sandreas.hansson@arm.com 34911051Sandreas.hansson@arm.com // Check the address map interval tree 35011051Sandreas.hansson@arm.com PortMapConstIter i = portMap.find(addr); 35111051Sandreas.hansson@arm.com if (i != portMap.end()) { 35211051Sandreas.hansson@arm.com dest_id = i->second; 35311051Sandreas.hansson@arm.com updatePortCache(dest_id, i->first); 35411051Sandreas.hansson@arm.com return dest_id; 35511051Sandreas.hansson@arm.com } 35611051Sandreas.hansson@arm.com 35711051Sandreas.hansson@arm.com // Check if this matches the default range 35811051Sandreas.hansson@arm.com if (useDefaultRange) { 35911051Sandreas.hansson@arm.com if (defaultRange == addr) { 36011051Sandreas.hansson@arm.com DPRINTF(BusAddrRanges, " found addr %#llx on default\n", 36111051Sandreas.hansson@arm.com addr); 36211051Sandreas.hansson@arm.com return defaultPortID; 36311051Sandreas.hansson@arm.com } 36411051Sandreas.hansson@arm.com } else if (defaultPortID != InvalidPortID) { 36511051Sandreas.hansson@arm.com DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " 36611051Sandreas.hansson@arm.com "will use default port\n", addr); 36711051Sandreas.hansson@arm.com return defaultPortID; 36811051Sandreas.hansson@arm.com } 36911051Sandreas.hansson@arm.com 37011051Sandreas.hansson@arm.com // we should use the range for the default port and it did not 37111051Sandreas.hansson@arm.com // match, or the default port is not set 37211051Sandreas.hansson@arm.com fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 37311051Sandreas.hansson@arm.com name()); 37411051Sandreas.hansson@arm.com} 37511051Sandreas.hansson@arm.com 37611051Sandreas.hansson@arm.com/** Function called by the port when the bus is receiving a range change.*/ 37711051Sandreas.hansson@arm.comvoid 37811051Sandreas.hansson@arm.comBaseBus::recvRangeChange(PortID master_port_id) 37911051Sandreas.hansson@arm.com{ 38011051Sandreas.hansson@arm.com // remember that we got a range from this master port and thus the 38111051Sandreas.hansson@arm.com // connected slave module 38211051Sandreas.hansson@arm.com gotAddrRanges[master_port_id] = true; 38311051Sandreas.hansson@arm.com 38411051Sandreas.hansson@arm.com // update the global flag 38511051Sandreas.hansson@arm.com if (!gotAllAddrRanges) { 38611051Sandreas.hansson@arm.com // take a logical AND of all the ports and see if we got 38711051Sandreas.hansson@arm.com // ranges from everyone 38811051Sandreas.hansson@arm.com gotAllAddrRanges = true; 38911051Sandreas.hansson@arm.com std::vector<bool>::const_iterator r = gotAddrRanges.begin(); 39011051Sandreas.hansson@arm.com while (gotAllAddrRanges && r != gotAddrRanges.end()) { 39111051Sandreas.hansson@arm.com gotAllAddrRanges &= *r++; 39211051Sandreas.hansson@arm.com } 39311051Sandreas.hansson@arm.com } 39411051Sandreas.hansson@arm.com 39511051Sandreas.hansson@arm.com // note that we could get the range from the default port at any 39611051Sandreas.hansson@arm.com // point in time, and we cannot assume that the default range is 39711051Sandreas.hansson@arm.com // set before the other ones are, so we do additional checks once 39811051Sandreas.hansson@arm.com // all ranges are provided 39911051Sandreas.hansson@arm.com DPRINTF(BusAddrRanges, "received RangeChange from slave port %s\n", 40011051Sandreas.hansson@arm.com masterPorts[master_port_id]->getSlavePort().name()); 40111051Sandreas.hansson@arm.com 40211051Sandreas.hansson@arm.com if (master_port_id == defaultPortID) { 40311051Sandreas.hansson@arm.com // only update if we are indeed checking ranges for the 40411051Sandreas.hansson@arm.com // default port since the port might not have a valid range 40511051Sandreas.hansson@arm.com // otherwise 40611051Sandreas.hansson@arm.com if (useDefaultRange) { 40711051Sandreas.hansson@arm.com AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 40811051Sandreas.hansson@arm.com 40911051Sandreas.hansson@arm.com if (ranges.size() != 1) 41011051Sandreas.hansson@arm.com fatal("Bus %s may only have a single default range", 41111051Sandreas.hansson@arm.com name()); 41211051Sandreas.hansson@arm.com 41311051Sandreas.hansson@arm.com defaultRange = ranges.front(); 41411051Sandreas.hansson@arm.com } 41511051Sandreas.hansson@arm.com } else { 41611051Sandreas.hansson@arm.com // the ports are allowed to update their address ranges 41711051Sandreas.hansson@arm.com // dynamically, so remove any existing entries 41811051Sandreas.hansson@arm.com if (gotAddrRanges[master_port_id]) { 41911051Sandreas.hansson@arm.com for (PortMapIter p = portMap.begin(); p != portMap.end(); ) { 42011051Sandreas.hansson@arm.com if (p->second == master_port_id) 42111051Sandreas.hansson@arm.com // erasing invalidates the iterator, so advance it 42211051Sandreas.hansson@arm.com // before the deletion takes place 42311051Sandreas.hansson@arm.com portMap.erase(p++); 42411051Sandreas.hansson@arm.com else 42511051Sandreas.hansson@arm.com p++; 42611051Sandreas.hansson@arm.com } 42711051Sandreas.hansson@arm.com } 42811051Sandreas.hansson@arm.com 42911051Sandreas.hansson@arm.com AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 43011051Sandreas.hansson@arm.com 43111051Sandreas.hansson@arm.com for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) { 43211051Sandreas.hansson@arm.com DPRINTF(BusAddrRanges, "Adding range %#llx : %#llx for id %d\n", 43311051Sandreas.hansson@arm.com r->start, r->end, master_port_id); 43411051Sandreas.hansson@arm.com if (portMap.insert(*r, master_port_id) == portMap.end()) { 43511051Sandreas.hansson@arm.com PortID conflict_id = portMap.find(*r)->second; 43611051Sandreas.hansson@arm.com fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 43711051Sandreas.hansson@arm.com name(), 43811051Sandreas.hansson@arm.com masterPorts[master_port_id]->getSlavePort().name(), 43911051Sandreas.hansson@arm.com masterPorts[conflict_id]->getSlavePort().name()); 44011051Sandreas.hansson@arm.com } 44111051Sandreas.hansson@arm.com } 44211051Sandreas.hansson@arm.com } 44311051Sandreas.hansson@arm.com 44411051Sandreas.hansson@arm.com // if we have received ranges from all our neighbouring slave 44511051Sandreas.hansson@arm.com // modules, go ahead and tell our connected master modules in 44611051Sandreas.hansson@arm.com // turn, this effectively assumes a tree structure of the system 44711051Sandreas.hansson@arm.com if (gotAllAddrRanges) { 44811051Sandreas.hansson@arm.com // also check that no range partially overlaps with the 44911051Sandreas.hansson@arm.com // default range, this has to be done after all ranges are set 45011051Sandreas.hansson@arm.com // as there are no guarantees for when the default range is 45111051Sandreas.hansson@arm.com // update with respect to the other ones 45211051Sandreas.hansson@arm.com if (useDefaultRange) { 45311051Sandreas.hansson@arm.com for (PortID port_id = 0; port_id < masterPorts.size(); ++port_id) { 45411051Sandreas.hansson@arm.com if (port_id == defaultPortID) { 45511051Sandreas.hansson@arm.com if (!gotAddrRanges[port_id]) 45611051Sandreas.hansson@arm.com fatal("Bus %s uses default range, but none provided", 45711051Sandreas.hansson@arm.com name()); 45811130Sali.jafri@arm.com } else { 45911130Sali.jafri@arm.com AddrRangeList ranges = 46011130Sali.jafri@arm.com masterPorts[port_id]->getAddrRanges(); 46111130Sali.jafri@arm.com 46211130Sali.jafri@arm.com for (AddrRangeConstIter r = ranges.begin(); 46311130Sali.jafri@arm.com r != ranges.end(); ++r) { 46411130Sali.jafri@arm.com // see if the new range is partially 46511130Sali.jafri@arm.com // overlapping the default range 46611130Sali.jafri@arm.com if (r->intersects(defaultRange) && 46711130Sali.jafri@arm.com !r->isSubset(defaultRange)) 46811130Sali.jafri@arm.com fatal("Range %#llx : %#llx intersects the " \ 46911130Sali.jafri@arm.com "default range of %s but is not a " \ 47011130Sali.jafri@arm.com "subset\n", r->start, r->end, name()); 47111130Sali.jafri@arm.com } 47211130Sali.jafri@arm.com } 47311130Sali.jafri@arm.com } 47411130Sali.jafri@arm.com } 47511130Sali.jafri@arm.com 47611130Sali.jafri@arm.com // tell all our neighbouring master ports that our address 47711130Sali.jafri@arm.com // ranges have changed 47811130Sali.jafri@arm.com for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 47911130Sali.jafri@arm.com ++s) 48011130Sali.jafri@arm.com (*s)->sendRangeChange(); 48111130Sali.jafri@arm.com } 48211130Sali.jafri@arm.com 48311130Sali.jafri@arm.com clearPortCache(); 48411130Sali.jafri@arm.com} 48511130Sali.jafri@arm.com 48611130Sali.jafri@arm.comAddrRangeList 48711130Sali.jafri@arm.comBaseBus::getAddrRanges() const 48811130Sali.jafri@arm.com{ 48911130Sali.jafri@arm.com // we should never be asked without first having sent a range 49011130Sali.jafri@arm.com // change, and the latter is only done once we have all the ranges 49111051Sandreas.hansson@arm.com // of the connected devices 49211051Sandreas.hansson@arm.com assert(gotAllAddrRanges); 49311051Sandreas.hansson@arm.com 49411051Sandreas.hansson@arm.com DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 49511051Sandreas.hansson@arm.com 49611051Sandreas.hansson@arm.com // start out with the default range 49711051Sandreas.hansson@arm.com AddrRangeList ranges; 49811051Sandreas.hansson@arm.com ranges.push_back(defaultRange); 49911051Sandreas.hansson@arm.com DPRINTF(BusAddrRanges, " -- %#llx : %#llx DEFAULT\n", 50011051Sandreas.hansson@arm.com defaultRange.start, defaultRange.end); 50111051Sandreas.hansson@arm.com 50211051Sandreas.hansson@arm.com // add any range that is not a subset of the default range 50311051Sandreas.hansson@arm.com for (PortMapConstIter p = portMap.begin(); p != portMap.end(); ++p) { 50411051Sandreas.hansson@arm.com if (useDefaultRange && p->first.isSubset(defaultRange)) { 50511051Sandreas.hansson@arm.com DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 50611051Sandreas.hansson@arm.com p->first.start, p->first.end); 50711051Sandreas.hansson@arm.com } else { 50811051Sandreas.hansson@arm.com ranges.push_back(p->first); 50911051Sandreas.hansson@arm.com DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 51011051Sandreas.hansson@arm.com p->first.start, p->first.end); 51111051Sandreas.hansson@arm.com } 51211051Sandreas.hansson@arm.com } 51311051Sandreas.hansson@arm.com 51411051Sandreas.hansson@arm.com return ranges; 51511051Sandreas.hansson@arm.com} 51611051Sandreas.hansson@arm.com 51711051Sandreas.hansson@arm.comunsigned 51811051Sandreas.hansson@arm.comBaseBus::deviceBlockSize() const 51911051Sandreas.hansson@arm.com{ 52011051Sandreas.hansson@arm.com return blockSize; 52111051Sandreas.hansson@arm.com} 52211051Sandreas.hansson@arm.com 52311051Sandreas.hansson@arm.comtemplate <typename PortClass> 52411051Sandreas.hansson@arm.comunsigned int 52511051Sandreas.hansson@arm.comBaseBus::Layer<PortClass>::drain(Event * de) 52611051Sandreas.hansson@arm.com{ 52711051Sandreas.hansson@arm.com //We should check that we're not "doing" anything, and that noone is 52811051Sandreas.hansson@arm.com //waiting. We might be idle but have someone waiting if the device we 52911051Sandreas.hansson@arm.com //contacted for a retry didn't actually retry. 53011051Sandreas.hansson@arm.com if (!retryList.empty() || state != IDLE) { 53111051Sandreas.hansson@arm.com DPRINTF(Drain, "Bus not drained\n"); 53211051Sandreas.hansson@arm.com drainEvent = de; 53311051Sandreas.hansson@arm.com return 1; 53411051Sandreas.hansson@arm.com } 53511051Sandreas.hansson@arm.com return 0; 53611051Sandreas.hansson@arm.com} 53711051Sandreas.hansson@arm.com 53811051Sandreas.hansson@arm.com/** 53911051Sandreas.hansson@arm.com * Bus layer template instantiations. Could be removed with _impl.hh 54011051Sandreas.hansson@arm.com * file, but since there are only two given options (MasterPort and 54111051Sandreas.hansson@arm.com * SlavePort) it seems a bit excessive at this point. 54211051Sandreas.hansson@arm.com */ 54311051Sandreas.hansson@arm.comtemplate class BaseBus::Layer<SlavePort>; 54411051Sandreas.hansson@arm.comtemplate class BaseBus::Layer<MasterPort>; 54511051Sandreas.hansson@arm.com