xbar.cc revision 9547
14120Sgblack@eecs.umich.edu/* 24120Sgblack@eecs.umich.edu * Copyright (c) 2011-2013 ARM Limited 37087Snate@binkert.org * All rights reserved 47087Snate@binkert.org * 57087Snate@binkert.org * The license below extends only to copyright in the software and shall 67087Snate@binkert.org * not be construed as granting a license to any other intellectual 77087Snate@binkert.org * property including but not limited to intellectual property relating 87087Snate@binkert.org * to a hardware implementation of the functionality of the software 97087Snate@binkert.org * licensed hereunder. You may use the software subject to the license 107087Snate@binkert.org * terms below provided that you ensure that this notice is replicated 117087Snate@binkert.org * unmodified and in its entirety in all distributions of the software, 127087Snate@binkert.org * modified or unmodified, in source code or in binary form. 137087Snate@binkert.org * 147087Snate@binkert.org * Copyright (c) 2006 The Regents of The University of Michigan 154120Sgblack@eecs.umich.edu * All rights reserved. 164120Sgblack@eecs.umich.edu * 174120Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 184120Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 194120Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 204120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 214120Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 224120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 234120Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 244120Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 254120Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 264120Sgblack@eecs.umich.edu * this software without specific prior written permission. 274120Sgblack@eecs.umich.edu * 284120Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 294120Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 304120Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 314120Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 324120Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 334120Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 344120Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 354120Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 364120Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 374120Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 384120Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 394120Sgblack@eecs.umich.edu * 404120Sgblack@eecs.umich.edu * Authors: Ali Saidi 414120Sgblack@eecs.umich.edu * Andreas Hansson 424120Sgblack@eecs.umich.edu * William Wang 434202Sbinkertn@umich.edu */ 445069Sgblack@eecs.umich.edu 454202Sbinkertn@umich.edu/** 465659Sgblack@eecs.umich.edu * @file 479022Sgblack@eecs.umich.edu * Definition of a bus object. 489023Sgblack@eecs.umich.edu */ 494601Sgblack@eecs.umich.edu 505124Sgblack@eecs.umich.edu#include "base/misc.hh" 517966Sgblack@eecs.umich.edu#include "base/trace.hh" 525083Sgblack@eecs.umich.edu#include "debug/Bus.hh" 534679Sgblack@eecs.umich.edu#include "debug/BusAddrRanges.hh" 546515Sgblack@eecs.umich.edu#include "debug/Drain.hh" 555083Sgblack@eecs.umich.edu#include "mem/bus.hh" 564679Sgblack@eecs.umich.edu 574679Sgblack@eecs.umich.eduBaseBus::BaseBus(const BaseBusParams *p) 588745Sgblack@eecs.umich.edu : MemObject(p), 596313Sgblack@eecs.umich.edu headerCycles(p->header_cycles), width(p->width), 608771Sgblack@eecs.umich.edu gotAddrRanges(p->port_default_connection_count + 618771Sgblack@eecs.umich.edu p->port_master_connection_count, false), 628771Sgblack@eecs.umich.edu gotAllAddrRanges(false), defaultPortID(InvalidPortID), 638771Sgblack@eecs.umich.edu useDefaultRange(p->use_default_range), 646365Sgblack@eecs.umich.edu blockSize(p->block_size) 655124Sgblack@eecs.umich.edu{} 668752Sgblack@eecs.umich.edu 678771Sgblack@eecs.umich.eduBaseBus::~BaseBus() 684202Sbinkertn@umich.edu{ 698771Sgblack@eecs.umich.edu for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); 708771Sgblack@eecs.umich.edu ++m) { 714997Sgblack@eecs.umich.edu delete *m; 727624Sgblack@eecs.umich.edu } 735135Sgblack@eecs.umich.edu 748753Sgblack@eecs.umich.edu for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); 754997Sgblack@eecs.umich.edu ++s) { 769384SAndreas.Sandberg@arm.com delete *s; 778745Sgblack@eecs.umich.edu } 786365Sgblack@eecs.umich.edu} 798771Sgblack@eecs.umich.edu 808740Sgblack@eecs.umich.eduvoid 816365Sgblack@eecs.umich.eduBaseBus::init() 828740Sgblack@eecs.umich.edu{ 838745Sgblack@eecs.umich.edu // determine the maximum peer block size, look at both the 848752Sgblack@eecs.umich.edu // connected master and slave modules 858752Sgblack@eecs.umich.edu uint32_t peer_block_size = 0; 869023Sgblack@eecs.umich.edu 878335Snate@binkert.org for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); 884120Sgblack@eecs.umich.edu ++m) { 895069Sgblack@eecs.umich.edu peer_block_size = std::max((*m)->peerBlockSize(), peer_block_size); 905081Sgblack@eecs.umich.edu } 915081Sgblack@eecs.umich.edu 925081Sgblack@eecs.umich.edu for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 935081Sgblack@eecs.umich.edu ++s) { 945081Sgblack@eecs.umich.edu peer_block_size = std::max((*s)->peerBlockSize(), peer_block_size); 955081Sgblack@eecs.umich.edu } 965081Sgblack@eecs.umich.edu 975081Sgblack@eecs.umich.edu // if the peers do not have a block size, use the default value 985081Sgblack@eecs.umich.edu // set through the bus parameters 995081Sgblack@eecs.umich.edu if (peer_block_size != 0) 1005081Sgblack@eecs.umich.edu blockSize = peer_block_size; 1015081Sgblack@eecs.umich.edu 1025081Sgblack@eecs.umich.edu // check if the block size is a value known to work 1035081Sgblack@eecs.umich.edu if (!(blockSize == 16 || blockSize == 32 || blockSize == 64 || 1045081Sgblack@eecs.umich.edu blockSize == 128)) 1055081Sgblack@eecs.umich.edu warn_once("Block size is neither 16, 32, 64 or 128 bytes.\n"); 1065081Sgblack@eecs.umich.edu} 1075081Sgblack@eecs.umich.edu 1085081Sgblack@eecs.umich.eduBaseMasterPort & 1095081Sgblack@eecs.umich.eduBaseBus::getMasterPort(const std::string &if_name, PortID idx) 1105081Sgblack@eecs.umich.edu{ 1115081Sgblack@eecs.umich.edu if (if_name == "master" && idx < masterPorts.size()) { 1125081Sgblack@eecs.umich.edu // the master port index translates directly to the vector position 1135081Sgblack@eecs.umich.edu return *masterPorts[idx]; 1145081Sgblack@eecs.umich.edu } else if (if_name == "default") { 1155081Sgblack@eecs.umich.edu return *masterPorts[defaultPortID]; 1165081Sgblack@eecs.umich.edu } else { 1175081Sgblack@eecs.umich.edu return MemObject::getMasterPort(if_name, idx); 1185081Sgblack@eecs.umich.edu } 1195081Sgblack@eecs.umich.edu} 1205081Sgblack@eecs.umich.edu 1215081Sgblack@eecs.umich.eduBaseSlavePort & 1225081Sgblack@eecs.umich.eduBaseBus::getSlavePort(const std::string &if_name, PortID idx) 1235081Sgblack@eecs.umich.edu{ 1245081Sgblack@eecs.umich.edu if (if_name == "slave" && idx < slavePorts.size()) { 1255081Sgblack@eecs.umich.edu // the slave port index translates directly to the vector position 1265081Sgblack@eecs.umich.edu return *slavePorts[idx]; 1275081Sgblack@eecs.umich.edu } else { 1285081Sgblack@eecs.umich.edu return MemObject::getSlavePort(if_name, idx); 1295081Sgblack@eecs.umich.edu } 1305081Sgblack@eecs.umich.edu} 1315081Sgblack@eecs.umich.edu 1325081Sgblack@eecs.umich.eduvoid 1335081Sgblack@eecs.umich.eduBaseBus::calcPacketTiming(PacketPtr pkt) 1345081Sgblack@eecs.umich.edu{ 1355081Sgblack@eecs.umich.edu // the bus will be called at a time that is not necessarily 1365081Sgblack@eecs.umich.edu // coinciding with its own clock, so start by determining how long 1375081Sgblack@eecs.umich.edu // until the next clock edge (could be zero) 1385081Sgblack@eecs.umich.edu Tick offset = nextCycle() - curTick(); 1395081Sgblack@eecs.umich.edu 1405081Sgblack@eecs.umich.edu // determine how many cycles are needed to send the data 1415081Sgblack@eecs.umich.edu unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0; 1425081Sgblack@eecs.umich.edu 1435081Sgblack@eecs.umich.edu // The first word will be delivered on the cycle after the header. 1445081Sgblack@eecs.umich.edu pkt->busFirstWordDelay = (headerCycles + 1) * clockPeriod() + offset; 1455680Sgblack@eecs.umich.edu 1465081Sgblack@eecs.umich.edu // Note that currently busLastWordDelay can be smaller than 1475933Sgblack@eecs.umich.edu // busFirstWordDelay if the packet has no data 1485173Sgblack@eecs.umich.edu pkt->busLastWordDelay = (headerCycles + dataCycles) * clockPeriod() + 1495359Sgblack@eecs.umich.edu offset; 1505081Sgblack@eecs.umich.edu} 1515149Sgblack@eecs.umich.edu 1525298Sgblack@eecs.umich.edutemplate <typename PortClass> 1535081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name) : 1545081Sgblack@eecs.umich.edu Drainable(), 1555081Sgblack@eecs.umich.edu bus(_bus), _name(_name), state(IDLE), drainManager(NULL), 1565081Sgblack@eecs.umich.edu releaseEvent(this) 1575081Sgblack@eecs.umich.edu{ 1585081Sgblack@eecs.umich.edu} 1595081Sgblack@eecs.umich.edu 1605081Sgblack@eecs.umich.edutemplate <typename PortClass> 1615081Sgblack@eecs.umich.eduvoid BaseBus::Layer<PortClass>::occupyLayer(Tick until) 1625081Sgblack@eecs.umich.edu{ 1635081Sgblack@eecs.umich.edu // ensure the state is busy or in retry and never idle at this 1645081Sgblack@eecs.umich.edu // point, as the bus should transition from idle as soon as it has 1655081Sgblack@eecs.umich.edu // decided to forward the packet to prevent any follow-on calls to 1665081Sgblack@eecs.umich.edu // sendTiming seeing an unoccupied bus 1675081Sgblack@eecs.umich.edu assert(state != IDLE); 1685081Sgblack@eecs.umich.edu 1695081Sgblack@eecs.umich.edu // note that we do not change the bus state here, if we are going 1705081Sgblack@eecs.umich.edu // from idle to busy it is handled by tryTiming, and if we 1715081Sgblack@eecs.umich.edu // are in retry we should remain in retry such that 1725081Sgblack@eecs.umich.edu // succeededTiming still sees the accurate state 1735081Sgblack@eecs.umich.edu 1745081Sgblack@eecs.umich.edu // until should never be 0 as express snoops never occupy the bus 1755081Sgblack@eecs.umich.edu assert(until != 0); 1765081Sgblack@eecs.umich.edu bus.schedule(releaseEvent, until); 1775081Sgblack@eecs.umich.edu 1785081Sgblack@eecs.umich.edu DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", 1795081Sgblack@eecs.umich.edu curTick(), until); 1805081Sgblack@eecs.umich.edu} 1815081Sgblack@eecs.umich.edu 1825081Sgblack@eecs.umich.edutemplate <typename PortClass> 1835081Sgblack@eecs.umich.edubool 1845081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::tryTiming(PortClass* port) 1855081Sgblack@eecs.umich.edu{ 1865081Sgblack@eecs.umich.edu // first we see if the bus is busy, next we check if we are in a 1875081Sgblack@eecs.umich.edu // retry with a port other than the current one 1885081Sgblack@eecs.umich.edu if (state == BUSY || (state == RETRY && port != retryList.front())) { 1895081Sgblack@eecs.umich.edu // put the port at the end of the retry list 1905081Sgblack@eecs.umich.edu retryList.push_back(port); 1915081Sgblack@eecs.umich.edu return false; 1925081Sgblack@eecs.umich.edu } 1935081Sgblack@eecs.umich.edu 1945081Sgblack@eecs.umich.edu // update the state which is shared for request, response and 1955081Sgblack@eecs.umich.edu // snoop responses, if we were idle we are now busy, if we are in 1965081Sgblack@eecs.umich.edu // a retry, then do not change 1975081Sgblack@eecs.umich.edu if (state == IDLE) 1985081Sgblack@eecs.umich.edu state = BUSY; 1995081Sgblack@eecs.umich.edu 2005081Sgblack@eecs.umich.edu return true; 2015081Sgblack@eecs.umich.edu} 2025081Sgblack@eecs.umich.edu 2035081Sgblack@eecs.umich.edutemplate <typename PortClass> 2045081Sgblack@eecs.umich.eduvoid 2055081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::succeededTiming(Tick busy_time) 2065081Sgblack@eecs.umich.edu{ 2075081Sgblack@eecs.umich.edu // if a retrying port succeeded, also take it off the retry list 2085081Sgblack@eecs.umich.edu if (state == RETRY) { 2095081Sgblack@eecs.umich.edu DPRINTF(BaseBus, "Remove retry from list %s\n", 2105081Sgblack@eecs.umich.edu retryList.front()->name()); 2115081Sgblack@eecs.umich.edu retryList.pop_front(); 2125081Sgblack@eecs.umich.edu state = BUSY; 2135081Sgblack@eecs.umich.edu } 2145081Sgblack@eecs.umich.edu 2155081Sgblack@eecs.umich.edu // we should either have gone from idle to busy in the 2165081Sgblack@eecs.umich.edu // tryTiming test, or just gone from a retry to busy 2175081Sgblack@eecs.umich.edu assert(state == BUSY); 2185081Sgblack@eecs.umich.edu 2195081Sgblack@eecs.umich.edu // occupy the bus accordingly 2205081Sgblack@eecs.umich.edu occupyLayer(busy_time); 2215081Sgblack@eecs.umich.edu} 2225081Sgblack@eecs.umich.edu 2235081Sgblack@eecs.umich.edutemplate <typename PortClass> 2245081Sgblack@eecs.umich.eduvoid 2255081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time) 2265081Sgblack@eecs.umich.edu{ 2275081Sgblack@eecs.umich.edu // if we are not in a retry, i.e. busy (but never idle), or we are 2285081Sgblack@eecs.umich.edu // in a retry but not for the current port, then add the port at 2295081Sgblack@eecs.umich.edu // the end of the retry list 2305081Sgblack@eecs.umich.edu if (state != RETRY || port != retryList.front()) { 2315081Sgblack@eecs.umich.edu retryList.push_back(port); 2325081Sgblack@eecs.umich.edu } 2335081Sgblack@eecs.umich.edu 2345081Sgblack@eecs.umich.edu // even if we retried the current one and did not succeed, 2355081Sgblack@eecs.umich.edu // we are no longer retrying but instead busy 2365081Sgblack@eecs.umich.edu state = BUSY; 2375081Sgblack@eecs.umich.edu 2385081Sgblack@eecs.umich.edu // occupy the bus accordingly 2395081Sgblack@eecs.umich.edu occupyLayer(busy_time); 2405081Sgblack@eecs.umich.edu} 2415081Sgblack@eecs.umich.edu 2425081Sgblack@eecs.umich.edutemplate <typename PortClass> 2435081Sgblack@eecs.umich.eduvoid 2445081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::releaseLayer() 2455081Sgblack@eecs.umich.edu{ 2465081Sgblack@eecs.umich.edu // releasing the bus means we should now be idle 2475081Sgblack@eecs.umich.edu assert(state == BUSY); 2485081Sgblack@eecs.umich.edu assert(!releaseEvent.scheduled()); 2495081Sgblack@eecs.umich.edu 2505081Sgblack@eecs.umich.edu // update the state 2515081Sgblack@eecs.umich.edu state = IDLE; 2525081Sgblack@eecs.umich.edu 2535081Sgblack@eecs.umich.edu // bus is now idle, so if someone is waiting we can retry 2545081Sgblack@eecs.umich.edu if (!retryList.empty()) { 2555081Sgblack@eecs.umich.edu // note that we block (return false on recvTiming) both 2565081Sgblack@eecs.umich.edu // because the bus is busy and because the destination is 2575081Sgblack@eecs.umich.edu // busy, and in the latter case the bus may be released before 2585081Sgblack@eecs.umich.edu // we see a retry from the destination 2595081Sgblack@eecs.umich.edu retryWaiting(); 2605081Sgblack@eecs.umich.edu } else if (drainManager) { 2615081Sgblack@eecs.umich.edu DPRINTF(Drain, "Bus done draining, signaling drain manager\n"); 2625081Sgblack@eecs.umich.edu //If we weren't able to drain before, do it now. 2635081Sgblack@eecs.umich.edu drainManager->signalDrainDone(); 2645081Sgblack@eecs.umich.edu // Clear the drain event once we're done with it. 2655081Sgblack@eecs.umich.edu drainManager = NULL; 2665081Sgblack@eecs.umich.edu } 2675081Sgblack@eecs.umich.edu} 2685081Sgblack@eecs.umich.edu 2695081Sgblack@eecs.umich.edutemplate <typename PortClass> 2705081Sgblack@eecs.umich.eduvoid 2715081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::retryWaiting() 2725081Sgblack@eecs.umich.edu{ 2735081Sgblack@eecs.umich.edu // this should never be called with an empty retry list 2745081Sgblack@eecs.umich.edu assert(!retryList.empty()); 2755081Sgblack@eecs.umich.edu 2765081Sgblack@eecs.umich.edu // we always go to retrying from idle 2775081Sgblack@eecs.umich.edu assert(state == IDLE); 2785081Sgblack@eecs.umich.edu 2795081Sgblack@eecs.umich.edu // update the state which is shared for request, response and 2805081Sgblack@eecs.umich.edu // snoop responses 2815081Sgblack@eecs.umich.edu state = RETRY; 2825081Sgblack@eecs.umich.edu 2835081Sgblack@eecs.umich.edu // note that we might have blocked on the receiving port being 2845081Sgblack@eecs.umich.edu // busy (rather than the bus itself) and now call retry before the 2855081Sgblack@eecs.umich.edu // destination called retry on the bus 2865081Sgblack@eecs.umich.edu retryList.front()->sendRetry(); 2875081Sgblack@eecs.umich.edu 2885081Sgblack@eecs.umich.edu // If the bus is still in the retry state, sendTiming wasn't 2895081Sgblack@eecs.umich.edu // called in zero time (e.g. the cache does this) 2905081Sgblack@eecs.umich.edu if (state == RETRY) { 2915081Sgblack@eecs.umich.edu retryList.pop_front(); 2925081Sgblack@eecs.umich.edu 2935081Sgblack@eecs.umich.edu //Burn a cycle for the missed grant. 2945081Sgblack@eecs.umich.edu 2955081Sgblack@eecs.umich.edu // update the state which is shared for request, response and 2965081Sgblack@eecs.umich.edu // snoop responses 2975081Sgblack@eecs.umich.edu state = BUSY; 2985081Sgblack@eecs.umich.edu 2995081Sgblack@eecs.umich.edu // occupy the bus layer until the next cycle ends 3005081Sgblack@eecs.umich.edu occupyLayer(bus.clockEdge(Cycles(1))); 3015081Sgblack@eecs.umich.edu } 3025081Sgblack@eecs.umich.edu} 3035081Sgblack@eecs.umich.edu 3045081Sgblack@eecs.umich.edutemplate <typename PortClass> 3055081Sgblack@eecs.umich.eduvoid 3065081Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::recvRetry() 3075081Sgblack@eecs.umich.edu{ 3085069Sgblack@eecs.umich.edu // we got a retry from a peer that we tried to send something to 3094202Sbinkertn@umich.edu // and failed, but we sent it on the account of someone else, and 3104202Sbinkertn@umich.edu // that source port should be on our retry list, however if the 3114202Sbinkertn@umich.edu // bus layer is released before this happens and the retry (from 3125069Sgblack@eecs.umich.edu // the bus point of view) is successful then this no longer holds 3135069Sgblack@eecs.umich.edu // and we could in fact have an empty retry list 3145069Sgblack@eecs.umich.edu if (retryList.empty()) 315 return; 316 317 // if the bus layer is idle 318 if (state == IDLE) { 319 // note that we do not care who told us to retry at the moment, we 320 // merely let the first one on the retry list go 321 retryWaiting(); 322 } 323} 324 325PortID 326BaseBus::findPort(Addr addr) 327{ 328 // we should never see any address lookups before we've got the 329 // ranges of all connected slave modules 330 assert(gotAllAddrRanges); 331 332 // Check the cache 333 PortID dest_id = checkPortCache(addr); 334 if (dest_id != InvalidPortID) 335 return dest_id; 336 337 // Check the address map interval tree 338 PortMapConstIter i = portMap.find(addr); 339 if (i != portMap.end()) { 340 dest_id = i->second; 341 updatePortCache(dest_id, i->first); 342 return dest_id; 343 } 344 345 // Check if this matches the default range 346 if (useDefaultRange) { 347 if (defaultRange.contains(addr)) { 348 DPRINTF(BusAddrRanges, " found addr %#llx on default\n", 349 addr); 350 return defaultPortID; 351 } 352 } else if (defaultPortID != InvalidPortID) { 353 DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " 354 "will use default port\n", addr); 355 return defaultPortID; 356 } 357 358 // we should use the range for the default port and it did not 359 // match, or the default port is not set 360 fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 361 name()); 362} 363 364/** Function called by the port when the bus is receiving a range change.*/ 365void 366BaseBus::recvRangeChange(PortID master_port_id) 367{ 368 DPRINTF(BusAddrRanges, "Received range change from slave port %s\n", 369 masterPorts[master_port_id]->getSlavePort().name()); 370 371 // remember that we got a range from this master port and thus the 372 // connected slave module 373 gotAddrRanges[master_port_id] = true; 374 375 // update the global flag 376 if (!gotAllAddrRanges) { 377 // take a logical AND of all the ports and see if we got 378 // ranges from everyone 379 gotAllAddrRanges = true; 380 std::vector<bool>::const_iterator r = gotAddrRanges.begin(); 381 while (gotAllAddrRanges && r != gotAddrRanges.end()) { 382 gotAllAddrRanges &= *r++; 383 } 384 if (gotAllAddrRanges) 385 DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n"); 386 } 387 388 // note that we could get the range from the default port at any 389 // point in time, and we cannot assume that the default range is 390 // set before the other ones are, so we do additional checks once 391 // all ranges are provided 392 if (master_port_id == defaultPortID) { 393 // only update if we are indeed checking ranges for the 394 // default port since the port might not have a valid range 395 // otherwise 396 if (useDefaultRange) { 397 AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 398 399 if (ranges.size() != 1) 400 fatal("Bus %s may only have a single default range", 401 name()); 402 403 defaultRange = ranges.front(); 404 } 405 } else { 406 // the ports are allowed to update their address ranges 407 // dynamically, so remove any existing entries 408 if (gotAddrRanges[master_port_id]) { 409 for (PortMapIter p = portMap.begin(); p != portMap.end(); ) { 410 if (p->second == master_port_id) 411 // erasing invalidates the iterator, so advance it 412 // before the deletion takes place 413 portMap.erase(p++); 414 else 415 p++; 416 } 417 } 418 419 AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 420 421 for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) { 422 DPRINTF(BusAddrRanges, "Adding range %s for id %d\n", 423 r->to_string(), master_port_id); 424 if (portMap.insert(*r, master_port_id) == portMap.end()) { 425 PortID conflict_id = portMap.find(*r)->second; 426 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 427 name(), 428 masterPorts[master_port_id]->getSlavePort().name(), 429 masterPorts[conflict_id]->getSlavePort().name()); 430 } 431 } 432 } 433 434 // if we have received ranges from all our neighbouring slave 435 // modules, go ahead and tell our connected master modules in 436 // turn, this effectively assumes a tree structure of the system 437 if (gotAllAddrRanges) { 438 // also check that no range partially overlaps with the 439 // default range, this has to be done after all ranges are set 440 // as there are no guarantees for when the default range is 441 // update with respect to the other ones 442 if (useDefaultRange) { 443 for (PortID port_id = 0; port_id < masterPorts.size(); ++port_id) { 444 if (port_id == defaultPortID) { 445 if (!gotAddrRanges[port_id]) 446 fatal("Bus %s uses default range, but none provided", 447 name()); 448 } else { 449 AddrRangeList ranges = 450 masterPorts[port_id]->getAddrRanges(); 451 452 for (AddrRangeConstIter r = ranges.begin(); 453 r != ranges.end(); ++r) { 454 // see if the new range is partially 455 // overlapping the default range 456 if (r->intersects(defaultRange) && 457 !r->isSubset(defaultRange)) 458 fatal("Range %s intersects the " \ 459 "default range of %s but is not a " \ 460 "subset\n", r->to_string(), name()); 461 } 462 } 463 } 464 } 465 466 // tell all our neighbouring master ports that our address 467 // ranges have changed 468 for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 469 ++s) 470 (*s)->sendRangeChange(); 471 } 472 473 clearPortCache(); 474} 475 476AddrRangeList 477BaseBus::getAddrRanges() const 478{ 479 // we should never be asked without first having sent a range 480 // change, and the latter is only done once we have all the ranges 481 // of the connected devices 482 assert(gotAllAddrRanges); 483 484 // at the moment, this never happens, as there are no cycles in 485 // the range queries and no devices on the master side of a bus 486 // (CPU, cache, bridge etc) actually care about the ranges of the 487 // ports they are connected to 488 489 DPRINTF(BusAddrRanges, "Received address range request, returning:\n"); 490 491 // start out with the default range 492 AddrRangeList ranges; 493 if (useDefaultRange) { 494 ranges.push_back(defaultRange); 495 DPRINTF(BusAddrRanges, " -- Default %s\n", defaultRange.to_string()); 496 } 497 498 // add any range that is not a subset of the default range 499 for (PortMapConstIter p = portMap.begin(); p != portMap.end(); ++p) { 500 if (useDefaultRange && p->first.isSubset(defaultRange)) { 501 DPRINTF(BusAddrRanges, " -- %s is a subset of default\n", 502 p->first.to_string()); 503 } else { 504 ranges.push_back(p->first); 505 DPRINTF(BusAddrRanges, " -- %s\n", p->first.to_string()); 506 } 507 } 508 509 return ranges; 510} 511 512unsigned 513BaseBus::deviceBlockSize() const 514{ 515 return blockSize; 516} 517 518template <typename PortClass> 519unsigned int 520BaseBus::Layer<PortClass>::drain(DrainManager *dm) 521{ 522 //We should check that we're not "doing" anything, and that noone is 523 //waiting. We might be idle but have someone waiting if the device we 524 //contacted for a retry didn't actually retry. 525 if (!retryList.empty() || state != IDLE) { 526 DPRINTF(Drain, "Bus not drained\n"); 527 drainManager = dm; 528 return 1; 529 } 530 return 0; 531} 532 533/** 534 * Bus layer template instantiations. Could be removed with _impl.hh 535 * file, but since there are only two given options (MasterPort and 536 * SlavePort) it seems a bit excessive at this point. 537 */ 538template class BaseBus::Layer<SlavePort>; 539template class BaseBus::Layer<MasterPort>; 540