xbar.cc revision 9716
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 * 55647Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 65647Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 75647Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 85647Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 95647Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 105647Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 115647Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 125647Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 135647Sgblack@eecs.umich.edu * 145647Sgblack@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan 155647Sgblack@eecs.umich.edu * All rights reserved. 165647Sgblack@eecs.umich.edu * 175647Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 185647Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 195647Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 205647Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 215647Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 225647Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 235647Sgblack@eecs.umich.edu * 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 * 405647Sgblack@eecs.umich.edu * Authors: Ali Saidi 415647Sgblack@eecs.umich.edu * Andreas Hansson 425647Sgblack@eecs.umich.edu * William Wang 435647Sgblack@eecs.umich.edu */ 445647Sgblack@eecs.umich.edu 455647Sgblack@eecs.umich.edu/** 465647Sgblack@eecs.umich.edu * @file 475647Sgblack@eecs.umich.edu * Definition of a bus object. 485647Sgblack@eecs.umich.edu */ 495647Sgblack@eecs.umich.edu 505647Sgblack@eecs.umich.edu#include "base/misc.hh" 515647Sgblack@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) 585648Sgblack@eecs.umich.edu : MemObject(p), 595647Sgblack@eecs.umich.edu headerCycles(p->header_cycles), width(p->width), 605654Sgblack@eecs.umich.edu gotAddrRanges(p->port_default_connection_count + 615647Sgblack@eecs.umich.edu p->port_master_connection_count, false), 625654Sgblack@eecs.umich.edu gotAllAddrRanges(false), defaultPortID(InvalidPortID), 635647Sgblack@eecs.umich.edu useDefaultRange(p->use_default_range), 645648Sgblack@eecs.umich.edu blockSize(p->block_size) 655648Sgblack@eecs.umich.edu{} 665647Sgblack@eecs.umich.edu 675647Sgblack@eecs.umich.eduBaseBus::~BaseBus() 685647Sgblack@eecs.umich.edu{ 695647Sgblack@eecs.umich.edu for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); 705647Sgblack@eecs.umich.edu ++m) { 715647Sgblack@eecs.umich.edu delete *m; 725647Sgblack@eecs.umich.edu } 735647Sgblack@eecs.umich.edu 745647Sgblack@eecs.umich.edu for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); 755648Sgblack@eecs.umich.edu ++s) { 765647Sgblack@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 = clockEdge() - 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 SrcType, typename DstType> 1605648Sgblack@eecs.umich.eduBaseBus::Layer<SrcType,DstType>::Layer(DstType& _port, BaseBus& _bus, 1615648Sgblack@eecs.umich.edu const std::string& _name) : 1625648Sgblack@eecs.umich.edu port(_port), bus(_bus), _name(_name), state(IDLE), drainManager(NULL), 1635648Sgblack@eecs.umich.edu retryingPort(NULL), waitingForPeer(NULL), 1645648Sgblack@eecs.umich.edu releaseEvent(this) 1655648Sgblack@eecs.umich.edu{ 1665648Sgblack@eecs.umich.edu} 1675648Sgblack@eecs.umich.edu 1685648Sgblack@eecs.umich.edutemplate <typename SrcType, typename DstType> 1695648Sgblack@eecs.umich.eduvoid BaseBus::Layer<SrcType,DstType>::occupyLayer(Tick until) 1705648Sgblack@eecs.umich.edu{ 1715648Sgblack@eecs.umich.edu // ensure the state is busy at this point, as the bus should 1725648Sgblack@eecs.umich.edu // transition from idle as soon as it has decided to forward the 1735648Sgblack@eecs.umich.edu // packet to prevent any follow-on calls to sendTiming seeing an 1745648Sgblack@eecs.umich.edu // unoccupied bus 1755648Sgblack@eecs.umich.edu assert(state == BUSY); 1765648Sgblack@eecs.umich.edu 1775648Sgblack@eecs.umich.edu // until should never be 0 as express snoops never occupy the bus 1785648Sgblack@eecs.umich.edu assert(until != 0); 1795648Sgblack@eecs.umich.edu bus.schedule(releaseEvent, until); 1805648Sgblack@eecs.umich.edu 1815648Sgblack@eecs.umich.edu // account for the occupied ticks 1825648Sgblack@eecs.umich.edu occupancy += until - curTick(); 1835648Sgblack@eecs.umich.edu 1845648Sgblack@eecs.umich.edu DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", 1855648Sgblack@eecs.umich.edu curTick(), until); 1865648Sgblack@eecs.umich.edu} 1875648Sgblack@eecs.umich.edu 1885648Sgblack@eecs.umich.edutemplate <typename SrcType, typename DstType> 1895648Sgblack@eecs.umich.edubool 1905648Sgblack@eecs.umich.eduBaseBus::Layer<SrcType,DstType>::tryTiming(SrcType* src_port) 1915648Sgblack@eecs.umich.edu{ 1925648Sgblack@eecs.umich.edu // if we are in the retry state, we will not see anything but the 1935648Sgblack@eecs.umich.edu // retrying port (or in the case of the snoop ports the snoop 1945648Sgblack@eecs.umich.edu // response port that mirrors the actual slave port) as we leave 1955648Sgblack@eecs.umich.edu // this state again in zero time if the peer does not immediately 1965648Sgblack@eecs.umich.edu // call the bus when receiving the retry 1975648Sgblack@eecs.umich.edu 1985648Sgblack@eecs.umich.edu // first we see if the layer is busy, next we check if the 1995648Sgblack@eecs.umich.edu // destination port is already engaged in a transaction waiting 2005648Sgblack@eecs.umich.edu // for a retry from the peer 2015648Sgblack@eecs.umich.edu if (state == BUSY || waitingForPeer != NULL) { 2025648Sgblack@eecs.umich.edu // the port should not be waiting already 2035648Sgblack@eecs.umich.edu assert(std::find(waitingForLayer.begin(), waitingForLayer.end(), 2045648Sgblack@eecs.umich.edu src_port) == waitingForLayer.end()); 2055648Sgblack@eecs.umich.edu 2065648Sgblack@eecs.umich.edu // put the port at the end of the retry list waiting for the 2075648Sgblack@eecs.umich.edu // layer to be freed up (and in the case of a busy peer, for 2085648Sgblack@eecs.umich.edu // that transaction to go through, and then the bus to free 2095648Sgblack@eecs.umich.edu // up) 2105648Sgblack@eecs.umich.edu waitingForLayer.push_back(src_port); 2115648Sgblack@eecs.umich.edu return false; 2125648Sgblack@eecs.umich.edu } 2135648Sgblack@eecs.umich.edu 2145648Sgblack@eecs.umich.edu // update the state to busy 2155648Sgblack@eecs.umich.edu state = BUSY; 2165648Sgblack@eecs.umich.edu 2175648Sgblack@eecs.umich.edu // reset the retrying port 2185648Sgblack@eecs.umich.edu retryingPort = NULL; 2195648Sgblack@eecs.umich.edu 2205649Sgblack@eecs.umich.edu return true; 2215649Sgblack@eecs.umich.edu} 2225649Sgblack@eecs.umich.edu 2235648Sgblack@eecs.umich.edutemplate <typename SrcType, typename DstType> 2245648Sgblack@eecs.umich.eduvoid 2255648Sgblack@eecs.umich.eduBaseBus::Layer<SrcType,DstType>::succeededTiming(Tick busy_time) 2265648Sgblack@eecs.umich.edu{ 2275648Sgblack@eecs.umich.edu // we should have gone from idle or retry to busy in the tryTiming 2285648Sgblack@eecs.umich.edu // test 2295648Sgblack@eecs.umich.edu assert(state == BUSY); 2305648Sgblack@eecs.umich.edu 2315648Sgblack@eecs.umich.edu // occupy the bus accordingly 2325648Sgblack@eecs.umich.edu occupyLayer(busy_time); 2335648Sgblack@eecs.umich.edu} 2345648Sgblack@eecs.umich.edu 2355648Sgblack@eecs.umich.edutemplate <typename SrcType, typename DstType> 2365648Sgblack@eecs.umich.eduvoid 2375649Sgblack@eecs.umich.eduBaseBus::Layer<SrcType,DstType>::failedTiming(SrcType* src_port, 2385649Sgblack@eecs.umich.edu Tick busy_time) 2395649Sgblack@eecs.umich.edu{ 2405648Sgblack@eecs.umich.edu // ensure no one got in between and tried to send something to 2415648Sgblack@eecs.umich.edu // this port 2425647Sgblack@eecs.umich.edu assert(waitingForPeer == NULL); 2435647Sgblack@eecs.umich.edu 2445651Sgblack@eecs.umich.edu // if the source port is the current retrying one or not, we have 2455651Sgblack@eecs.umich.edu // failed in forwarding and should track that we are now waiting 2465651Sgblack@eecs.umich.edu // for the peer to send a retry 2475654Sgblack@eecs.umich.edu waitingForPeer = src_port; 2485654Sgblack@eecs.umich.edu 2495651Sgblack@eecs.umich.edu // we should have gone from idle or retry to busy in the tryTiming 2505651Sgblack@eecs.umich.edu // test 2515651Sgblack@eecs.umich.edu assert(state == BUSY); 2525651Sgblack@eecs.umich.edu 2535654Sgblack@eecs.umich.edu // occupy the bus accordingly 2545654Sgblack@eecs.umich.edu occupyLayer(busy_time); 2555654Sgblack@eecs.umich.edu} 2565654Sgblack@eecs.umich.edu 2575654Sgblack@eecs.umich.edutemplate <typename SrcType, typename DstType> 2585654Sgblack@eecs.umich.eduvoid 2595654Sgblack@eecs.umich.eduBaseBus::Layer<SrcType,DstType>::releaseLayer() 2605654Sgblack@eecs.umich.edu{ 2615654Sgblack@eecs.umich.edu // releasing the bus means we should now be idle 2625655Sgblack@eecs.umich.edu assert(state == BUSY); 2635655Sgblack@eecs.umich.edu assert(!releaseEvent.scheduled()); 2645655Sgblack@eecs.umich.edu 2655655Sgblack@eecs.umich.edu // update the state 2665655Sgblack@eecs.umich.edu state = IDLE; 2675655Sgblack@eecs.umich.edu 2685655Sgblack@eecs.umich.edu // bus layer is now idle, so if someone is waiting we can retry 2695655Sgblack@eecs.umich.edu if (!waitingForLayer.empty()) { 2705655Sgblack@eecs.umich.edu retryWaiting(); 2715654Sgblack@eecs.umich.edu } else if (waitingForPeer == NULL && drainManager) { 2725654Sgblack@eecs.umich.edu DPRINTF(Drain, "Bus done draining, signaling drain manager\n"); 2735654Sgblack@eecs.umich.edu //If we weren't able to drain before, do it now. 2745654Sgblack@eecs.umich.edu drainManager->signalDrainDone(); 2755654Sgblack@eecs.umich.edu // Clear the drain event once we're done with it. 2765654Sgblack@eecs.umich.edu drainManager = NULL; 2775654Sgblack@eecs.umich.edu } 2785654Sgblack@eecs.umich.edu} 2795654Sgblack@eecs.umich.edu 2805654Sgblack@eecs.umich.edutemplate <typename SrcType, typename DstType> 2815654Sgblack@eecs.umich.eduvoid 2825654Sgblack@eecs.umich.eduBaseBus::Layer<SrcType,DstType>::retryWaiting() 2835654Sgblack@eecs.umich.edu{ 2845654Sgblack@eecs.umich.edu // this should never be called with no one waiting 2855655Sgblack@eecs.umich.edu assert(!waitingForLayer.empty()); 2865655Sgblack@eecs.umich.edu 2875655Sgblack@eecs.umich.edu // we always go to retrying from idle 2885655Sgblack@eecs.umich.edu assert(state == IDLE); 2895655Sgblack@eecs.umich.edu 2905655Sgblack@eecs.umich.edu // update the state 2915655Sgblack@eecs.umich.edu state = RETRY; 2925655Sgblack@eecs.umich.edu 2935655Sgblack@eecs.umich.edu // set the retrying port to the front of the retry list and pop it 2945655Sgblack@eecs.umich.edu // off the list 2955655Sgblack@eecs.umich.edu assert(retryingPort == NULL); 2965655Sgblack@eecs.umich.edu retryingPort = waitingForLayer.front(); 2975655Sgblack@eecs.umich.edu waitingForLayer.pop_front(); 2985655Sgblack@eecs.umich.edu 2995655Sgblack@eecs.umich.edu // tell the port to retry, which in some cases ends up calling the 3005655Sgblack@eecs.umich.edu // bus 3015655Sgblack@eecs.umich.edu retryingPort->sendRetry(); 3025655Sgblack@eecs.umich.edu 3035655Sgblack@eecs.umich.edu // If the bus is still in the retry state, sendTiming wasn't 3045655Sgblack@eecs.umich.edu // called in zero time (e.g. the cache does this), burn a cycle 3055655Sgblack@eecs.umich.edu if (state == RETRY) { 3065654Sgblack@eecs.umich.edu // update the state to busy and reset the retrying port, we 3075651Sgblack@eecs.umich.edu // have done our bit and sent the retry 3085651Sgblack@eecs.umich.edu state = BUSY; 3095651Sgblack@eecs.umich.edu retryingPort = NULL; 3105651Sgblack@eecs.umich.edu 3115651Sgblack@eecs.umich.edu // occupy the bus layer until the next cycle ends 3125651Sgblack@eecs.umich.edu occupyLayer(bus.clockEdge(Cycles(1))); 3135651Sgblack@eecs.umich.edu } 3145651Sgblack@eecs.umich.edu} 3155651Sgblack@eecs.umich.edu 3165651Sgblack@eecs.umich.edutemplate <typename SrcType, typename DstType> 3175651Sgblack@eecs.umich.eduvoid 3185651Sgblack@eecs.umich.eduBaseBus::Layer<SrcType,DstType>::recvRetry() 3195647Sgblack@eecs.umich.edu{ 3205648Sgblack@eecs.umich.edu // we should never get a retry without having failed to forward 3215647Sgblack@eecs.umich.edu // something to this port 3225647Sgblack@eecs.umich.edu assert(waitingForPeer != NULL); 3235647Sgblack@eecs.umich.edu 3245647Sgblack@eecs.umich.edu // add the port where the failed packet originated to the front of 3255647Sgblack@eecs.umich.edu // the waiting ports for the layer, this allows us to call retry 3265647Sgblack@eecs.umich.edu // on the port immediately if the bus layer is idle 3275647Sgblack@eecs.umich.edu waitingForLayer.push_front(waitingForPeer); 3285647Sgblack@eecs.umich.edu 3295647Sgblack@eecs.umich.edu // we are no longer waiting for the peer 3305647Sgblack@eecs.umich.edu waitingForPeer = NULL; 3315647Sgblack@eecs.umich.edu 3325647Sgblack@eecs.umich.edu // if the bus layer is idle, retry this port straight away, if we 3335647Sgblack@eecs.umich.edu // are busy, then simply let the port wait for its turn 3345647Sgblack@eecs.umich.edu if (state == IDLE) { 3355647Sgblack@eecs.umich.edu retryWaiting(); 3365647Sgblack@eecs.umich.edu } else { 3375647Sgblack@eecs.umich.edu assert(state == BUSY); 3385647Sgblack@eecs.umich.edu } 3395647Sgblack@eecs.umich.edu} 3405647Sgblack@eecs.umich.edu 3415647Sgblack@eecs.umich.eduPortID 3425647Sgblack@eecs.umich.eduBaseBus::findPort(Addr addr) 3435647Sgblack@eecs.umich.edu{ 3445647Sgblack@eecs.umich.edu // we should never see any address lookups before we've got the 3455647Sgblack@eecs.umich.edu // ranges of all connected slave modules 3465647Sgblack@eecs.umich.edu assert(gotAllAddrRanges); 3475647Sgblack@eecs.umich.edu 3485647Sgblack@eecs.umich.edu // Check the cache 3495648Sgblack@eecs.umich.edu PortID dest_id = checkPortCache(addr); 3505648Sgblack@eecs.umich.edu if (dest_id != InvalidPortID) 3515647Sgblack@eecs.umich.edu return dest_id; 3525647Sgblack@eecs.umich.edu 3535647Sgblack@eecs.umich.edu // Check the address map interval tree 3545647Sgblack@eecs.umich.edu PortMapConstIter i = portMap.find(addr); 3555647Sgblack@eecs.umich.edu if (i != portMap.end()) { 3565647Sgblack@eecs.umich.edu dest_id = i->second; 3575648Sgblack@eecs.umich.edu updatePortCache(dest_id, i->first); 3585647Sgblack@eecs.umich.edu return dest_id; 3595647Sgblack@eecs.umich.edu } 3605647Sgblack@eecs.umich.edu 3615648Sgblack@eecs.umich.edu // Check if this matches the default range 3625647Sgblack@eecs.umich.edu if (useDefaultRange) { 3635647Sgblack@eecs.umich.edu if (defaultRange.contains(addr)) { 3645647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, " found addr %#llx on default\n", 3655647Sgblack@eecs.umich.edu addr); 3665647Sgblack@eecs.umich.edu return defaultPortID; 3675647Sgblack@eecs.umich.edu } 3685647Sgblack@eecs.umich.edu } else if (defaultPortID != InvalidPortID) { 3695647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " 3705647Sgblack@eecs.umich.edu "will use default port\n", addr); 3715647Sgblack@eecs.umich.edu return defaultPortID; 3725647Sgblack@eecs.umich.edu } 3735647Sgblack@eecs.umich.edu 3745647Sgblack@eecs.umich.edu // we should use the range for the default port and it did not 3755647Sgblack@eecs.umich.edu // match, or the default port is not set 3765647Sgblack@eecs.umich.edu fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 3775647Sgblack@eecs.umich.edu name()); 3785647Sgblack@eecs.umich.edu} 3795647Sgblack@eecs.umich.edu 3805647Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a range change.*/ 3815647Sgblack@eecs.umich.eduvoid 3825647Sgblack@eecs.umich.eduBaseBus::recvRangeChange(PortID master_port_id) 3835647Sgblack@eecs.umich.edu{ 3845647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Received range change from slave port %s\n", 3855647Sgblack@eecs.umich.edu masterPorts[master_port_id]->getSlavePort().name()); 3865647Sgblack@eecs.umich.edu 3875647Sgblack@eecs.umich.edu // remember that we got a range from this master port and thus the 3885647Sgblack@eecs.umich.edu // connected slave module 3895647Sgblack@eecs.umich.edu gotAddrRanges[master_port_id] = true; 3905647Sgblack@eecs.umich.edu 3915647Sgblack@eecs.umich.edu // update the global flag 3925647Sgblack@eecs.umich.edu if (!gotAllAddrRanges) { 3935647Sgblack@eecs.umich.edu // take a logical AND of all the ports and see if we got 3945647Sgblack@eecs.umich.edu // ranges from everyone 3955647Sgblack@eecs.umich.edu gotAllAddrRanges = true; 3965647Sgblack@eecs.umich.edu std::vector<bool>::const_iterator r = gotAddrRanges.begin(); 3975647Sgblack@eecs.umich.edu while (gotAllAddrRanges && r != gotAddrRanges.end()) { 3985647Sgblack@eecs.umich.edu gotAllAddrRanges &= *r++; 3995647Sgblack@eecs.umich.edu } 4005647Sgblack@eecs.umich.edu if (gotAllAddrRanges) 4015647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n"); 4025647Sgblack@eecs.umich.edu } 4035647Sgblack@eecs.umich.edu 4045647Sgblack@eecs.umich.edu // note that we could get the range from the default port at any 4055647Sgblack@eecs.umich.edu // point in time, and we cannot assume that the default range is 4065647Sgblack@eecs.umich.edu // set before the other ones are, so we do additional checks once 4075647Sgblack@eecs.umich.edu // all ranges are provided 4085647Sgblack@eecs.umich.edu if (master_port_id == defaultPortID) { 4095647Sgblack@eecs.umich.edu // only update if we are indeed checking ranges for the 4105647Sgblack@eecs.umich.edu // default port since the port might not have a valid range 4115647Sgblack@eecs.umich.edu // otherwise 4125647Sgblack@eecs.umich.edu if (useDefaultRange) { 4135647Sgblack@eecs.umich.edu AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 4145647Sgblack@eecs.umich.edu 4155647Sgblack@eecs.umich.edu if (ranges.size() != 1) 4165647Sgblack@eecs.umich.edu fatal("Bus %s may only have a single default range", 4175647Sgblack@eecs.umich.edu name()); 4185647Sgblack@eecs.umich.edu 4195647Sgblack@eecs.umich.edu defaultRange = ranges.front(); 4205647Sgblack@eecs.umich.edu } 4215647Sgblack@eecs.umich.edu } else { 4225647Sgblack@eecs.umich.edu // the ports are allowed to update their address ranges 4235647Sgblack@eecs.umich.edu // dynamically, so remove any existing entries 4245647Sgblack@eecs.umich.edu if (gotAddrRanges[master_port_id]) { 4255647Sgblack@eecs.umich.edu for (PortMapIter p = portMap.begin(); p != portMap.end(); ) { 4265647Sgblack@eecs.umich.edu if (p->second == master_port_id) 4275647Sgblack@eecs.umich.edu // erasing invalidates the iterator, so advance it 4285647Sgblack@eecs.umich.edu // before the deletion takes place 4295647Sgblack@eecs.umich.edu portMap.erase(p++); 4305647Sgblack@eecs.umich.edu else 4315647Sgblack@eecs.umich.edu p++; 4325647Sgblack@eecs.umich.edu } 4335647Sgblack@eecs.umich.edu } 4345647Sgblack@eecs.umich.edu 4355647Sgblack@eecs.umich.edu AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 4365647Sgblack@eecs.umich.edu 4375647Sgblack@eecs.umich.edu for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) { 4385647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Adding range %s for id %d\n", 4395647Sgblack@eecs.umich.edu r->to_string(), master_port_id); 4405647Sgblack@eecs.umich.edu if (portMap.insert(*r, master_port_id) == portMap.end()) { 4415648Sgblack@eecs.umich.edu PortID conflict_id = portMap.find(*r)->second; 4425648Sgblack@eecs.umich.edu fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 4435648Sgblack@eecs.umich.edu name(), 4445648Sgblack@eecs.umich.edu masterPorts[master_port_id]->getSlavePort().name(), 4455648Sgblack@eecs.umich.edu masterPorts[conflict_id]->getSlavePort().name()); 4465648Sgblack@eecs.umich.edu } 4475648Sgblack@eecs.umich.edu } 4485648Sgblack@eecs.umich.edu } 4495648Sgblack@eecs.umich.edu 4505648Sgblack@eecs.umich.edu // if we have received ranges from all our neighbouring slave 4515648Sgblack@eecs.umich.edu // modules, go ahead and tell our connected master modules in 4525648Sgblack@eecs.umich.edu // turn, this effectively assumes a tree structure of the system 4535648Sgblack@eecs.umich.edu if (gotAllAddrRanges) { 4545648Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Aggregating bus ranges\n"); 4555648Sgblack@eecs.umich.edu busRanges.clear(); 4565648Sgblack@eecs.umich.edu 4575648Sgblack@eecs.umich.edu // start out with the default range 4585648Sgblack@eecs.umich.edu if (useDefaultRange) { 4595647Sgblack@eecs.umich.edu if (!gotAddrRanges[defaultPortID]) 4605647Sgblack@eecs.umich.edu fatal("Bus %s uses default range, but none provided", 4615647Sgblack@eecs.umich.edu name()); 4625647Sgblack@eecs.umich.edu 4635647Sgblack@eecs.umich.edu busRanges.push_back(defaultRange); 4645647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding default %s\n", 4655647Sgblack@eecs.umich.edu defaultRange.to_string()); 4665647Sgblack@eecs.umich.edu } 4675647Sgblack@eecs.umich.edu 4685647Sgblack@eecs.umich.edu // merge all interleaved ranges and add any range that is not 4695648Sgblack@eecs.umich.edu // a subset of the default range 4705647Sgblack@eecs.umich.edu std::vector<AddrRange> intlv_ranges; 4715647Sgblack@eecs.umich.edu for (AddrRangeMap<PortID>::const_iterator r = portMap.begin(); 4725647Sgblack@eecs.umich.edu r != portMap.end(); ++r) { 4735654Sgblack@eecs.umich.edu // if the range is interleaved then save it for now 4745654Sgblack@eecs.umich.edu if (r->first.interleaved()) { 4755654Sgblack@eecs.umich.edu // if we already got interleaved ranges that are not 4765654Sgblack@eecs.umich.edu // part of the same range, then first do a merge 4775689Sgblack@eecs.umich.edu // before we add the new one 4785689Sgblack@eecs.umich.edu if (!intlv_ranges.empty() && 4795654Sgblack@eecs.umich.edu !intlv_ranges.back().mergesWith(r->first)) { 4805689Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n", 4815655Sgblack@eecs.umich.edu intlv_ranges.size()); 4825689Sgblack@eecs.umich.edu AddrRange merged_range(intlv_ranges); 4835689Sgblack@eecs.umich.edu // next decide if we keep the merged range or not 4845655Sgblack@eecs.umich.edu if (!(useDefaultRange && 4855689Sgblack@eecs.umich.edu merged_range.isSubset(defaultRange))) { 4865655Sgblack@eecs.umich.edu busRanges.push_back(merged_range); 4875689Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding merged range %s\n", 4885689Sgblack@eecs.umich.edu merged_range.to_string()); 4895655Sgblack@eecs.umich.edu } 4905689Sgblack@eecs.umich.edu intlv_ranges.clear(); 4915654Sgblack@eecs.umich.edu } 4925654Sgblack@eecs.umich.edu intlv_ranges.push_back(r->first); 4935654Sgblack@eecs.umich.edu } else { 4945654Sgblack@eecs.umich.edu // keep the current range if not a subset of the default 4955654Sgblack@eecs.umich.edu if (!(useDefaultRange && 4965654Sgblack@eecs.umich.edu r->first.isSubset(defaultRange))) { 4975654Sgblack@eecs.umich.edu busRanges.push_back(r->first); 4985654Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding range %s\n", 4995655Sgblack@eecs.umich.edu r->first.to_string()); 5005655Sgblack@eecs.umich.edu } 5015655Sgblack@eecs.umich.edu } 5025655Sgblack@eecs.umich.edu } 5035689Sgblack@eecs.umich.edu 5045655Sgblack@eecs.umich.edu // if there is still interleaved ranges waiting to be merged, 5055655Sgblack@eecs.umich.edu // go ahead and do it 5065689Sgblack@eecs.umich.edu if (!intlv_ranges.empty()) { 5075655Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n", 5085655Sgblack@eecs.umich.edu intlv_ranges.size()); 5095689Sgblack@eecs.umich.edu AddrRange merged_range(intlv_ranges); 5105655Sgblack@eecs.umich.edu if (!(useDefaultRange && merged_range.isSubset(defaultRange))) { 5115655Sgblack@eecs.umich.edu busRanges.push_back(merged_range); 5125655Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "-- Adding merged range %s\n", 5135655Sgblack@eecs.umich.edu merged_range.to_string()); 5145655Sgblack@eecs.umich.edu } 5155655Sgblack@eecs.umich.edu } 5165655Sgblack@eecs.umich.edu 5175689Sgblack@eecs.umich.edu // also check that no range partially overlaps with the 5185655Sgblack@eecs.umich.edu // default range, this has to be done after all ranges are set 5195655Sgblack@eecs.umich.edu // as there are no guarantees for when the default range is 5205689Sgblack@eecs.umich.edu // update with respect to the other ones 5215655Sgblack@eecs.umich.edu if (useDefaultRange) { 5225655Sgblack@eecs.umich.edu for (AddrRangeConstIter r = busRanges.begin(); 5235655Sgblack@eecs.umich.edu r != busRanges.end(); ++r) { 5245654Sgblack@eecs.umich.edu // see if the new range is partially 5255654Sgblack@eecs.umich.edu // overlapping the default range 5265654Sgblack@eecs.umich.edu if (r->intersects(defaultRange) && 5275654Sgblack@eecs.umich.edu !r->isSubset(defaultRange)) 5285654Sgblack@eecs.umich.edu fatal("Range %s intersects the " \ 5295654Sgblack@eecs.umich.edu "default range of %s but is not a " \ 5305655Sgblack@eecs.umich.edu "subset\n", r->to_string(), name()); 5315655Sgblack@eecs.umich.edu } 5325689Sgblack@eecs.umich.edu } 5335655Sgblack@eecs.umich.edu 5345655Sgblack@eecs.umich.edu // tell all our neighbouring master ports that our address 5355689Sgblack@eecs.umich.edu // ranges have changed 5365655Sgblack@eecs.umich.edu for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 5375655Sgblack@eecs.umich.edu ++s) 5385689Sgblack@eecs.umich.edu (*s)->sendRangeChange(); 5395655Sgblack@eecs.umich.edu } 5405655Sgblack@eecs.umich.edu 5415655Sgblack@eecs.umich.edu clearPortCache(); 5425655Sgblack@eecs.umich.edu} 5435655Sgblack@eecs.umich.edu 5445655Sgblack@eecs.umich.eduAddrRangeList 5455655Sgblack@eecs.umich.eduBaseBus::getAddrRanges() const 5465689Sgblack@eecs.umich.edu{ 5475655Sgblack@eecs.umich.edu // we should never be asked without first having sent a range 5485655Sgblack@eecs.umich.edu // change, and the latter is only done once we have all the ranges 5495655Sgblack@eecs.umich.edu // of the connected devices 5505655Sgblack@eecs.umich.edu assert(gotAllAddrRanges); 5515655Sgblack@eecs.umich.edu 5525655Sgblack@eecs.umich.edu // at the moment, this never happens, as there are no cycles in 5535655Sgblack@eecs.umich.edu // the range queries and no devices on the master side of a bus 5545654Sgblack@eecs.umich.edu // (CPU, cache, bridge etc) actually care about the ranges of the 5555654Sgblack@eecs.umich.edu // ports they are connected to 5565647Sgblack@eecs.umich.edu 5575647Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Received address range request\n"); 5585647Sgblack@eecs.umich.edu 5595647Sgblack@eecs.umich.edu return busRanges; 5605647Sgblack@eecs.umich.edu} 561 562unsigned 563BaseBus::deviceBlockSize() const 564{ 565 return blockSize; 566} 567 568void 569BaseBus::regStats() 570{ 571 using namespace Stats; 572 573 transDist 574 .init(MemCmd::NUM_MEM_CMDS) 575 .name(name() + ".trans_dist") 576 .desc("Transaction distribution") 577 .flags(nozero); 578 579 // get the string representation of the commands 580 for (int i = 0; i < MemCmd::NUM_MEM_CMDS; i++) { 581 MemCmd cmd(i); 582 const std::string &cstr = cmd.toString(); 583 transDist.subname(i, cstr); 584 } 585 586 pktCount 587 .init(slavePorts.size(), masterPorts.size()) 588 .name(name() + ".pkt_count") 589 .desc("Packet count per connected master and slave (bytes)") 590 .flags(total | nozero | nonan); 591 592 totPktSize 593 .init(slavePorts.size(), masterPorts.size()) 594 .name(name() + ".tot_pkt_size") 595 .desc("Cumulative packet size per connected master and slave (bytes)") 596 .flags(total | nozero | nonan); 597 598 // both the packet count and total size are two-dimensional 599 // vectors, indexed by slave port id and master port id, thus the 600 // neighbouring master and slave, they do not differentiate what 601 // came from the master and was forwarded to the slave (requests 602 // and snoop responses) and what came from the slave and was 603 // forwarded to the master (responses and snoop requests) 604 for (int i = 0; i < slavePorts.size(); i++) { 605 pktCount.subname(i, slavePorts[i]->getMasterPort().name()); 606 totPktSize.subname(i, slavePorts[i]->getMasterPort().name()); 607 for (int j = 0; j < masterPorts.size(); j++) { 608 pktCount.ysubname(j, masterPorts[j]->getSlavePort().name()); 609 totPktSize.ysubname(j, masterPorts[j]->getSlavePort().name()); 610 } 611 } 612} 613 614template <typename SrcType, typename DstType> 615unsigned int 616BaseBus::Layer<SrcType,DstType>::drain(DrainManager *dm) 617{ 618 //We should check that we're not "doing" anything, and that noone is 619 //waiting. We might be idle but have someone waiting if the device we 620 //contacted for a retry didn't actually retry. 621 if (state != IDLE) { 622 DPRINTF(Drain, "Bus not drained\n"); 623 drainManager = dm; 624 return 1; 625 } 626 return 0; 627} 628 629template <typename SrcType, typename DstType> 630void 631BaseBus::Layer<SrcType,DstType>::regStats() 632{ 633 using namespace Stats; 634 635 occupancy 636 .name(name() + ".occupancy") 637 .desc("Layer occupancy (ticks)") 638 .flags(nozero); 639 640 utilization 641 .name(name() + ".utilization") 642 .desc("Layer utilization (%)") 643 .precision(1) 644 .flags(nozero); 645 646 utilization = 100 * occupancy / simTicks; 647} 648 649/** 650 * Bus layer template instantiations. Could be removed with _impl.hh 651 * file, but since there are only two given options (MasterPort and 652 * SlavePort) it seems a bit excessive at this point. 653 */ 654template class BaseBus::Layer<SlavePort,MasterPort>; 655template class BaseBus::Layer<MasterPort,SlavePort>; 656