xbar.cc revision 9545
112137Sar4jc@virginia.edu/* 212137Sar4jc@virginia.edu * Copyright (c) 2011-2013 ARM Limited 312137Sar4jc@virginia.edu * All rights reserved 412137Sar4jc@virginia.edu * 512137Sar4jc@virginia.edu * The license below extends only to copyright in the software and shall 612137Sar4jc@virginia.edu * not be construed as granting a license to any other intellectual 712137Sar4jc@virginia.edu * property including but not limited to intellectual property relating 812137Sar4jc@virginia.edu * to a hardware implementation of the functionality of the software 912137Sar4jc@virginia.edu * licensed hereunder. You may use the software subject to the license 1012137Sar4jc@virginia.edu * terms below provided that you ensure that this notice is replicated 1112137Sar4jc@virginia.edu * unmodified and in its entirety in all distributions of the software, 1212137Sar4jc@virginia.edu * modified or unmodified, in source code or in binary form. 1312137Sar4jc@virginia.edu * 1412137Sar4jc@virginia.edu * Copyright (c) 2006 The Regents of The University of Michigan 1512137Sar4jc@virginia.edu * All rights reserved. 1612137Sar4jc@virginia.edu * 1712137Sar4jc@virginia.edu * Redistribution and use in source and binary forms, with or without 1812137Sar4jc@virginia.edu * modification, are permitted provided that the following conditions are 1912137Sar4jc@virginia.edu * met: redistributions of source code must retain the above copyright 2012137Sar4jc@virginia.edu * notice, this list of conditions and the following disclaimer; 2112137Sar4jc@virginia.edu * redistributions in binary form must reproduce the above copyright 2212137Sar4jc@virginia.edu * notice, this list of conditions and the following disclaimer in the 2312137Sar4jc@virginia.edu * documentation and/or other materials provided with the distribution; 2412137Sar4jc@virginia.edu * neither the name of the copyright holders nor the names of its 2512137Sar4jc@virginia.edu * contributors may be used to endorse or promote products derived from 2612137Sar4jc@virginia.edu * this software without specific prior written permission. 2712137Sar4jc@virginia.edu * 2812137Sar4jc@virginia.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2912137Sar4jc@virginia.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3012137Sar4jc@virginia.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3112137Sar4jc@virginia.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3212137Sar4jc@virginia.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3312137Sar4jc@virginia.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3412137Sar4jc@virginia.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3512137Sar4jc@virginia.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3612137Sar4jc@virginia.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3712137Sar4jc@virginia.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3812137Sar4jc@virginia.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3912137Sar4jc@virginia.edu * 4012137Sar4jc@virginia.edu * Authors: Ali Saidi 4112137Sar4jc@virginia.edu * Andreas Hansson 4212137Sar4jc@virginia.edu * William Wang 4312137Sar4jc@virginia.edu */ 4412137Sar4jc@virginia.edu 4512137Sar4jc@virginia.edu/** 4612137Sar4jc@virginia.edu * @file 4712137Sar4jc@virginia.edu * Definition of a bus object. 4812137Sar4jc@virginia.edu */ 4912137Sar4jc@virginia.edu 5012137Sar4jc@virginia.edu#include "base/misc.hh" 5112137Sar4jc@virginia.edu#include "base/trace.hh" 5212137Sar4jc@virginia.edu#include "debug/Bus.hh" 5312137Sar4jc@virginia.edu#include "debug/BusAddrRanges.hh" 5412137Sar4jc@virginia.edu#include "debug/Drain.hh" 5512137Sar4jc@virginia.edu#include "mem/bus.hh" 5612137Sar4jc@virginia.edu 5712137Sar4jc@virginia.eduBaseBus::BaseBus(const BaseBusParams *p) 5812137Sar4jc@virginia.edu : MemObject(p), 5912137Sar4jc@virginia.edu headerCycles(p->header_cycles), width(p->width), 6012137Sar4jc@virginia.edu gotAddrRanges(p->port_default_connection_count + 6112137Sar4jc@virginia.edu p->port_master_connection_count, false), 6212137Sar4jc@virginia.edu gotAllAddrRanges(false), defaultPortID(InvalidPortID), 6312137Sar4jc@virginia.edu useDefaultRange(p->use_default_range), 6412137Sar4jc@virginia.edu blockSize(p->block_size) 6512137Sar4jc@virginia.edu{} 6612137Sar4jc@virginia.edu 6712137Sar4jc@virginia.eduBaseBus::~BaseBus() 6812137Sar4jc@virginia.edu{ 6912137Sar4jc@virginia.edu for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); 7012137Sar4jc@virginia.edu ++m) { 7112137Sar4jc@virginia.edu delete *m; 7212137Sar4jc@virginia.edu } 7312137Sar4jc@virginia.edu 7412137Sar4jc@virginia.edu for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); 7512137Sar4jc@virginia.edu ++s) { 7612137Sar4jc@virginia.edu delete *s; 7712137Sar4jc@virginia.edu } 7812137Sar4jc@virginia.edu} 7912137Sar4jc@virginia.edu 8012137Sar4jc@virginia.eduvoid 8112137Sar4jc@virginia.eduBaseBus::init() 8212137Sar4jc@virginia.edu{ 8312137Sar4jc@virginia.edu // determine the maximum peer block size, look at both the 8412137Sar4jc@virginia.edu // connected master and slave modules 8512137Sar4jc@virginia.edu uint32_t peer_block_size = 0; 8612137Sar4jc@virginia.edu 8712137Sar4jc@virginia.edu for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); 8812137Sar4jc@virginia.edu ++m) { 8912137Sar4jc@virginia.edu peer_block_size = std::max((*m)->peerBlockSize(), peer_block_size); 9012137Sar4jc@virginia.edu } 9112137Sar4jc@virginia.edu 9212137Sar4jc@virginia.edu for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 9312137Sar4jc@virginia.edu ++s) { 9412137Sar4jc@virginia.edu peer_block_size = std::max((*s)->peerBlockSize(), peer_block_size); 9512137Sar4jc@virginia.edu } 9612137Sar4jc@virginia.edu 9712137Sar4jc@virginia.edu // if the peers do not have a block size, use the default value 9812137Sar4jc@virginia.edu // set through the bus parameters 9912137Sar4jc@virginia.edu if (peer_block_size != 0) 10012137Sar4jc@virginia.edu blockSize = peer_block_size; 10112137Sar4jc@virginia.edu 10212137Sar4jc@virginia.edu // check if the block size is a value known to work 10312137Sar4jc@virginia.edu if (!(blockSize == 16 || blockSize == 32 || blockSize == 64 || 10412137Sar4jc@virginia.edu blockSize == 128)) 10512137Sar4jc@virginia.edu warn_once("Block size is neither 16, 32, 64 or 128 bytes.\n"); 10612137Sar4jc@virginia.edu} 10712137Sar4jc@virginia.edu 10812137Sar4jc@virginia.eduBaseMasterPort & 10912137Sar4jc@virginia.eduBaseBus::getMasterPort(const std::string &if_name, PortID idx) 11012137Sar4jc@virginia.edu{ 11112137Sar4jc@virginia.edu if (if_name == "master" && idx < masterPorts.size()) { 11212137Sar4jc@virginia.edu // the master port index translates directly to the vector position 11312137Sar4jc@virginia.edu return *masterPorts[idx]; 11412137Sar4jc@virginia.edu } else if (if_name == "default") { 11512137Sar4jc@virginia.edu return *masterPorts[defaultPortID]; 11612137Sar4jc@virginia.edu } else { 11712137Sar4jc@virginia.edu return MemObject::getMasterPort(if_name, idx); 11812137Sar4jc@virginia.edu } 11912137Sar4jc@virginia.edu} 12012137Sar4jc@virginia.edu 12112137Sar4jc@virginia.eduBaseSlavePort & 12212137Sar4jc@virginia.eduBaseBus::getSlavePort(const std::string &if_name, PortID idx) 12312137Sar4jc@virginia.edu{ 12412137Sar4jc@virginia.edu if (if_name == "slave" && idx < slavePorts.size()) { 12512137Sar4jc@virginia.edu // the slave port index translates directly to the vector position 12612137Sar4jc@virginia.edu return *slavePorts[idx]; 12712137Sar4jc@virginia.edu } else { 12812137Sar4jc@virginia.edu return MemObject::getSlavePort(if_name, idx); 12912137Sar4jc@virginia.edu } 13012137Sar4jc@virginia.edu} 13112137Sar4jc@virginia.edu 13212137Sar4jc@virginia.eduTick 13312137Sar4jc@virginia.eduBaseBus::calcPacketTiming(PacketPtr pkt) 13412137Sar4jc@virginia.edu{ 13512137Sar4jc@virginia.edu // determine the header time rounded to the closest following 13612137Sar4jc@virginia.edu // clock edge 13712137Sar4jc@virginia.edu Tick headerTime = clockEdge(headerCycles); 13812137Sar4jc@virginia.edu 13912137Sar4jc@virginia.edu // The packet will be sent. Figure out how long it occupies the bus, and 14012137Sar4jc@virginia.edu // how much of that time is for the first "word", aka bus width. 14112137Sar4jc@virginia.edu Cycles numCycles(0); 14212137Sar4jc@virginia.edu if (pkt->hasData()) { 14312137Sar4jc@virginia.edu // If a packet has data, it needs ceil(size/width) cycles to send it 14412137Sar4jc@virginia.edu unsigned dataSize = pkt->getSize(); 14512137Sar4jc@virginia.edu numCycles = Cycles(divCeil(dataSize, width)); 14612137Sar4jc@virginia.edu } 14712137Sar4jc@virginia.edu 14812137Sar4jc@virginia.edu // The first word will be delivered on the cycle after the header. 14912137Sar4jc@virginia.edu pkt->firstWordTime = headerTime + clockPeriod(); 15012137Sar4jc@virginia.edu 15112137Sar4jc@virginia.edu // Note that currently finishTime can be smaller than 15212137Sar4jc@virginia.edu // firstWordTime if the packet has no data 15312137Sar4jc@virginia.edu pkt->finishTime = headerTime + numCycles * clockPeriod(); 15412137Sar4jc@virginia.edu 15512137Sar4jc@virginia.edu return headerTime; 15612137Sar4jc@virginia.edu} 15712137Sar4jc@virginia.edu 15812137Sar4jc@virginia.edutemplate <typename PortClass> 15912137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name) : 16012137Sar4jc@virginia.edu Drainable(), 16112137Sar4jc@virginia.edu bus(_bus), _name(_name), state(IDLE), drainManager(NULL), 16212137Sar4jc@virginia.edu releaseEvent(this) 16312137Sar4jc@virginia.edu{ 16412137Sar4jc@virginia.edu} 16512137Sar4jc@virginia.edu 16612137Sar4jc@virginia.edutemplate <typename PortClass> 16712137Sar4jc@virginia.eduvoid BaseBus::Layer<PortClass>::occupyLayer(Tick until) 16812137Sar4jc@virginia.edu{ 16912137Sar4jc@virginia.edu // ensure the state is busy or in retry and never idle at this 17012137Sar4jc@virginia.edu // point, as the bus should transition from idle as soon as it has 17112137Sar4jc@virginia.edu // decided to forward the packet to prevent any follow-on calls to 17212137Sar4jc@virginia.edu // sendTiming seeing an unoccupied bus 17312137Sar4jc@virginia.edu assert(state != IDLE); 17412137Sar4jc@virginia.edu 17512137Sar4jc@virginia.edu // note that we do not change the bus state here, if we are going 17612137Sar4jc@virginia.edu // from idle to busy it is handled by tryTiming, and if we 17712137Sar4jc@virginia.edu // are in retry we should remain in retry such that 17812137Sar4jc@virginia.edu // succeededTiming still sees the accurate state 17912137Sar4jc@virginia.edu 18012137Sar4jc@virginia.edu // until should never be 0 as express snoops never occupy the bus 18112137Sar4jc@virginia.edu assert(until != 0); 18212137Sar4jc@virginia.edu bus.schedule(releaseEvent, until); 18312137Sar4jc@virginia.edu 18412137Sar4jc@virginia.edu DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", 18512137Sar4jc@virginia.edu curTick(), until); 18612137Sar4jc@virginia.edu} 18712137Sar4jc@virginia.edu 18812137Sar4jc@virginia.edutemplate <typename PortClass> 18912137Sar4jc@virginia.edubool 19012137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::tryTiming(PortClass* port) 19112137Sar4jc@virginia.edu{ 19212137Sar4jc@virginia.edu // first we see if the bus is busy, next we check if we are in a 19312137Sar4jc@virginia.edu // retry with a port other than the current one 19412137Sar4jc@virginia.edu if (state == BUSY || (state == RETRY && port != retryList.front())) { 19512137Sar4jc@virginia.edu // put the port at the end of the retry list 19612137Sar4jc@virginia.edu retryList.push_back(port); 19712137Sar4jc@virginia.edu return false; 19812137Sar4jc@virginia.edu } 19912137Sar4jc@virginia.edu 20012137Sar4jc@virginia.edu // update the state which is shared for request, response and 20112137Sar4jc@virginia.edu // snoop responses, if we were idle we are now busy, if we are in 20212137Sar4jc@virginia.edu // a retry, then do not change 20312137Sar4jc@virginia.edu if (state == IDLE) 20412137Sar4jc@virginia.edu state = BUSY; 20512137Sar4jc@virginia.edu 20612137Sar4jc@virginia.edu return true; 20712137Sar4jc@virginia.edu} 20812137Sar4jc@virginia.edu 20912137Sar4jc@virginia.edutemplate <typename PortClass> 21012137Sar4jc@virginia.eduvoid 21112137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::succeededTiming(Tick busy_time) 21212137Sar4jc@virginia.edu{ 21312137Sar4jc@virginia.edu // if a retrying port succeeded, also take it off the retry list 21412137Sar4jc@virginia.edu if (state == RETRY) { 21512137Sar4jc@virginia.edu DPRINTF(BaseBus, "Remove retry from list %s\n", 21612137Sar4jc@virginia.edu retryList.front()->name()); 21712137Sar4jc@virginia.edu retryList.pop_front(); 21812137Sar4jc@virginia.edu state = BUSY; 21912137Sar4jc@virginia.edu } 22012137Sar4jc@virginia.edu 22112137Sar4jc@virginia.edu // we should either have gone from idle to busy in the 22212137Sar4jc@virginia.edu // tryTiming test, or just gone from a retry to busy 22312137Sar4jc@virginia.edu assert(state == BUSY); 22412137Sar4jc@virginia.edu 22512137Sar4jc@virginia.edu // occupy the bus accordingly 22612137Sar4jc@virginia.edu occupyLayer(busy_time); 22712137Sar4jc@virginia.edu} 22812137Sar4jc@virginia.edu 22912137Sar4jc@virginia.edutemplate <typename PortClass> 23012137Sar4jc@virginia.eduvoid 23112137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time) 23212137Sar4jc@virginia.edu{ 23312137Sar4jc@virginia.edu // if we are not in a retry, i.e. busy (but never idle), or we are 23412137Sar4jc@virginia.edu // in a retry but not for the current port, then add the port at 23512137Sar4jc@virginia.edu // the end of the retry list 23612137Sar4jc@virginia.edu if (state != RETRY || port != retryList.front()) { 23712137Sar4jc@virginia.edu retryList.push_back(port); 23812137Sar4jc@virginia.edu } 23912137Sar4jc@virginia.edu 24012137Sar4jc@virginia.edu // even if we retried the current one and did not succeed, 24112137Sar4jc@virginia.edu // we are no longer retrying but instead busy 24212137Sar4jc@virginia.edu state = BUSY; 24312137Sar4jc@virginia.edu 24412137Sar4jc@virginia.edu // occupy the bus accordingly 24512137Sar4jc@virginia.edu occupyLayer(busy_time); 24612137Sar4jc@virginia.edu} 24712137Sar4jc@virginia.edu 24812137Sar4jc@virginia.edutemplate <typename PortClass> 24912137Sar4jc@virginia.eduvoid 25012137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::releaseLayer() 25112137Sar4jc@virginia.edu{ 25212137Sar4jc@virginia.edu // releasing the bus means we should now be idle 25312137Sar4jc@virginia.edu assert(state == BUSY); 25412137Sar4jc@virginia.edu assert(!releaseEvent.scheduled()); 25512137Sar4jc@virginia.edu 25612137Sar4jc@virginia.edu // update the state 25712137Sar4jc@virginia.edu state = IDLE; 25812137Sar4jc@virginia.edu 25912137Sar4jc@virginia.edu // bus is now idle, so if someone is waiting we can retry 26012137Sar4jc@virginia.edu if (!retryList.empty()) { 26112137Sar4jc@virginia.edu // note that we block (return false on recvTiming) both 26212137Sar4jc@virginia.edu // because the bus is busy and because the destination is 26312137Sar4jc@virginia.edu // busy, and in the latter case the bus may be released before 26412137Sar4jc@virginia.edu // we see a retry from the destination 26512137Sar4jc@virginia.edu retryWaiting(); 26612137Sar4jc@virginia.edu } else if (drainManager) { 26712137Sar4jc@virginia.edu DPRINTF(Drain, "Bus done draining, signaling drain manager\n"); 26812137Sar4jc@virginia.edu //If we weren't able to drain before, do it now. 26912137Sar4jc@virginia.edu drainManager->signalDrainDone(); 27012137Sar4jc@virginia.edu // Clear the drain event once we're done with it. 27112137Sar4jc@virginia.edu drainManager = NULL; 27212137Sar4jc@virginia.edu } 27312137Sar4jc@virginia.edu} 27412137Sar4jc@virginia.edu 27512137Sar4jc@virginia.edutemplate <typename PortClass> 27612137Sar4jc@virginia.eduvoid 27712137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::retryWaiting() 27812137Sar4jc@virginia.edu{ 27912137Sar4jc@virginia.edu // this should never be called with an empty retry list 28012137Sar4jc@virginia.edu assert(!retryList.empty()); 28112137Sar4jc@virginia.edu 28212137Sar4jc@virginia.edu // we always go to retrying from idle 28312137Sar4jc@virginia.edu assert(state == IDLE); 28412137Sar4jc@virginia.edu 28512137Sar4jc@virginia.edu // update the state which is shared for request, response and 28612137Sar4jc@virginia.edu // snoop responses 28712137Sar4jc@virginia.edu state = RETRY; 28812137Sar4jc@virginia.edu 28912137Sar4jc@virginia.edu // note that we might have blocked on the receiving port being 29012137Sar4jc@virginia.edu // busy (rather than the bus itself) and now call retry before the 29112137Sar4jc@virginia.edu // destination called retry on the bus 29212137Sar4jc@virginia.edu retryList.front()->sendRetry(); 29312137Sar4jc@virginia.edu 29412137Sar4jc@virginia.edu // If the bus is still in the retry state, sendTiming wasn't 29512137Sar4jc@virginia.edu // called in zero time (e.g. the cache does this) 29612137Sar4jc@virginia.edu if (state == RETRY) { 29712137Sar4jc@virginia.edu retryList.pop_front(); 29812137Sar4jc@virginia.edu 29912137Sar4jc@virginia.edu //Burn a cycle for the missed grant. 30012137Sar4jc@virginia.edu 30112137Sar4jc@virginia.edu // update the state which is shared for request, response and 30212137Sar4jc@virginia.edu // snoop responses 30312137Sar4jc@virginia.edu state = BUSY; 30412137Sar4jc@virginia.edu 30512137Sar4jc@virginia.edu // occupy the bus layer until the next cycle ends 30612137Sar4jc@virginia.edu occupyLayer(bus.clockEdge(Cycles(1))); 30712137Sar4jc@virginia.edu } 30812137Sar4jc@virginia.edu} 30912137Sar4jc@virginia.edu 31012137Sar4jc@virginia.edutemplate <typename PortClass> 31112137Sar4jc@virginia.eduvoid 31212137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::recvRetry() 31312137Sar4jc@virginia.edu{ 31412137Sar4jc@virginia.edu // we got a retry from a peer that we tried to send something to 31512137Sar4jc@virginia.edu // and failed, but we sent it on the account of someone else, and 31612137Sar4jc@virginia.edu // that source port should be on our retry list, however if the 31712137Sar4jc@virginia.edu // bus layer is released before this happens and the retry (from 31812137Sar4jc@virginia.edu // the bus point of view) is successful then this no longer holds 31912137Sar4jc@virginia.edu // and we could in fact have an empty retry list 32012137Sar4jc@virginia.edu if (retryList.empty()) 32112137Sar4jc@virginia.edu return; 32212137Sar4jc@virginia.edu 32312137Sar4jc@virginia.edu // if the bus layer is idle 32412137Sar4jc@virginia.edu if (state == IDLE) { 32512137Sar4jc@virginia.edu // note that we do not care who told us to retry at the moment, we 32612137Sar4jc@virginia.edu // merely let the first one on the retry list go 32712137Sar4jc@virginia.edu retryWaiting(); 32812137Sar4jc@virginia.edu } 32912137Sar4jc@virginia.edu} 33012137Sar4jc@virginia.edu 33112137Sar4jc@virginia.eduPortID 33212137Sar4jc@virginia.eduBaseBus::findPort(Addr addr) 33312137Sar4jc@virginia.edu{ 33412137Sar4jc@virginia.edu // we should never see any address lookups before we've got the 33512137Sar4jc@virginia.edu // ranges of all connected slave modules 33612137Sar4jc@virginia.edu assert(gotAllAddrRanges); 33712137Sar4jc@virginia.edu 33812137Sar4jc@virginia.edu // Check the cache 33912137Sar4jc@virginia.edu PortID dest_id = checkPortCache(addr); 34012137Sar4jc@virginia.edu if (dest_id != InvalidPortID) 34112137Sar4jc@virginia.edu return dest_id; 34212137Sar4jc@virginia.edu 34312137Sar4jc@virginia.edu // Check the address map interval tree 34412137Sar4jc@virginia.edu PortMapConstIter i = portMap.find(addr); 34512137Sar4jc@virginia.edu if (i != portMap.end()) { 34612137Sar4jc@virginia.edu dest_id = i->second; 34712137Sar4jc@virginia.edu updatePortCache(dest_id, i->first); 34812137Sar4jc@virginia.edu return dest_id; 34912137Sar4jc@virginia.edu } 35012137Sar4jc@virginia.edu 35112137Sar4jc@virginia.edu // Check if this matches the default range 35212137Sar4jc@virginia.edu if (useDefaultRange) { 35312137Sar4jc@virginia.edu if (defaultRange.contains(addr)) { 35412137Sar4jc@virginia.edu DPRINTF(BusAddrRanges, " found addr %#llx on default\n", 35512137Sar4jc@virginia.edu addr); 35612137Sar4jc@virginia.edu return defaultPortID; 35712137Sar4jc@virginia.edu } 35812137Sar4jc@virginia.edu } else if (defaultPortID != InvalidPortID) { 35912137Sar4jc@virginia.edu DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " 36012137Sar4jc@virginia.edu "will use default port\n", addr); 36112137Sar4jc@virginia.edu return defaultPortID; 36212137Sar4jc@virginia.edu } 36312137Sar4jc@virginia.edu 36412137Sar4jc@virginia.edu // we should use the range for the default port and it did not 36512137Sar4jc@virginia.edu // match, or the default port is not set 36612137Sar4jc@virginia.edu fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 36712137Sar4jc@virginia.edu name()); 36812137Sar4jc@virginia.edu} 36912137Sar4jc@virginia.edu 37012137Sar4jc@virginia.edu/** Function called by the port when the bus is receiving a range change.*/ 37112137Sar4jc@virginia.eduvoid 37212137Sar4jc@virginia.eduBaseBus::recvRangeChange(PortID master_port_id) 37312137Sar4jc@virginia.edu{ 37412137Sar4jc@virginia.edu DPRINTF(BusAddrRanges, "Received range change from slave port %s\n", 37512137Sar4jc@virginia.edu masterPorts[master_port_id]->getSlavePort().name()); 37612137Sar4jc@virginia.edu 37712137Sar4jc@virginia.edu // remember that we got a range from this master port and thus the 37812137Sar4jc@virginia.edu // connected slave module 37912137Sar4jc@virginia.edu gotAddrRanges[master_port_id] = true; 38012137Sar4jc@virginia.edu 38112137Sar4jc@virginia.edu // update the global flag 38212137Sar4jc@virginia.edu if (!gotAllAddrRanges) { 38312137Sar4jc@virginia.edu // take a logical AND of all the ports and see if we got 38412137Sar4jc@virginia.edu // ranges from everyone 38512137Sar4jc@virginia.edu gotAllAddrRanges = true; 38612137Sar4jc@virginia.edu std::vector<bool>::const_iterator r = gotAddrRanges.begin(); 38712137Sar4jc@virginia.edu while (gotAllAddrRanges && r != gotAddrRanges.end()) { 38812137Sar4jc@virginia.edu gotAllAddrRanges &= *r++; 38912137Sar4jc@virginia.edu } 39012137Sar4jc@virginia.edu if (gotAllAddrRanges) 39112137Sar4jc@virginia.edu DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n"); 39212137Sar4jc@virginia.edu } 39312137Sar4jc@virginia.edu 39412137Sar4jc@virginia.edu // note that we could get the range from the default port at any 39512137Sar4jc@virginia.edu // point in time, and we cannot assume that the default range is 39612137Sar4jc@virginia.edu // set before the other ones are, so we do additional checks once 39712137Sar4jc@virginia.edu // all ranges are provided 39812137Sar4jc@virginia.edu if (master_port_id == defaultPortID) { 39912137Sar4jc@virginia.edu // only update if we are indeed checking ranges for the 40012137Sar4jc@virginia.edu // default port since the port might not have a valid range 40112137Sar4jc@virginia.edu // otherwise 40212137Sar4jc@virginia.edu if (useDefaultRange) { 40312137Sar4jc@virginia.edu AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 40412137Sar4jc@virginia.edu 40512137Sar4jc@virginia.edu if (ranges.size() != 1) 40612137Sar4jc@virginia.edu fatal("Bus %s may only have a single default range", 40712137Sar4jc@virginia.edu name()); 40812137Sar4jc@virginia.edu 40912137Sar4jc@virginia.edu defaultRange = ranges.front(); 41012137Sar4jc@virginia.edu } 41112137Sar4jc@virginia.edu } else { 41212137Sar4jc@virginia.edu // the ports are allowed to update their address ranges 41312137Sar4jc@virginia.edu // dynamically, so remove any existing entries 41412137Sar4jc@virginia.edu if (gotAddrRanges[master_port_id]) { 41512137Sar4jc@virginia.edu for (PortMapIter p = portMap.begin(); p != portMap.end(); ) { 41612137Sar4jc@virginia.edu if (p->second == master_port_id) 41712137Sar4jc@virginia.edu // erasing invalidates the iterator, so advance it 41812137Sar4jc@virginia.edu // before the deletion takes place 41912137Sar4jc@virginia.edu portMap.erase(p++); 42012137Sar4jc@virginia.edu else 42112137Sar4jc@virginia.edu p++; 42212137Sar4jc@virginia.edu } 42312137Sar4jc@virginia.edu } 42412137Sar4jc@virginia.edu 42512137Sar4jc@virginia.edu AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 42612137Sar4jc@virginia.edu 42712137Sar4jc@virginia.edu for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) { 42812137Sar4jc@virginia.edu DPRINTF(BusAddrRanges, "Adding range %s for id %d\n", 42912137Sar4jc@virginia.edu r->to_string(), master_port_id); 43012137Sar4jc@virginia.edu if (portMap.insert(*r, master_port_id) == portMap.end()) { 43112137Sar4jc@virginia.edu PortID conflict_id = portMap.find(*r)->second; 43212137Sar4jc@virginia.edu fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 43312137Sar4jc@virginia.edu name(), 43412137Sar4jc@virginia.edu masterPorts[master_port_id]->getSlavePort().name(), 43512137Sar4jc@virginia.edu masterPorts[conflict_id]->getSlavePort().name()); 43612137Sar4jc@virginia.edu } 43712137Sar4jc@virginia.edu } 43812137Sar4jc@virginia.edu } 43912137Sar4jc@virginia.edu 44012137Sar4jc@virginia.edu // if we have received ranges from all our neighbouring slave 44112137Sar4jc@virginia.edu // modules, go ahead and tell our connected master modules in 44212137Sar4jc@virginia.edu // turn, this effectively assumes a tree structure of the system 44312137Sar4jc@virginia.edu if (gotAllAddrRanges) { 44412137Sar4jc@virginia.edu // also check that no range partially overlaps with the 44512137Sar4jc@virginia.edu // default range, this has to be done after all ranges are set 44612137Sar4jc@virginia.edu // as there are no guarantees for when the default range is 44712137Sar4jc@virginia.edu // update with respect to the other ones 44812137Sar4jc@virginia.edu if (useDefaultRange) { 44912137Sar4jc@virginia.edu for (PortID port_id = 0; port_id < masterPorts.size(); ++port_id) { 45012137Sar4jc@virginia.edu if (port_id == defaultPortID) { 45112137Sar4jc@virginia.edu if (!gotAddrRanges[port_id]) 45212137Sar4jc@virginia.edu fatal("Bus %s uses default range, but none provided", 45312137Sar4jc@virginia.edu name()); 45412137Sar4jc@virginia.edu } else { 45512137Sar4jc@virginia.edu AddrRangeList ranges = 45612137Sar4jc@virginia.edu masterPorts[port_id]->getAddrRanges(); 45712137Sar4jc@virginia.edu 45812137Sar4jc@virginia.edu for (AddrRangeConstIter r = ranges.begin(); 45912137Sar4jc@virginia.edu r != ranges.end(); ++r) { 46012137Sar4jc@virginia.edu // see if the new range is partially 46112137Sar4jc@virginia.edu // overlapping the default range 46212137Sar4jc@virginia.edu if (r->intersects(defaultRange) && 46312137Sar4jc@virginia.edu !r->isSubset(defaultRange)) 46412137Sar4jc@virginia.edu fatal("Range %s intersects the " \ 46512137Sar4jc@virginia.edu "default range of %s but is not a " \ 46612137Sar4jc@virginia.edu "subset\n", r->to_string(), name()); 46712137Sar4jc@virginia.edu } 46812137Sar4jc@virginia.edu } 46912137Sar4jc@virginia.edu } 47012137Sar4jc@virginia.edu } 47112137Sar4jc@virginia.edu 47212137Sar4jc@virginia.edu // tell all our neighbouring master ports that our address 47312137Sar4jc@virginia.edu // ranges have changed 47412137Sar4jc@virginia.edu for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 47512137Sar4jc@virginia.edu ++s) 47612137Sar4jc@virginia.edu (*s)->sendRangeChange(); 47712137Sar4jc@virginia.edu } 47812137Sar4jc@virginia.edu 47912137Sar4jc@virginia.edu clearPortCache(); 48012137Sar4jc@virginia.edu} 48112137Sar4jc@virginia.edu 48212137Sar4jc@virginia.eduAddrRangeList 48312137Sar4jc@virginia.eduBaseBus::getAddrRanges() const 48412137Sar4jc@virginia.edu{ 48512137Sar4jc@virginia.edu // we should never be asked without first having sent a range 48612137Sar4jc@virginia.edu // change, and the latter is only done once we have all the ranges 48712137Sar4jc@virginia.edu // of the connected devices 48812137Sar4jc@virginia.edu assert(gotAllAddrRanges); 48912137Sar4jc@virginia.edu 49012137Sar4jc@virginia.edu // at the moment, this never happens, as there are no cycles in 49112137Sar4jc@virginia.edu // the range queries and no devices on the master side of a bus 49212137Sar4jc@virginia.edu // (CPU, cache, bridge etc) actually care about the ranges of the 49312137Sar4jc@virginia.edu // ports they are connected to 49412137Sar4jc@virginia.edu 49512137Sar4jc@virginia.edu DPRINTF(BusAddrRanges, "Received address range request, returning:\n"); 49612137Sar4jc@virginia.edu 49712137Sar4jc@virginia.edu // start out with the default range 49812137Sar4jc@virginia.edu AddrRangeList ranges; 49912137Sar4jc@virginia.edu if (useDefaultRange) { 50012137Sar4jc@virginia.edu ranges.push_back(defaultRange); 50112137Sar4jc@virginia.edu DPRINTF(BusAddrRanges, " -- Default %s\n", defaultRange.to_string()); 50212137Sar4jc@virginia.edu } 50312137Sar4jc@virginia.edu 50412137Sar4jc@virginia.edu // add any range that is not a subset of the default range 50512137Sar4jc@virginia.edu for (PortMapConstIter p = portMap.begin(); p != portMap.end(); ++p) { 50612137Sar4jc@virginia.edu if (useDefaultRange && p->first.isSubset(defaultRange)) { 50712137Sar4jc@virginia.edu DPRINTF(BusAddrRanges, " -- %s is a subset of default\n", 50812137Sar4jc@virginia.edu p->first.to_string()); 50912137Sar4jc@virginia.edu } else { 51012137Sar4jc@virginia.edu ranges.push_back(p->first); 51112137Sar4jc@virginia.edu DPRINTF(BusAddrRanges, " -- %s\n", p->first.to_string()); 51212137Sar4jc@virginia.edu } 51312137Sar4jc@virginia.edu } 51412137Sar4jc@virginia.edu 51512137Sar4jc@virginia.edu return ranges; 51612137Sar4jc@virginia.edu} 51712137Sar4jc@virginia.edu 51812137Sar4jc@virginia.eduunsigned 51912137Sar4jc@virginia.eduBaseBus::deviceBlockSize() const 52012137Sar4jc@virginia.edu{ 52112137Sar4jc@virginia.edu return blockSize; 52212137Sar4jc@virginia.edu} 52312137Sar4jc@virginia.edu 52412137Sar4jc@virginia.edutemplate <typename PortClass> 52512137Sar4jc@virginia.eduunsigned int 52612137Sar4jc@virginia.eduBaseBus::Layer<PortClass>::drain(DrainManager *dm) 52712137Sar4jc@virginia.edu{ 52812137Sar4jc@virginia.edu //We should check that we're not "doing" anything, and that noone is 52912137Sar4jc@virginia.edu //waiting. We might be idle but have someone waiting if the device we 53012137Sar4jc@virginia.edu //contacted for a retry didn't actually retry. 53112137Sar4jc@virginia.edu if (!retryList.empty() || state != IDLE) { 53212137Sar4jc@virginia.edu DPRINTF(Drain, "Bus not drained\n"); 53312137Sar4jc@virginia.edu drainManager = dm; 53412137Sar4jc@virginia.edu return 1; 53512137Sar4jc@virginia.edu } 53612137Sar4jc@virginia.edu return 0; 53712137Sar4jc@virginia.edu} 53812137Sar4jc@virginia.edu 53912137Sar4jc@virginia.edu/** 54012137Sar4jc@virginia.edu * Bus layer template instantiations. Could be removed with _impl.hh 54112137Sar4jc@virginia.edu * file, but since there are only two given options (MasterPort and 54212137Sar4jc@virginia.edu * SlavePort) it seems a bit excessive at this point. 54312137Sar4jc@virginia.edu */ 54412137Sar4jc@virginia.edutemplate class BaseBus::Layer<SlavePort>; 54512137Sar4jc@virginia.edutemplate class BaseBus::Layer<MasterPort>; 54612137Sar4jc@virginia.edu