xbar.cc revision 9612
15647Sgblack@eecs.umich.edu/* 25647Sgblack@eecs.umich.edu * Copyright (c) 2011-2013 ARM Limited 35647Sgblack@eecs.umich.edu * All rights reserved 45647Sgblack@eecs.umich.edu * 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. 135647Sgblack@eecs.umich.edu * 147087Snate@binkert.org * Copyright (c) 2006 The Regents of The University of Michigan 157087Snate@binkert.org * All rights reserved. 167087Snate@binkert.org * 177087Snate@binkert.org * Redistribution and use in source and binary forms, with or without 187087Snate@binkert.org * modification, are permitted provided that the following conditions are 197087Snate@binkert.org * met: redistributions of source code must retain the above copyright 207087Snate@binkert.org * notice, this list of conditions and the following disclaimer; 217087Snate@binkert.org * redistributions in binary form must reproduce the above copyright 225647Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 237087Snate@binkert.org * documentation and/or other materials provided with the distribution; 245647Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 255647Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 265647Sgblack@eecs.umich.edu * this software without specific prior written permission. 275647Sgblack@eecs.umich.edu * 285647Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 295647Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 305647Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 315647Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 325647Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 335647Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 345647Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 355647Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 365647Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 375647Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 385647Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 395647Sgblack@eecs.umich.edu * 408229Snate@binkert.org * Authors: Ali Saidi 415647Sgblack@eecs.umich.edu * Andreas Hansson 425654Sgblack@eecs.umich.edu * William Wang 435647Sgblack@eecs.umich.edu */ 446137Sgblack@eecs.umich.edu 456137Sgblack@eecs.umich.edu/** 466137Sgblack@eecs.umich.edu * @file 475654Sgblack@eecs.umich.edu * Definition of a bus object. 486046Sgblack@eecs.umich.edu */ 495647Sgblack@eecs.umich.edu 505648Sgblack@eecs.umich.edu#include "base/misc.hh" 515648Sgblack@eecs.umich.edu#include "base/trace.hh" 525647Sgblack@eecs.umich.edu#include "debug/Bus.hh" 535647Sgblack@eecs.umich.edu#include "debug/BusAddrRanges.hh" 545647Sgblack@eecs.umich.edu#include "debug/Drain.hh" 555647Sgblack@eecs.umich.edu#include "mem/bus.hh" 565647Sgblack@eecs.umich.edu 575647Sgblack@eecs.umich.eduBaseBus::BaseBus(const BaseBusParams *p) 585647Sgblack@eecs.umich.edu : MemObject(p), 595647Sgblack@eecs.umich.edu headerCycles(p->header_cycles), width(p->width), 605647Sgblack@eecs.umich.edu gotAddrRanges(p->port_default_connection_count + 615648Sgblack@eecs.umich.edu p->port_master_connection_count, false), 625647Sgblack@eecs.umich.edu gotAllAddrRanges(false), defaultPortID(InvalidPortID), 635648Sgblack@eecs.umich.edu useDefaultRange(p->use_default_range), 645648Sgblack@eecs.umich.edu blockSize(p->block_size) 655648Sgblack@eecs.umich.edu{} 665648Sgblack@eecs.umich.edu 675648Sgblack@eecs.umich.eduBaseBus::~BaseBus() 685648Sgblack@eecs.umich.edu{ 695648Sgblack@eecs.umich.edu for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); 705648Sgblack@eecs.umich.edu ++m) { 715648Sgblack@eecs.umich.edu delete *m; 725648Sgblack@eecs.umich.edu } 735648Sgblack@eecs.umich.edu 745648Sgblack@eecs.umich.edu for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); 755648Sgblack@eecs.umich.edu ++s) { 765648Sgblack@eecs.umich.edu delete *s; 775648Sgblack@eecs.umich.edu } 785648Sgblack@eecs.umich.edu} 795648Sgblack@eecs.umich.edu 805648Sgblack@eecs.umich.eduvoid 815648Sgblack@eecs.umich.eduBaseBus::init() 825648Sgblack@eecs.umich.edu{ 835648Sgblack@eecs.umich.edu // determine the maximum peer block size, look at both the 845648Sgblack@eecs.umich.edu // connected master and slave modules 855648Sgblack@eecs.umich.edu uint32_t peer_block_size = 0; 865648Sgblack@eecs.umich.edu 875648Sgblack@eecs.umich.edu for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); 885648Sgblack@eecs.umich.edu ++m) { 895648Sgblack@eecs.umich.edu peer_block_size = std::max((*m)->peerBlockSize(), peer_block_size); 905648Sgblack@eecs.umich.edu } 915648Sgblack@eecs.umich.edu 925648Sgblack@eecs.umich.edu for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 935648Sgblack@eecs.umich.edu ++s) { 945648Sgblack@eecs.umich.edu peer_block_size = std::max((*s)->peerBlockSize(), peer_block_size); 955648Sgblack@eecs.umich.edu } 965648Sgblack@eecs.umich.edu 975648Sgblack@eecs.umich.edu // if the peers do not have a block size, use the default value 985648Sgblack@eecs.umich.edu // set through the bus parameters 995648Sgblack@eecs.umich.edu if (peer_block_size != 0) 1005648Sgblack@eecs.umich.edu blockSize = peer_block_size; 1015648Sgblack@eecs.umich.edu 1025648Sgblack@eecs.umich.edu // check if the block size is a value known to work 1035648Sgblack@eecs.umich.edu if (!(blockSize == 16 || blockSize == 32 || blockSize == 64 || 1045648Sgblack@eecs.umich.edu blockSize == 128)) 1055648Sgblack@eecs.umich.edu warn_once("Block size is neither 16, 32, 64 or 128 bytes.\n"); 1065648Sgblack@eecs.umich.edu} 1075648Sgblack@eecs.umich.edu 1085648Sgblack@eecs.umich.eduBaseMasterPort & 1095648Sgblack@eecs.umich.eduBaseBus::getMasterPort(const std::string &if_name, PortID idx) 1105648Sgblack@eecs.umich.edu{ 1115648Sgblack@eecs.umich.edu if (if_name == "master" && idx < masterPorts.size()) { 1125648Sgblack@eecs.umich.edu // the master port index translates directly to the vector position 1135648Sgblack@eecs.umich.edu return *masterPorts[idx]; 1145648Sgblack@eecs.umich.edu } else if (if_name == "default") { 1155648Sgblack@eecs.umich.edu return *masterPorts[defaultPortID]; 1165648Sgblack@eecs.umich.edu } else { 1175648Sgblack@eecs.umich.edu return MemObject::getMasterPort(if_name, idx); 1185648Sgblack@eecs.umich.edu } 1195648Sgblack@eecs.umich.edu} 1205648Sgblack@eecs.umich.edu 1215648Sgblack@eecs.umich.eduBaseSlavePort & 1225648Sgblack@eecs.umich.eduBaseBus::getSlavePort(const std::string &if_name, PortID idx) 1235648Sgblack@eecs.umich.edu{ 1245648Sgblack@eecs.umich.edu if (if_name == "slave" && idx < slavePorts.size()) { 1255648Sgblack@eecs.umich.edu // the slave port index translates directly to the vector position 1265648Sgblack@eecs.umich.edu return *slavePorts[idx]; 1275648Sgblack@eecs.umich.edu } else { 1285648Sgblack@eecs.umich.edu return MemObject::getSlavePort(if_name, idx); 1295648Sgblack@eecs.umich.edu } 1305648Sgblack@eecs.umich.edu} 1315648Sgblack@eecs.umich.edu 1325648Sgblack@eecs.umich.eduvoid 1335648Sgblack@eecs.umich.eduBaseBus::calcPacketTiming(PacketPtr pkt) 1345648Sgblack@eecs.umich.edu{ 1355648Sgblack@eecs.umich.edu // the bus will be called at a time that is not necessarily 1365648Sgblack@eecs.umich.edu // coinciding with its own clock, so start by determining how long 1375648Sgblack@eecs.umich.edu // until the next clock edge (could be zero) 1385648Sgblack@eecs.umich.edu Tick offset = nextCycle() - curTick(); 1395648Sgblack@eecs.umich.edu 1405648Sgblack@eecs.umich.edu // determine how many cycles are needed to send the data 1415648Sgblack@eecs.umich.edu unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0; 1425648Sgblack@eecs.umich.edu 1435648Sgblack@eecs.umich.edu // before setting the bus delay fields of the packet, ensure that 1445648Sgblack@eecs.umich.edu // the delay from any previous bus has been accounted for 1455648Sgblack@eecs.umich.edu if (pkt->busFirstWordDelay != 0 || pkt->busLastWordDelay != 0) 1465648Sgblack@eecs.umich.edu panic("Packet %s already has bus delay (%d, %d) that should be " 1475648Sgblack@eecs.umich.edu "accounted for.\n", pkt->cmdString(), pkt->busFirstWordDelay, 1485648Sgblack@eecs.umich.edu pkt->busLastWordDelay); 1495648Sgblack@eecs.umich.edu 1505648Sgblack@eecs.umich.edu // The first word will be delivered on the cycle after the header. 1515648Sgblack@eecs.umich.edu pkt->busFirstWordDelay = (headerCycles + 1) * clockPeriod() + offset; 1525648Sgblack@eecs.umich.edu 1535648Sgblack@eecs.umich.edu // Note that currently busLastWordDelay can be smaller than 1545648Sgblack@eecs.umich.edu // busFirstWordDelay if the packet has no data 1555648Sgblack@eecs.umich.edu pkt->busLastWordDelay = (headerCycles + dataCycles) * clockPeriod() + 1565648Sgblack@eecs.umich.edu offset; 1575648Sgblack@eecs.umich.edu} 1585648Sgblack@eecs.umich.edu 1595648Sgblack@eecs.umich.edutemplate <typename PortClass> 1605648Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name, 1615648Sgblack@eecs.umich.edu uint16_t num_dest_ports) : 1625648Sgblack@eecs.umich.edu Drainable(), 1635648Sgblack@eecs.umich.edu bus(_bus), _name(_name), state(IDLE), drainManager(NULL), 1645648Sgblack@eecs.umich.edu retryingPort(NULL), waitingForPeer(num_dest_ports, NULL), 1655648Sgblack@eecs.umich.edu releaseEvent(this) 1665648Sgblack@eecs.umich.edu{ 1675648Sgblack@eecs.umich.edu} 1685648Sgblack@eecs.umich.edu 1695648Sgblack@eecs.umich.edutemplate <typename PortClass> 1705648Sgblack@eecs.umich.eduvoid BaseBus::Layer<PortClass>::occupyLayer(Tick until) 1715648Sgblack@eecs.umich.edu{ 1725648Sgblack@eecs.umich.edu // ensure the state is busy at this point, as the bus should 1735648Sgblack@eecs.umich.edu // transition from idle as soon as it has decided to forward the 1745648Sgblack@eecs.umich.edu // packet to prevent any follow-on calls to sendTiming seeing an 1755648Sgblack@eecs.umich.edu // unoccupied bus 1765648Sgblack@eecs.umich.edu assert(state == BUSY); 1775648Sgblack@eecs.umich.edu 1785648Sgblack@eecs.umich.edu // until should never be 0 as express snoops never occupy the bus 1795648Sgblack@eecs.umich.edu assert(until != 0); 1805648Sgblack@eecs.umich.edu bus.schedule(releaseEvent, until); 1815648Sgblack@eecs.umich.edu 1825648Sgblack@eecs.umich.edu DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", 1835648Sgblack@eecs.umich.edu curTick(), until); 1845648Sgblack@eecs.umich.edu} 1855648Sgblack@eecs.umich.edu 1865648Sgblack@eecs.umich.edutemplate <typename PortClass> 1875648Sgblack@eecs.umich.edubool 1885648Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::tryTiming(PortClass* port, PortID dest_port_id) 1895648Sgblack@eecs.umich.edu{ 1905648Sgblack@eecs.umich.edu // first we see if the bus is busy, next we check if we are in a 1915648Sgblack@eecs.umich.edu // retry with a port other than the current one, lastly we check 1925648Sgblack@eecs.umich.edu // if the destination port is already engaged in a transaction 1935648Sgblack@eecs.umich.edu // waiting for a retry from the peer 1945648Sgblack@eecs.umich.edu if (state == BUSY || (state == RETRY && port != retryingPort) || 1955648Sgblack@eecs.umich.edu (dest_port_id != InvalidPortID && 1965648Sgblack@eecs.umich.edu waitingForPeer[dest_port_id] != NULL)) { 1975648Sgblack@eecs.umich.edu // put the port at the end of the retry list waiting for the 1985648Sgblack@eecs.umich.edu // layer to be freed up (and in the case of a busy peer, for 1995648Sgblack@eecs.umich.edu // that transaction to go through, and then the bus to free 2005648Sgblack@eecs.umich.edu // up) 2015648Sgblack@eecs.umich.edu waitingForLayer.push_back(port); 2025648Sgblack@eecs.umich.edu return false; 2035648Sgblack@eecs.umich.edu } 2045648Sgblack@eecs.umich.edu 2055648Sgblack@eecs.umich.edu // update the state to busy 2065649Sgblack@eecs.umich.edu state = BUSY; 2075649Sgblack@eecs.umich.edu 2085649Sgblack@eecs.umich.edu // reset the retrying port 2095648Sgblack@eecs.umich.edu retryingPort = NULL; 2105898Sgblack@eecs.umich.edu 2115648Sgblack@eecs.umich.edu return true; 2125648Sgblack@eecs.umich.edu} 2135648Sgblack@eecs.umich.edu 2145648Sgblack@eecs.umich.edutemplate <typename PortClass> 2155648Sgblack@eecs.umich.eduvoid 2165648Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::succeededTiming(Tick busy_time) 2175648Sgblack@eecs.umich.edu{ 2185648Sgblack@eecs.umich.edu // we should have gone from idle or retry to busy in the tryTiming 2195648Sgblack@eecs.umich.edu // test 2205648Sgblack@eecs.umich.edu assert(state == BUSY); 2215648Sgblack@eecs.umich.edu 2225648Sgblack@eecs.umich.edu // occupy the bus accordingly 2235648Sgblack@eecs.umich.edu occupyLayer(busy_time); 2245649Sgblack@eecs.umich.edu} 2255649Sgblack@eecs.umich.edu 2265649Sgblack@eecs.umich.edutemplate <typename PortClass> 2275648Sgblack@eecs.umich.eduvoid 2285898Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::failedTiming(PortClass* src_port, 2295648Sgblack@eecs.umich.edu PortID dest_port_id, Tick busy_time) 2305647Sgblack@eecs.umich.edu{ 2315691Sgblack@eecs.umich.edu // ensure no one got in between and tried to send something to 2325691Sgblack@eecs.umich.edu // this port 2335691Sgblack@eecs.umich.edu assert(waitingForPeer[dest_port_id] == NULL); 2345691Sgblack@eecs.umich.edu 2355691Sgblack@eecs.umich.edu // if the source port is the current retrying one or not, we have 2365691Sgblack@eecs.umich.edu // failed in forwarding and should track that we are now waiting 2375691Sgblack@eecs.umich.edu // for the peer to send a retry 2385691Sgblack@eecs.umich.edu waitingForPeer[dest_port_id] = src_port; 2395691Sgblack@eecs.umich.edu 2405691Sgblack@eecs.umich.edu // we should have gone from idle or retry to busy in the tryTiming 2415691Sgblack@eecs.umich.edu // test 2425691Sgblack@eecs.umich.edu assert(state == BUSY); 2435691Sgblack@eecs.umich.edu 2445691Sgblack@eecs.umich.edu // occupy the bus accordingly 2455691Sgblack@eecs.umich.edu occupyLayer(busy_time); 2465691Sgblack@eecs.umich.edu} 2475691Sgblack@eecs.umich.edu 2485691Sgblack@eecs.umich.edutemplate <typename PortClass> 2495691Sgblack@eecs.umich.eduvoid 2505691Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::releaseLayer() 2515691Sgblack@eecs.umich.edu{ 2525691Sgblack@eecs.umich.edu // releasing the bus means we should now be idle 2535691Sgblack@eecs.umich.edu assert(state == BUSY); 2545691Sgblack@eecs.umich.edu assert(!releaseEvent.scheduled()); 2555691Sgblack@eecs.umich.edu 2565691Sgblack@eecs.umich.edu // update the state 2575691Sgblack@eecs.umich.edu state = IDLE; 2585691Sgblack@eecs.umich.edu 2595691Sgblack@eecs.umich.edu // bus layer is now idle, so if someone is waiting we can retry 2605691Sgblack@eecs.umich.edu if (!waitingForLayer.empty()) { 2615691Sgblack@eecs.umich.edu retryWaiting(); 2625691Sgblack@eecs.umich.edu } else if (drainManager) { 2635691Sgblack@eecs.umich.edu DPRINTF(Drain, "Bus done draining, signaling drain manager\n"); 2645691Sgblack@eecs.umich.edu //If we weren't able to drain before, do it now. 2655691Sgblack@eecs.umich.edu drainManager->signalDrainDone(); 2665691Sgblack@eecs.umich.edu // Clear the drain event once we're done with it. 2675691Sgblack@eecs.umich.edu drainManager = NULL; 2685691Sgblack@eecs.umich.edu } 2695691Sgblack@eecs.umich.edu} 2706066Sgblack@eecs.umich.edu 2716066Sgblack@eecs.umich.edutemplate <typename PortClass> 2726050Sgblack@eecs.umich.eduvoid 2736050Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::retryWaiting() 2745691Sgblack@eecs.umich.edu{ 2755691Sgblack@eecs.umich.edu // this should never be called with no one waiting 2765811Sgblack@eecs.umich.edu assert(!waitingForLayer.empty()); 2775691Sgblack@eecs.umich.edu 2785647Sgblack@eecs.umich.edu // we always go to retrying from idle 2796041Sgblack@eecs.umich.edu assert(state == IDLE); 2806041Sgblack@eecs.umich.edu 2816041Sgblack@eecs.umich.edu // update the state 2826041Sgblack@eecs.umich.edu state = RETRY; 2836136Sgblack@eecs.umich.edu 2846136Sgblack@eecs.umich.edu // set the retrying port to the front of the retry list and pop it 2856136Sgblack@eecs.umich.edu // off the list 2866136Sgblack@eecs.umich.edu assert(retryingPort == NULL); 2876136Sgblack@eecs.umich.edu retryingPort = waitingForLayer.front(); 2886041Sgblack@eecs.umich.edu waitingForLayer.pop_front(); 2896136Sgblack@eecs.umich.edu 2906136Sgblack@eecs.umich.edu // tell the port to retry, which in some cases ends up calling the 2916041Sgblack@eecs.umich.edu // bus 2926041Sgblack@eecs.umich.edu retryingPort->sendRetry(); 2936041Sgblack@eecs.umich.edu 2946137Sgblack@eecs.umich.edu // If the bus is still in the retry state, sendTiming wasn't 2956137Sgblack@eecs.umich.edu // called in zero time (e.g. the cache does this), burn a cycle 2966137Sgblack@eecs.umich.edu if (state == RETRY) { 2977913SBrad.Beckmann@amd.com // update the state to busy and reset the retrying port, we 2987913SBrad.Beckmann@amd.com // have done our bit and sent the retry 2997913SBrad.Beckmann@amd.com state = BUSY; 3007913SBrad.Beckmann@amd.com retryingPort = NULL; 3017913SBrad.Beckmann@amd.com 3026137Sgblack@eecs.umich.edu // occupy the bus layer until the next cycle ends 3037913SBrad.Beckmann@amd.com occupyLayer(bus.clockEdge(Cycles(1))); 3047913SBrad.Beckmann@amd.com } 3056137Sgblack@eecs.umich.edu} 3066137Sgblack@eecs.umich.edu 3076137Sgblack@eecs.umich.edutemplate <typename PortClass> 3086137Sgblack@eecs.umich.eduvoid 3096137Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::recvRetry(PortID port_id) 3106137Sgblack@eecs.umich.edu{ 3115651Sgblack@eecs.umich.edu // we should never get a retry without having failed to forward 3125651Sgblack@eecs.umich.edu // something to this port 3135651Sgblack@eecs.umich.edu assert(waitingForPeer[port_id] != NULL); 3146136Sgblack@eecs.umich.edu 3155651Sgblack@eecs.umich.edu // find the port where the failed packet originated and remove the 3165651Sgblack@eecs.umich.edu // item from the waiting list 3175651Sgblack@eecs.umich.edu PortClass* retry_port = waitingForPeer[port_id]; 3185651Sgblack@eecs.umich.edu waitingForPeer[port_id] = NULL; 3195654Sgblack@eecs.umich.edu 3205654Sgblack@eecs.umich.edu // add this port at the front of the waiting ports for the layer, 3215654Sgblack@eecs.umich.edu // this allows us to call retry on the port immediately if the bus 3225654Sgblack@eecs.umich.edu // layer is idle 3235697Snate@binkert.org waitingForLayer.push_front(retry_port); 3245655Sgblack@eecs.umich.edu 3255691Sgblack@eecs.umich.edu // if the bus layer is idle, retry this port straight away, if we 3265691Sgblack@eecs.umich.edu // are busy, then simply let the port wait for its turn 3275654Sgblack@eecs.umich.edu if (state == IDLE) { 3285651Sgblack@eecs.umich.edu retryWaiting(); 3295651Sgblack@eecs.umich.edu } else { 3305651Sgblack@eecs.umich.edu assert(state == BUSY); 3315651Sgblack@eecs.umich.edu } 3325651Sgblack@eecs.umich.edu} 3335651Sgblack@eecs.umich.edu 3346064Sgblack@eecs.umich.eduPortID 3355651Sgblack@eecs.umich.eduBaseBus::findPort(Addr addr) 3365651Sgblack@eecs.umich.edu{ 3375651Sgblack@eecs.umich.edu // we should never see any address lookups before we've got the 3385651Sgblack@eecs.umich.edu // ranges of all connected slave modules 3396065Sgblack@eecs.umich.edu assert(gotAllAddrRanges); 3406065Sgblack@eecs.umich.edu 3416065Sgblack@eecs.umich.edu // Check the cache 3426065Sgblack@eecs.umich.edu PortID dest_id = checkPortCache(addr); 3436065Sgblack@eecs.umich.edu if (dest_id != InvalidPortID) 3446069Sgblack@eecs.umich.edu return dest_id; 3456069Sgblack@eecs.umich.edu 3466069Sgblack@eecs.umich.edu // Check the address map interval tree 3476069Sgblack@eecs.umich.edu PortMapConstIter i = portMap.find(addr); 3486069Sgblack@eecs.umich.edu if (i != portMap.end()) { 3496069Sgblack@eecs.umich.edu dest_id = i->second; 3506065Sgblack@eecs.umich.edu updatePortCache(dest_id, i->first); 3516065Sgblack@eecs.umich.edu return dest_id; 3526065Sgblack@eecs.umich.edu } 3536065Sgblack@eecs.umich.edu 3546065Sgblack@eecs.umich.edu // Check if this matches the default range 3556041Sgblack@eecs.umich.edu if (useDefaultRange) { 3566041Sgblack@eecs.umich.edu if (defaultRange.contains(addr)) { 3576041Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, " found addr %#llx on default\n", 3586041Sgblack@eecs.umich.edu addr); 3596136Sgblack@eecs.umich.edu return defaultPortID; 3606136Sgblack@eecs.umich.edu } 3616136Sgblack@eecs.umich.edu } else if (defaultPortID != InvalidPortID) { 3626061Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " 3636061Sgblack@eecs.umich.edu "will use default port\n", addr); 3646041Sgblack@eecs.umich.edu return defaultPortID; 3656041Sgblack@eecs.umich.edu } 3666041Sgblack@eecs.umich.edu 3676041Sgblack@eecs.umich.edu // we should use the range for the default port and it did not 3686041Sgblack@eecs.umich.edu // match, or the default port is not set 3696041Sgblack@eecs.umich.edu fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 3706041Sgblack@eecs.umich.edu name()); 3716136Sgblack@eecs.umich.edu} 3726136Sgblack@eecs.umich.edu 3736136Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a range change.*/ 3746041Sgblack@eecs.umich.eduvoid 3756041Sgblack@eecs.umich.eduBaseBus::recvRangeChange(PortID master_port_id) 3766041Sgblack@eecs.umich.edu{ 3775647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Received range change from slave port %s\n", 3785648Sgblack@eecs.umich.edu masterPorts[master_port_id]->getSlavePort().name()); 3795647Sgblack@eecs.umich.edu 3805647Sgblack@eecs.umich.edu // remember that we got a range from this master port and thus the 3815647Sgblack@eecs.umich.edu // connected slave module 3825647Sgblack@eecs.umich.edu gotAddrRanges[master_port_id] = true; 3835647Sgblack@eecs.umich.edu 3845647Sgblack@eecs.umich.edu // update the global flag 3855647Sgblack@eecs.umich.edu if (!gotAllAddrRanges) { 3865647Sgblack@eecs.umich.edu // take a logical AND of all the ports and see if we got 3875647Sgblack@eecs.umich.edu // ranges from everyone 3885647Sgblack@eecs.umich.edu gotAllAddrRanges = true; 3895647Sgblack@eecs.umich.edu std::vector<bool>::const_iterator r = gotAddrRanges.begin(); 3905647Sgblack@eecs.umich.edu while (gotAllAddrRanges && r != gotAddrRanges.end()) { 3915647Sgblack@eecs.umich.edu gotAllAddrRanges &= *r++; 3925647Sgblack@eecs.umich.edu } 3935647Sgblack@eecs.umich.edu if (gotAllAddrRanges) 3945647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n"); 3955647Sgblack@eecs.umich.edu } 3965848Sgblack@eecs.umich.edu 3975848Sgblack@eecs.umich.edu // note that we could get the range from the default port at any 3985848Sgblack@eecs.umich.edu // point in time, and we cannot assume that the default range is 3995848Sgblack@eecs.umich.edu // set before the other ones are, so we do additional checks once 4005848Sgblack@eecs.umich.edu // all ranges are provided 4015848Sgblack@eecs.umich.edu if (master_port_id == defaultPortID) { 4027823Ssteve.reinhardt@amd.com // only update if we are indeed checking ranges for the 4035848Sgblack@eecs.umich.edu // default port since the port might not have a valid range 4045848Sgblack@eecs.umich.edu // otherwise 4055848Sgblack@eecs.umich.edu if (useDefaultRange) { 4065848Sgblack@eecs.umich.edu AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 4075848Sgblack@eecs.umich.edu 4085848Sgblack@eecs.umich.edu if (ranges.size() != 1) 4095647Sgblack@eecs.umich.edu fatal("Bus %s may only have a single default range", 4105647Sgblack@eecs.umich.edu name()); 4115647Sgblack@eecs.umich.edu 4125647Sgblack@eecs.umich.edu defaultRange = ranges.front(); 4135648Sgblack@eecs.umich.edu } 4145647Sgblack@eecs.umich.edu } else { 4155647Sgblack@eecs.umich.edu // the ports are allowed to update their address ranges 4165647Sgblack@eecs.umich.edu // dynamically, so remove any existing entries 4175648Sgblack@eecs.umich.edu if (gotAddrRanges[master_port_id]) { 4185647Sgblack@eecs.umich.edu for (PortMapIter p = portMap.begin(); p != portMap.end(); ) { 4195647Sgblack@eecs.umich.edu if (p->second == master_port_id) 4205647Sgblack@eecs.umich.edu // erasing invalidates the iterator, so advance it 4215647Sgblack@eecs.umich.edu // before the deletion takes place 4225647Sgblack@eecs.umich.edu portMap.erase(p++); 4235647Sgblack@eecs.umich.edu else 4245647Sgblack@eecs.umich.edu p++; 4255647Sgblack@eecs.umich.edu } 4265647Sgblack@eecs.umich.edu } 4275647Sgblack@eecs.umich.edu 4285647Sgblack@eecs.umich.edu AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 4295647Sgblack@eecs.umich.edu 4305647Sgblack@eecs.umich.edu for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) { 4315647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Adding range %s for id %d\n", 4325647Sgblack@eecs.umich.edu r->to_string(), master_port_id); 4335647Sgblack@eecs.umich.edu if (portMap.insert(*r, master_port_id) == portMap.end()) { 4345647Sgblack@eecs.umich.edu PortID conflict_id = portMap.find(*r)->second; 4355647Sgblack@eecs.umich.edu fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 4365647Sgblack@eecs.umich.edu name(), 4375647Sgblack@eecs.umich.edu masterPorts[master_port_id]->getSlavePort().name(), 4385647Sgblack@eecs.umich.edu masterPorts[conflict_id]->getSlavePort().name()); 4395647Sgblack@eecs.umich.edu } 4405647Sgblack@eecs.umich.edu } 4415647Sgblack@eecs.umich.edu } 4425647Sgblack@eecs.umich.edu 4435647Sgblack@eecs.umich.edu // if we have received ranges from all our neighbouring slave 4445647Sgblack@eecs.umich.edu // modules, go ahead and tell our connected master modules in 4455647Sgblack@eecs.umich.edu // turn, this effectively assumes a tree structure of the system 4465647Sgblack@eecs.umich.edu if (gotAllAddrRanges) { 4475647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Aggregating bus ranges\n"); 4485647Sgblack@eecs.umich.edu busRanges.clear(); 4495647Sgblack@eecs.umich.edu 4505690Sgblack@eecs.umich.edu // start out with the default range 4515690Sgblack@eecs.umich.edu if (useDefaultRange) { 4525690Sgblack@eecs.umich.edu if (!gotAddrRanges[defaultPortID]) 4535690Sgblack@eecs.umich.edu fatal("Bus %s uses default range, but none provided", 4545647Sgblack@eecs.umich.edu name()); 4555647Sgblack@eecs.umich.edu 4565647Sgblack@eecs.umich.edu busRanges.push_back(defaultRange); 4575647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding default %s\n", 4585647Sgblack@eecs.umich.edu defaultRange.to_string()); 4595647Sgblack@eecs.umich.edu } 4605647Sgblack@eecs.umich.edu 4615647Sgblack@eecs.umich.edu // merge all interleaved ranges and add any range that is not 4625647Sgblack@eecs.umich.edu // a subset of the default range 4635647Sgblack@eecs.umich.edu std::vector<AddrRange> intlv_ranges; 4645647Sgblack@eecs.umich.edu for (AddrRangeMap<PortID>::const_iterator r = portMap.begin(); 4655647Sgblack@eecs.umich.edu r != portMap.end(); ++r) { 4665647Sgblack@eecs.umich.edu // if the range is interleaved then save it for now 4675647Sgblack@eecs.umich.edu if (r->first.interleaved()) { 4685647Sgblack@eecs.umich.edu // if we already got interleaved ranges that are not 4695647Sgblack@eecs.umich.edu // part of the same range, then first do a merge 4705647Sgblack@eecs.umich.edu // before we add the new one 4715647Sgblack@eecs.umich.edu if (!intlv_ranges.empty() && 4725647Sgblack@eecs.umich.edu !intlv_ranges.back().mergesWith(r->first)) { 4735647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n", 4745647Sgblack@eecs.umich.edu intlv_ranges.size()); 4755647Sgblack@eecs.umich.edu AddrRange merged_range(intlv_ranges); 4765647Sgblack@eecs.umich.edu // next decide if we keep the merged range or not 4775647Sgblack@eecs.umich.edu if (!(useDefaultRange && 4785647Sgblack@eecs.umich.edu merged_range.isSubset(defaultRange))) { 4796046Sgblack@eecs.umich.edu busRanges.push_back(merged_range); 4806046Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding merged range %s\n", 4816046Sgblack@eecs.umich.edu merged_range.to_string()); 4826046Sgblack@eecs.umich.edu } 4836046Sgblack@eecs.umich.edu intlv_ranges.clear(); 4846046Sgblack@eecs.umich.edu } 4856046Sgblack@eecs.umich.edu intlv_ranges.push_back(r->first); 4866046Sgblack@eecs.umich.edu } else { 4876046Sgblack@eecs.umich.edu // keep the current range if not a subset of the default 4886046Sgblack@eecs.umich.edu if (!(useDefaultRange && 4896046Sgblack@eecs.umich.edu r->first.isSubset(defaultRange))) { 4906712Snate@binkert.org busRanges.push_back(r->first); 4916046Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding range %s\n", 4926046Sgblack@eecs.umich.edu r->first.to_string()); 4936046Sgblack@eecs.umich.edu } 4946046Sgblack@eecs.umich.edu } 4956046Sgblack@eecs.umich.edu } 4966046Sgblack@eecs.umich.edu 4976046Sgblack@eecs.umich.edu // if there is still interleaved ranges waiting to be merged, 4986065Sgblack@eecs.umich.edu // go ahead and do it 4996065Sgblack@eecs.umich.edu if (!intlv_ranges.empty()) { 5006138Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n", 5016138Sgblack@eecs.umich.edu intlv_ranges.size()); 5026046Sgblack@eecs.umich.edu AddrRange merged_range(intlv_ranges); 5036046Sgblack@eecs.umich.edu if (!(useDefaultRange && merged_range.isSubset(defaultRange))) { 5046138Sgblack@eecs.umich.edu busRanges.push_back(merged_range); 5056138Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding merged range %s\n", 5066138Sgblack@eecs.umich.edu merged_range.to_string()); 5076138Sgblack@eecs.umich.edu } 5086138Sgblack@eecs.umich.edu } 5096138Sgblack@eecs.umich.edu 5106138Sgblack@eecs.umich.edu // also check that no range partially overlaps with the 5116138Sgblack@eecs.umich.edu // default range, this has to be done after all ranges are set 5126138Sgblack@eecs.umich.edu // as there are no guarantees for when the default range is 5136138Sgblack@eecs.umich.edu // update with respect to the other ones 5146138Sgblack@eecs.umich.edu if (useDefaultRange) { 5156138Sgblack@eecs.umich.edu for (AddrRangeConstIter r = busRanges.begin(); 5166138Sgblack@eecs.umich.edu r != busRanges.end(); ++r) { 5176138Sgblack@eecs.umich.edu // see if the new range is partially 5186138Sgblack@eecs.umich.edu // overlapping the default range 5196138Sgblack@eecs.umich.edu if (r->intersects(defaultRange) && 5206138Sgblack@eecs.umich.edu !r->isSubset(defaultRange)) 5216138Sgblack@eecs.umich.edu fatal("Range %s intersects the " \ 5226138Sgblack@eecs.umich.edu "default range of %s but is not a " \ 5236138Sgblack@eecs.umich.edu "subset\n", r->to_string(), name()); 5246138Sgblack@eecs.umich.edu } 5256138Sgblack@eecs.umich.edu } 5266138Sgblack@eecs.umich.edu 5276138Sgblack@eecs.umich.edu // tell all our neighbouring master ports that our address 5286138Sgblack@eecs.umich.edu // ranges have changed 5296138Sgblack@eecs.umich.edu for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 5306138Sgblack@eecs.umich.edu ++s) 5316138Sgblack@eecs.umich.edu (*s)->sendRangeChange(); 5326138Sgblack@eecs.umich.edu } 5336138Sgblack@eecs.umich.edu 5346138Sgblack@eecs.umich.edu clearPortCache(); 5356046Sgblack@eecs.umich.edu} 5366046Sgblack@eecs.umich.edu 5376069Sgblack@eecs.umich.eduAddrRangeList 5386069Sgblack@eecs.umich.eduBaseBus::getAddrRanges() const 5396069Sgblack@eecs.umich.edu{ 5406046Sgblack@eecs.umich.edu // we should never be asked without first having sent a range 5416046Sgblack@eecs.umich.edu // change, and the latter is only done once we have all the ranges 5426069Sgblack@eecs.umich.edu // of the connected devices 5436069Sgblack@eecs.umich.edu assert(gotAllAddrRanges); 5446069Sgblack@eecs.umich.edu 5456046Sgblack@eecs.umich.edu // at the moment, this never happens, as there are no cycles in 5466069Sgblack@eecs.umich.edu // the range queries and no devices on the master side of a bus 5476069Sgblack@eecs.umich.edu // (CPU, cache, bridge etc) actually care about the ranges of the 5486138Sgblack@eecs.umich.edu // ports they are connected to 5496138Sgblack@eecs.umich.edu 5506069Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Received address range request\n"); 5516069Sgblack@eecs.umich.edu 5526069Sgblack@eecs.umich.edu return busRanges; 5536046Sgblack@eecs.umich.edu} 5546046Sgblack@eecs.umich.edu 5556138Sgblack@eecs.umich.eduunsigned 5566138Sgblack@eecs.umich.eduBaseBus::deviceBlockSize() const 5576138Sgblack@eecs.umich.edu{ 5586046Sgblack@eecs.umich.edu return blockSize; 5595647Sgblack@eecs.umich.edu} 5605647Sgblack@eecs.umich.edu 5615647Sgblack@eecs.umich.edutemplate <typename PortClass> 5625647Sgblack@eecs.umich.eduunsigned int 5635647Sgblack@eecs.umich.eduBaseBus::Layer<PortClass>::drain(DrainManager *dm) 5645647Sgblack@eecs.umich.edu{ 5655647Sgblack@eecs.umich.edu //We should check that we're not "doing" anything, and that noone is 5665647Sgblack@eecs.umich.edu //waiting. We might be idle but have someone waiting if the device we 5675647Sgblack@eecs.umich.edu //contacted for a retry didn't actually retry. 5685647Sgblack@eecs.umich.edu if (state != IDLE) { 5695647Sgblack@eecs.umich.edu DPRINTF(Drain, "Bus not drained\n"); 5705647Sgblack@eecs.umich.edu drainManager = dm; 5715647Sgblack@eecs.umich.edu return 1; 5725647Sgblack@eecs.umich.edu } 5735648Sgblack@eecs.umich.edu return 0; 5745648Sgblack@eecs.umich.edu} 5755648Sgblack@eecs.umich.edu 5765848Sgblack@eecs.umich.edu/** 5775848Sgblack@eecs.umich.edu * Bus layer template instantiations. Could be removed with _impl.hh 5785848Sgblack@eecs.umich.edu * file, but since there are only two given options (MasterPort and 5795648Sgblack@eecs.umich.edu * SlavePort) it seems a bit excessive at this point. 5807823Ssteve.reinhardt@amd.com */ 5815648Sgblack@eecs.umich.edutemplate class BaseBus::Layer<SlavePort>; 5825648Sgblack@eecs.umich.edutemplate class BaseBus::Layer<MasterPort>; 5837823Ssteve.reinhardt@amd.com