coherent_xbar.cc revision 8711
12568SN/A/* 22568SN/A * Copyright (c) 2011 ARM Limited 32568SN/A * All rights reserved 42568SN/A * 52568SN/A * The license below extends only to copyright in the software and shall 62568SN/A * not be construed as granting a license to any other intellectual 72568SN/A * property including but not limited to intellectual property relating 82568SN/A * to a hardware implementation of the functionality of the software 92568SN/A * licensed hereunder. You may use the software subject to the license 102568SN/A * terms below provided that you ensure that this notice is replicated 112568SN/A * unmodified and in its entirety in all distributions of the software, 122568SN/A * modified or unmodified, in source code or in binary form. 132568SN/A * 142568SN/A * Copyright (c) 2006 The Regents of The University of Michigan 152568SN/A * All rights reserved. 162568SN/A * 172568SN/A * Redistribution and use in source and binary forms, with or without 182568SN/A * modification, are permitted provided that the following conditions are 192568SN/A * met: redistributions of source code must retain the above copyright 202568SN/A * notice, this list of conditions and the following disclaimer; 212568SN/A * redistributions in binary form must reproduce the above copyright 222568SN/A * notice, this list of conditions and the following disclaimer in the 232568SN/A * documentation and/or other materials provided with the distribution; 242568SN/A * neither the name of the copyright holders nor the names of its 252568SN/A * contributors may be used to endorse or promote products derived from 262568SN/A * this software without specific prior written permission. 272568SN/A * 282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312568SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322568SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332568SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342982Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352982Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362568SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372568SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382643Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392568SN/A * 404965Ssaidi@eecs.umich.edu * Authors: Ali Saidi 412568SN/A */ 422568SN/A 434762Snate@binkert.org/** 442568SN/A * @file 452643Sstever@eecs.umich.edu * Definition of a bus object. 462643Sstever@eecs.umich.edu */ 474435Ssaidi@eecs.umich.edu 484965Ssaidi@eecs.umich.edu#include <algorithm> 494965Ssaidi@eecs.umich.edu#include <limits> 505606Snate@binkert.org 514965Ssaidi@eecs.umich.edu#include "base/misc.hh" 524435Ssaidi@eecs.umich.edu#include "base/trace.hh" 534435Ssaidi@eecs.umich.edu#include "debug/Bus.hh" 542643Sstever@eecs.umich.edu#include "debug/BusAddrRanges.hh" 552643Sstever@eecs.umich.edu#include "debug/MMU.hh" 562643Sstever@eecs.umich.edu#include "mem/bus.hh" 574435Ssaidi@eecs.umich.edu 585034Smilesck@eecs.umich.eduBus::Bus(const BusParams *p) 594435Ssaidi@eecs.umich.edu : MemObject(p), busId(p->bus_id), clock(p->clock), 604965Ssaidi@eecs.umich.edu headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), 614435Ssaidi@eecs.umich.edu drainEvent(NULL), busIdle(this), inRetry(false), maxId(0), 624965Ssaidi@eecs.umich.edu defaultPort(NULL), funcPort(NULL), funcPortId(-4), 634435Ssaidi@eecs.umich.edu useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size), 642643Sstever@eecs.umich.edu cachedBlockSize(0), cachedBlockSizeValid(false) 654432Ssaidi@eecs.umich.edu{ 664432Ssaidi@eecs.umich.edu //width, clock period, and header cycles must be positive 672643Sstever@eecs.umich.edu if (width <= 0) 682643Sstever@eecs.umich.edu fatal("Bus width must be positive\n"); 692643Sstever@eecs.umich.edu if (clock <= 0) 702738Sstever@eecs.umich.edu fatal("Bus clock period must be positive\n"); 712643Sstever@eecs.umich.edu if (headerCycles <= 0) 722643Sstever@eecs.umich.edu fatal("Number of header cycles must be positive\n"); 732643Sstever@eecs.umich.edu clearBusCache(); 742643Sstever@eecs.umich.edu clearPortCache(); 752643Sstever@eecs.umich.edu} 762643Sstever@eecs.umich.edu 772643Sstever@eecs.umich.eduPort * 782643Sstever@eecs.umich.eduBus::getPort(const std::string &if_name, int idx) 792643Sstever@eecs.umich.edu{ 802643Sstever@eecs.umich.edu if (if_name == "default") { 815283Sgblack@eecs.umich.edu if (defaultPort == NULL) { 825283Sgblack@eecs.umich.edu defaultPort = new BusPort(csprintf("%s-default",name()), this, 835283Sgblack@eecs.umich.edu defaultId); 842643Sstever@eecs.umich.edu cachedBlockSizeValid = false; 852643Sstever@eecs.umich.edu return defaultPort; 862643Sstever@eecs.umich.edu } else 872643Sstever@eecs.umich.edu fatal("Default port already set\n"); 882568SN/A } 892568SN/A int id; 902568SN/A if (if_name == "functional") { 912568SN/A if (!funcPort) { 925476Snate@binkert.org id = maxId++; 934432Ssaidi@eecs.umich.edu funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); 944432Ssaidi@eecs.umich.edu funcPortId = id; 954432Ssaidi@eecs.umich.edu interfaces[id] = funcPort; 966764SBrad.Beckmann@amd.com } 976764SBrad.Beckmann@amd.com return funcPort; 986764SBrad.Beckmann@amd.com } 992568SN/A 1002568SN/A // if_name ignored? forced to be empty? 1014433Ssaidi@eecs.umich.edu id = maxId++; 1024435Ssaidi@eecs.umich.edu assert(maxId < std::numeric_limits<typeof(maxId)>::max()); 1034433Ssaidi@eecs.umich.edu BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 1044435Ssaidi@eecs.umich.edu interfaces[id] = bp; 1054435Ssaidi@eecs.umich.edu cachedBlockSizeValid = false; 1064435Ssaidi@eecs.umich.edu return bp; 1074435Ssaidi@eecs.umich.edu} 1084435Ssaidi@eecs.umich.edu 1094435Ssaidi@eecs.umich.eduvoid 1104435Ssaidi@eecs.umich.eduBus::init() 1114435Ssaidi@eecs.umich.edu{ 1124435Ssaidi@eecs.umich.edu m5::hash_map<short,BusPort*>::iterator intIter; 1134433Ssaidi@eecs.umich.edu 1142568SN/A // iterate over our interfaces and determine which of our neighbours 1152643Sstever@eecs.umich.edu // are snooping and add them as snoopers 1162568SN/A for (intIter = interfaces.begin(); intIter != interfaces.end(); 1172568SN/A intIter++) { 1183349Sbinkertn@umich.edu if (intIter->second->getPeer()->isSnooping()) { 1192568SN/A DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n", 1204433Ssaidi@eecs.umich.edu intIter->second->getPeer()->name()); 1213662Srdreslin@umich.edu snoopPorts.push_back(intIter->second); 1222643Sstever@eecs.umich.edu } 1234450Ssaidi@eecs.umich.edu } 1244450Ssaidi@eecs.umich.edu} 1254986Ssaidi@eecs.umich.edu 1264450Ssaidi@eecs.umich.eduBus::BusFreeEvent::BusFreeEvent(Bus *_bus) 1274450Ssaidi@eecs.umich.edu : bus(_bus) 1284450Ssaidi@eecs.umich.edu{} 1294986Ssaidi@eecs.umich.edu 1304433Ssaidi@eecs.umich.eduvoid 1314433Ssaidi@eecs.umich.eduBus::BusFreeEvent::process() 1324433Ssaidi@eecs.umich.edu{ 1333662Srdreslin@umich.edu bus->recvRetry(-1); 1344433Ssaidi@eecs.umich.edu} 1355562Snate@binkert.org 1364435Ssaidi@eecs.umich.educonst char * 1374433Ssaidi@eecs.umich.eduBus::BusFreeEvent::description() const 1384433Ssaidi@eecs.umich.edu{ 1394433Ssaidi@eecs.umich.edu return "bus became available"; 1404433Ssaidi@eecs.umich.edu} 1414433Ssaidi@eecs.umich.edu 1424433Ssaidi@eecs.umich.eduTick 1434433Ssaidi@eecs.umich.eduBus::calcPacketTiming(PacketPtr pkt) 1444433Ssaidi@eecs.umich.edu{ 1454433Ssaidi@eecs.umich.edu // Bring tickNextIdle up to the present tick. 1465562Snate@binkert.org // There is some potential ambiguity where a cycle starts, which 1474433Ssaidi@eecs.umich.edu // might make a difference when devices are acting right around a 1484433Ssaidi@eecs.umich.edu // cycle boundary. Using a < allows things which happen exactly on 1494433Ssaidi@eecs.umich.edu // a cycle boundary to take up only the following cycle. Anything 1504433Ssaidi@eecs.umich.edu // that happens later will have to "wait" for the end of that 1512657Ssaidi@eecs.umich.edu // cycle, and then start using the bus after that. 1522657Ssaidi@eecs.umich.edu if (tickNextIdle < curTick()) { 1534433Ssaidi@eecs.umich.edu tickNextIdle = curTick(); 1544433Ssaidi@eecs.umich.edu if (tickNextIdle % clock != 0) 1554433Ssaidi@eecs.umich.edu tickNextIdle = curTick() - (curTick() % clock) + clock; 1564433Ssaidi@eecs.umich.edu } 1574986Ssaidi@eecs.umich.edu 1584870Sstever@eecs.umich.edu Tick headerTime = tickNextIdle + headerCycles * clock; 1592657Ssaidi@eecs.umich.edu 1604433Ssaidi@eecs.umich.edu // The packet will be sent. Figure out how long it occupies the bus, and 1614435Ssaidi@eecs.umich.edu // how much of that time is for the first "word", aka bus width. 1624433Ssaidi@eecs.umich.edu int numCycles = 0; 1634435Ssaidi@eecs.umich.edu if (pkt->hasData()) { 1644435Ssaidi@eecs.umich.edu // If a packet has data, it needs ceil(size/width) cycles to send it 1654433Ssaidi@eecs.umich.edu int dataSize = pkt->getSize(); 1664435Ssaidi@eecs.umich.edu numCycles += dataSize/width; 1675606Snate@binkert.org if (dataSize % width) 1684435Ssaidi@eecs.umich.edu numCycles++; 1694435Ssaidi@eecs.umich.edu } 1704433Ssaidi@eecs.umich.edu 1714435Ssaidi@eecs.umich.edu // The first word will be delivered after the current tick, the delivery 1724435Ssaidi@eecs.umich.edu // of the address if any, and one bus cycle to deliver the data 1734435Ssaidi@eecs.umich.edu pkt->firstWordTime = headerTime + clock; 1744435Ssaidi@eecs.umich.edu 1754435Ssaidi@eecs.umich.edu pkt->finishTime = headerTime + numCycles * clock; 1764435Ssaidi@eecs.umich.edu 1774435Ssaidi@eecs.umich.edu return headerTime; 1784435Ssaidi@eecs.umich.edu} 1794435Ssaidi@eecs.umich.edu 1804435Ssaidi@eecs.umich.eduvoid Bus::occupyBus(Tick until) 1814435Ssaidi@eecs.umich.edu{ 1824435Ssaidi@eecs.umich.edu if (until == 0) { 1834435Ssaidi@eecs.umich.edu // shortcut for express snoop packets 1844435Ssaidi@eecs.umich.edu return; 1854435Ssaidi@eecs.umich.edu } 1864435Ssaidi@eecs.umich.edu 1874435Ssaidi@eecs.umich.edu tickNextIdle = until; 1884435Ssaidi@eecs.umich.edu reschedule(busIdle, tickNextIdle, true); 1895606Snate@binkert.org 1904435Ssaidi@eecs.umich.edu DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 1914435Ssaidi@eecs.umich.edu curTick(), tickNextIdle); 1924435Ssaidi@eecs.umich.edu} 1934435Ssaidi@eecs.umich.edu 1944435Ssaidi@eecs.umich.edu/** Function called by the port when the bus is receiving a Timing 1954435Ssaidi@eecs.umich.edu * transaction.*/ 1964433Ssaidi@eecs.umich.edubool 1974433Ssaidi@eecs.umich.eduBus::recvTiming(PacketPtr pkt) 1984433Ssaidi@eecs.umich.edu{ 1994433Ssaidi@eecs.umich.edu short src = pkt->getSrc(); 2003349Sbinkertn@umich.edu 2012657Ssaidi@eecs.umich.edu BusPort *src_port; 2024986Ssaidi@eecs.umich.edu if (src == defaultId) 2032643Sstever@eecs.umich.edu src_port = defaultPort; 2042643Sstever@eecs.umich.edu else { 2052643Sstever@eecs.umich.edu src_port = checkBusCache(src); 2064986Ssaidi@eecs.umich.edu if (src_port == NULL) { 2072643Sstever@eecs.umich.edu src_port = interfaces[src]; 2082643Sstever@eecs.umich.edu updateBusCache(src, src_port); 2092643Sstever@eecs.umich.edu } 2102643Sstever@eecs.umich.edu } 2112643Sstever@eecs.umich.edu 2124433Ssaidi@eecs.umich.edu // If the bus is busy, or other devices are in line ahead of the current 2134739Sstever@eecs.umich.edu // one, put this device on the retry list. 2142643Sstever@eecs.umich.edu if (!pkt->isExpressSnoop() && 2152643Sstever@eecs.umich.edu (tickNextIdle > curTick() || 2162643Sstever@eecs.umich.edu (retryList.size() && (!inRetry || src_port != retryList.front())))) 2174450Ssaidi@eecs.umich.edu { 2184986Ssaidi@eecs.umich.edu addToRetryList(src_port); 2194450Ssaidi@eecs.umich.edu DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n", 2204450Ssaidi@eecs.umich.edu src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 2214450Ssaidi@eecs.umich.edu return false; 2224450Ssaidi@eecs.umich.edu } 2234450Ssaidi@eecs.umich.edu 2242643Sstever@eecs.umich.edu DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n", 2252643Sstever@eecs.umich.edu src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 2262643Sstever@eecs.umich.edu 2272643Sstever@eecs.umich.edu Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt); 2282643Sstever@eecs.umich.edu Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime; 2292643Sstever@eecs.umich.edu 2302643Sstever@eecs.umich.edu short dest = pkt->getDest(); 2312643Sstever@eecs.umich.edu int dest_port_id; 2325606Snate@binkert.org Port *dest_port; 2332568SN/A 2342643Sstever@eecs.umich.edu if (dest == Packet::Broadcast) { 2352568SN/A dest_port_id = findPort(pkt->getAddr()); 2362568SN/A dest_port = (dest_port_id == defaultId) ? 2372568SN/A defaultPort : interfaces[dest_port_id]; 2382643Sstever@eecs.umich.edu SnoopIter s_end = snoopPorts.end(); 2392568SN/A for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 2402643Sstever@eecs.umich.edu BusPort *p = *s_iter; 2412568SN/A if (p != dest_port && p != src_port) { 2422643Sstever@eecs.umich.edu // cache is not allowed to refuse snoop 2432643Sstever@eecs.umich.edu bool success M5_VAR_USED = p->sendTiming(pkt); 2442643Sstever@eecs.umich.edu assert(success); 2452643Sstever@eecs.umich.edu } 2463349Sbinkertn@umich.edu } 2472643Sstever@eecs.umich.edu } else { 2482643Sstever@eecs.umich.edu assert(dest < maxId); 2492643Sstever@eecs.umich.edu assert(dest != src); // catch infinite loops 2502643Sstever@eecs.umich.edu dest_port_id = dest; 2514450Ssaidi@eecs.umich.edu if (dest_port_id == defaultId) 2524986Ssaidi@eecs.umich.edu dest_port = defaultPort; 2534986Ssaidi@eecs.umich.edu else { 2544986Ssaidi@eecs.umich.edu dest_port = checkBusCache(dest); 2554986Ssaidi@eecs.umich.edu if (dest_port == NULL) { 2564986Ssaidi@eecs.umich.edu dest_port = interfaces[dest_port_id]; 2574986Ssaidi@eecs.umich.edu // updateBusCache(dest_port_id, dest_port); 2584986Ssaidi@eecs.umich.edu } 2594986Ssaidi@eecs.umich.edu } 2604986Ssaidi@eecs.umich.edu dest_port = (dest_port_id == defaultId) ? 2614432Ssaidi@eecs.umich.edu defaultPort : interfaces[dest_port_id]; 2622643Sstever@eecs.umich.edu } 2632643Sstever@eecs.umich.edu 2642643Sstever@eecs.umich.edu if (dest_port_id == src) { 2652643Sstever@eecs.umich.edu // Must be forwarded snoop up from below... 2662657Ssaidi@eecs.umich.edu assert(dest == Packet::Broadcast); 2672657Ssaidi@eecs.umich.edu } else { 2684433Ssaidi@eecs.umich.edu // send to actual target 2692657Ssaidi@eecs.umich.edu if (!dest_port->sendTiming(pkt)) { 2702657Ssaidi@eecs.umich.edu // Packet not successfully sent. Leave or put it on the retry list. 2712657Ssaidi@eecs.umich.edu // illegal to block responses... can lead to deadlock 2722657Ssaidi@eecs.umich.edu assert(!pkt->isResponse()); 2732657Ssaidi@eecs.umich.edu // It's also illegal to force a transaction to retry after 2742657Ssaidi@eecs.umich.edu // someone else has committed to respond. 2752657Ssaidi@eecs.umich.edu assert(!pkt->memInhibitAsserted()); 2762657Ssaidi@eecs.umich.edu DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n", 2774986Ssaidi@eecs.umich.edu src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 2784986Ssaidi@eecs.umich.edu addToRetryList(src_port); 2794986Ssaidi@eecs.umich.edu occupyBus(headerFinishTime); 2804986Ssaidi@eecs.umich.edu return false; 2814433Ssaidi@eecs.umich.edu } 2822657Ssaidi@eecs.umich.edu // send OK, fall through... pkt may have been deleted by 2832657Ssaidi@eecs.umich.edu // target at this point, so it should *not* be referenced 2842657Ssaidi@eecs.umich.edu // again. We'll set it to NULL here just to be safe. 2854433Ssaidi@eecs.umich.edu pkt = NULL; 2865606Snate@binkert.org } 2872657Ssaidi@eecs.umich.edu 2882643Sstever@eecs.umich.edu occupyBus(packetFinishTime); 2892643Sstever@eecs.umich.edu 2904986Ssaidi@eecs.umich.edu // Packet was successfully sent. 2914435Ssaidi@eecs.umich.edu // Also take care of retries 2922643Sstever@eecs.umich.edu if (inRetry) { 2934986Ssaidi@eecs.umich.edu DPRINTF(Bus, "Remove retry from list %d\n", src); 2944433Ssaidi@eecs.umich.edu retryList.front()->onRetryList(false); 2954433Ssaidi@eecs.umich.edu retryList.pop_front(); 2962568SN/A inRetry = false; 2972568SN/A } 2982568SN/A return true; 2992657Ssaidi@eecs.umich.edu} 3002568SN/A 3012568SN/Avoid 3024435Ssaidi@eecs.umich.eduBus::recvRetry(int id) 3034435Ssaidi@eecs.umich.edu{ 3044435Ssaidi@eecs.umich.edu // If there's anything waiting, and the bus isn't busy... 3054435Ssaidi@eecs.umich.edu if (retryList.size() && curTick() >= tickNextIdle) { 3064435Ssaidi@eecs.umich.edu //retryingPort = retryList.front(); 3075606Snate@binkert.org inRetry = true; 3082568SN/A DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 3092568SN/A retryList.front()->sendRetry(); 3102643Sstever@eecs.umich.edu // If inRetry is still true, sendTiming wasn't called 3112568SN/A if (inRetry) 3122568SN/A { 3133349Sbinkertn@umich.edu retryList.front()->onRetryList(false); 3142568SN/A retryList.pop_front(); 3154454Ssaidi@eecs.umich.edu inRetry = false; 3162568SN/A 3172568SN/A //Bring tickNextIdle up to the present 3182643Sstever@eecs.umich.edu while (tickNextIdle < curTick()) 3192568SN/A tickNextIdle += clock; 3202568SN/A 3213349Sbinkertn@umich.edu //Burn a cycle for the missed grant. 3222568SN/A tickNextIdle += clock; 3232643Sstever@eecs.umich.edu 3242568SN/A reschedule(busIdle, tickNextIdle, true); 3255314Sstever@gmail.com } 3265314Sstever@gmail.com } 3272643Sstever@eecs.umich.edu //If we weren't able to drain before, we might be able to now. 3287668Ssteve.reinhardt@amd.com if (drainEvent && retryList.size() == 0 && curTick() >= tickNextIdle) { 3297668Ssteve.reinhardt@amd.com drainEvent->process(); 3304626Sstever@eecs.umich.edu // Clear the drain event once we're done with it. 3317668Ssteve.reinhardt@amd.com drainEvent = NULL; 3322568SN/A } 3332568SN/A} 3345314Sstever@gmail.com 3355314Sstever@gmail.comint 3364626Sstever@eecs.umich.eduBus::findPort(Addr addr) 3374626Sstever@eecs.umich.edu{ 3382568SN/A /* An interval tree would be a better way to do this. --ali. */ 3392568SN/A int dest_id; 3402643Sstever@eecs.umich.edu 3412568SN/A dest_id = checkPortCache(addr); 3422643Sstever@eecs.umich.edu if (dest_id != -1) 3432568SN/A return dest_id; 3442643Sstever@eecs.umich.edu 3452568SN/A // Check normal port ranges 3462568SN/A PortIter i = portMap.find(RangeSize(addr,1)); 3472568SN/A if (i != portMap.end()) { 3482643Sstever@eecs.umich.edu dest_id = i->second; 3494475Sstever@eecs.umich.edu updatePortCache(dest_id, i->first.start, i->first.end); 3502568SN/A return dest_id; 3512643Sstever@eecs.umich.edu } 3524965Ssaidi@eecs.umich.edu 3534877Sstever@eecs.umich.edu // Check if this matches the default range 3544877Sstever@eecs.umich.edu if (useDefaultRange) { 3552568SN/A AddrRangeIter a_end = defaultRange.end(); 3562568SN/A for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { 3574762Snate@binkert.org if (*i == addr) { 3584762Snate@binkert.org DPRINTF(Bus, " found addr %#llx on default\n", addr); 3592568SN/A return defaultId; 3604762Snate@binkert.org } 3612568SN/A } 362 363 panic("Unable to find destination for addr %#llx\n", addr); 364 } 365 366 DPRINTF(Bus, "Unable to find destination for addr %#llx, " 367 "will use default port\n", addr); 368 return defaultId; 369} 370 371 372/** Function called by the port when the bus is receiving a Atomic 373 * transaction.*/ 374Tick 375Bus::recvAtomic(PacketPtr pkt) 376{ 377 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 378 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 379 assert(pkt->getDest() == Packet::Broadcast); 380 assert(pkt->isRequest()); 381 382 // Variables for recording original command and snoop response (if 383 // any)... if a snooper respondes, we will need to restore 384 // original command so that additional snoops can take place 385 // properly 386 MemCmd orig_cmd = pkt->cmd; 387 MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 388 Tick snoop_response_latency = 0; 389 int orig_src = pkt->getSrc(); 390 391 int target_port_id = findPort(pkt->getAddr()); 392 BusPort *target_port; 393 if (target_port_id == defaultId) 394 target_port = defaultPort; 395 else { 396 target_port = checkBusCache(target_port_id); 397 if (target_port == NULL) { 398 target_port = interfaces[target_port_id]; 399 updateBusCache(target_port_id, target_port); 400 } 401 } 402 403 SnoopIter s_end = snoopPorts.end(); 404 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 405 BusPort *p = *s_iter; 406 // same port should not have both target addresses and snooping 407 assert(p != target_port); 408 if (p->getId() != pkt->getSrc()) { 409 Tick latency = p->sendAtomic(pkt); 410 if (pkt->isResponse()) { 411 // response from snoop agent 412 assert(pkt->cmd != orig_cmd); 413 assert(pkt->memInhibitAsserted()); 414 // should only happen once 415 assert(snoop_response_cmd == MemCmd::InvalidCmd); 416 // save response state 417 snoop_response_cmd = pkt->cmd; 418 snoop_response_latency = latency; 419 // restore original packet state for remaining snoopers 420 pkt->cmd = orig_cmd; 421 pkt->setSrc(orig_src); 422 pkt->setDest(Packet::Broadcast); 423 } 424 } 425 } 426 427 Tick response_latency = 0; 428 429 // we can get requests sent up from the memory side of the bus for 430 // snooping... don't send them back down! 431 if (target_port_id != pkt->getSrc()) { 432 response_latency = target_port->sendAtomic(pkt); 433 } 434 435 // if we got a response from a snooper, restore it here 436 if (snoop_response_cmd != MemCmd::InvalidCmd) { 437 // no one else should have responded 438 assert(!pkt->isResponse()); 439 assert(pkt->cmd == orig_cmd); 440 pkt->cmd = snoop_response_cmd; 441 response_latency = snoop_response_latency; 442 } 443 444 // why do we have this packet field and the return value both??? 445 pkt->finishTime = curTick() + response_latency; 446 return response_latency; 447} 448 449/** Function called by the port when the bus is receiving a Functional 450 * transaction.*/ 451void 452Bus::recvFunctional(PacketPtr pkt) 453{ 454 assert(pkt->getDest() == Packet::Broadcast); 455 456 int port_id = findPort(pkt->getAddr()); 457 Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id]; 458 // The packet may be changed by another bus on snoops, restore the 459 // id after each 460 int src_id = pkt->getSrc(); 461 462 if (!pkt->isPrint()) { 463 // don't do DPRINTFs on PrintReq as it clutters up the output 464 DPRINTF(Bus, 465 "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 466 src_id, port_id, pkt->getAddr(), 467 pkt->cmdString()); 468 } 469 470 assert(pkt->isRequest()); // hasn't already been satisfied 471 472 SnoopIter s_end = snoopPorts.end(); 473 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 474 BusPort *p = *s_iter; 475 if (p != port && p->getId() != src_id) { 476 p->sendFunctional(pkt); 477 } 478 if (pkt->isResponse()) { 479 break; 480 } 481 pkt->setSrc(src_id); 482 } 483 484 // If the snooping hasn't found what we were looking for, keep going. 485 if (!pkt->isResponse() && port_id != pkt->getSrc()) { 486 port->sendFunctional(pkt); 487 } 488} 489 490/** Function called by the port when the bus is receiving a range change.*/ 491void 492Bus::recvRangeChange(int id) 493{ 494 AddrRangeList ranges; 495 AddrRangeIter iter; 496 497 if (inRecvRangeChange.count(id)) 498 return; 499 inRecvRangeChange.insert(id); 500 501 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 502 503 clearPortCache(); 504 if (id == defaultId) { 505 defaultRange.clear(); 506 // Only try to update these ranges if the user set a default responder. 507 if (useDefaultRange) { 508 AddrRangeList ranges = defaultPort->getPeer()->getAddrRanges(); 509 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 510 defaultRange.push_back(*iter); 511 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 512 iter->start, iter->end); 513 } 514 } 515 } else { 516 517 assert((id < maxId && id >= 0) || id == defaultId); 518 BusPort *port = interfaces[id]; 519 520 // Clean out any previously existent ids 521 for (PortIter portIter = portMap.begin(); 522 portIter != portMap.end(); ) { 523 if (portIter->second == id) 524 portMap.erase(portIter++); 525 else 526 portIter++; 527 } 528 529 ranges = port->getPeer()->getAddrRanges(); 530 531 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 532 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 533 iter->start, iter->end, id); 534 if (portMap.insert(*iter, id) == portMap.end()) { 535 int conflict_id = portMap.find(*iter)->second; 536 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 537 name(), interfaces[id]->getPeer()->name(), 538 interfaces[conflict_id]->getPeer()->name()); 539 } 540 } 541 } 542 DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 543 544 // tell all our peers that our address range has changed. 545 // Don't tell the device that caused this change, it already knows 546 m5::hash_map<short,BusPort*>::iterator intIter; 547 548 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 549 if (intIter->first != id && intIter->first != funcPortId) 550 intIter->second->sendRangeChange(); 551 552 if (id != defaultId && defaultPort) 553 defaultPort->sendRangeChange(); 554 inRecvRangeChange.erase(id); 555} 556 557AddrRangeList 558Bus::getAddrRanges(int id) 559{ 560 AddrRangeList ranges; 561 562 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 563 564 for (AddrRangeIter dflt_iter = defaultRange.begin(); 565 dflt_iter != defaultRange.end(); dflt_iter++) { 566 ranges.push_back(*dflt_iter); 567 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 568 dflt_iter->end); 569 } 570 for (PortIter portIter = portMap.begin(); 571 portIter != portMap.end(); portIter++) { 572 bool subset = false; 573 for (AddrRangeIter dflt_iter = defaultRange.begin(); 574 dflt_iter != defaultRange.end(); dflt_iter++) { 575 if ((portIter->first.start < dflt_iter->start && 576 portIter->first.end >= dflt_iter->start) || 577 (portIter->first.start < dflt_iter->end && 578 portIter->first.end >= dflt_iter->end)) 579 fatal("Devices can not set ranges that itersect the default set\ 580 but are not a subset of the default set.\n"); 581 if (portIter->first.start >= dflt_iter->start && 582 portIter->first.end <= dflt_iter->end) { 583 subset = true; 584 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 585 portIter->first.start, portIter->first.end); 586 } 587 } 588 if (portIter->second != id && !subset) { 589 ranges.push_back(portIter->first); 590 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 591 portIter->first.start, portIter->first.end); 592 } 593 } 594 595 return ranges; 596} 597 598bool 599Bus::isSnooping(int id) 600{ 601 // in essence, answer the question if there are other snooping 602 // ports rather than the port that is asking 603 bool snoop = false; 604 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 605 s_iter++) { 606 if ((*s_iter)->getId() != id) { 607 snoop = true; 608 break; 609 } 610 } 611 return snoop; 612} 613 614unsigned 615Bus::findBlockSize(int id) 616{ 617 if (cachedBlockSizeValid) 618 return cachedBlockSize; 619 620 unsigned max_bs = 0; 621 622 PortIter p_end = portMap.end(); 623 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { 624 unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize(); 625 if (tmp_bs > max_bs) 626 max_bs = tmp_bs; 627 } 628 SnoopIter s_end = snoopPorts.end(); 629 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 630 unsigned tmp_bs = (*s_iter)->peerBlockSize(); 631 if (tmp_bs > max_bs) 632 max_bs = tmp_bs; 633 } 634 if (max_bs == 0) 635 max_bs = defaultBlockSize; 636 637 if (max_bs != 64) 638 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 639 cachedBlockSize = max_bs; 640 cachedBlockSizeValid = true; 641 return max_bs; 642} 643 644 645unsigned int 646Bus::drain(Event * de) 647{ 648 //We should check that we're not "doing" anything, and that noone is 649 //waiting. We might be idle but have someone waiting if the device we 650 //contacted for a retry didn't actually retry. 651 if (retryList.size() || (curTick() < tickNextIdle && busIdle.scheduled())) { 652 drainEvent = de; 653 return 1; 654 } 655 return 0; 656} 657 658void 659Bus::startup() 660{ 661 if (tickNextIdle < curTick()) 662 tickNextIdle = (curTick() / clock) * clock + clock; 663} 664 665Bus * 666BusParams::create() 667{ 668 return new Bus(this); 669} 670