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