coherent_xbar.cc revision 7523
16242Sgblack@eecs.umich.edu/* 27093Sgblack@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan 37093Sgblack@eecs.umich.edu * All rights reserved. 47093Sgblack@eecs.umich.edu * 57093Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67093Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 77093Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 87093Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 97093Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 107093Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 117093Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 127093Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 137093Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 146242Sgblack@eecs.umich.edu * this software without specific prior written permission. 156242Sgblack@eecs.umich.edu * 166242Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176242Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186242Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196242Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206242Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216242Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226242Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236242Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246242Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256242Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266242Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276242Sgblack@eecs.umich.edu * 286242Sgblack@eecs.umich.edu * Authors: Ali Saidi 296242Sgblack@eecs.umich.edu */ 306242Sgblack@eecs.umich.edu 316242Sgblack@eecs.umich.edu/** 326242Sgblack@eecs.umich.edu * @file 336242Sgblack@eecs.umich.edu * Definition of a bus object. 346242Sgblack@eecs.umich.edu */ 356242Sgblack@eecs.umich.edu 366242Sgblack@eecs.umich.edu#include <algorithm> 376242Sgblack@eecs.umich.edu#include <limits> 386242Sgblack@eecs.umich.edu 396242Sgblack@eecs.umich.edu#include "base/misc.hh" 406242Sgblack@eecs.umich.edu#include "base/trace.hh" 416242Sgblack@eecs.umich.edu#include "mem/bus.hh" 426242Sgblack@eecs.umich.edu 436242Sgblack@eecs.umich.eduBus::Bus(const BusParams *p) 446242Sgblack@eecs.umich.edu : MemObject(p), busId(p->bus_id), clock(p->clock), 456242Sgblack@eecs.umich.edu headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), 466242Sgblack@eecs.umich.edu drainEvent(NULL), busIdle(this), inRetry(false), maxId(0), 476242Sgblack@eecs.umich.edu defaultPort(NULL), funcPort(NULL), funcPortId(-4), 486242Sgblack@eecs.umich.edu useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size), 496242Sgblack@eecs.umich.edu cachedBlockSize(0), cachedBlockSizeValid(false) 506242Sgblack@eecs.umich.edu{ 516242Sgblack@eecs.umich.edu //width, clock period, and header cycles must be positive 526242Sgblack@eecs.umich.edu if (width <= 0) 536242Sgblack@eecs.umich.edu fatal("Bus width must be positive\n"); 546242Sgblack@eecs.umich.edu if (clock <= 0) 556242Sgblack@eecs.umich.edu fatal("Bus clock period must be positive\n"); 566242Sgblack@eecs.umich.edu if (headerCycles <= 0) 576242Sgblack@eecs.umich.edu fatal("Number of header cycles must be positive\n"); 586242Sgblack@eecs.umich.edu clearBusCache(); 596242Sgblack@eecs.umich.edu clearPortCache(); 606242Sgblack@eecs.umich.edu} 616242Sgblack@eecs.umich.edu 626242Sgblack@eecs.umich.eduPort * 636242Sgblack@eecs.umich.eduBus::getPort(const std::string &if_name, int idx) 646242Sgblack@eecs.umich.edu{ 657111Sgblack@eecs.umich.edu if (if_name == "default") { 666242Sgblack@eecs.umich.edu if (defaultPort == NULL) { 676242Sgblack@eecs.umich.edu defaultPort = new BusPort(csprintf("%s-default",name()), this, 686242Sgblack@eecs.umich.edu defaultId); 696242Sgblack@eecs.umich.edu cachedBlockSizeValid = false; 707408Sgblack@eecs.umich.edu return defaultPort; 716735Sgblack@eecs.umich.edu } else 726242Sgblack@eecs.umich.edu fatal("Default port already set\n"); 736242Sgblack@eecs.umich.edu } 746242Sgblack@eecs.umich.edu int id; 756723Sgblack@eecs.umich.edu if (if_name == "functional") { 766242Sgblack@eecs.umich.edu if (!funcPort) { 776242Sgblack@eecs.umich.edu id = maxId++; 786261Sgblack@eecs.umich.edu funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); 796403Sgblack@eecs.umich.edu funcPortId = id; 806403Sgblack@eecs.umich.edu interfaces[id] = funcPort; 816403Sgblack@eecs.umich.edu } 827325Sgblack@eecs.umich.edu return funcPort; 837325Sgblack@eecs.umich.edu } 847400SAli.Saidi@ARM.com 857350SAli.Saidi@ARM.com // if_name ignored? forced to be empty? 867259Sgblack@eecs.umich.edu id = maxId++; 877259Sgblack@eecs.umich.edu assert(maxId < std::numeric_limits<typeof(maxId)>::max()); 887259Sgblack@eecs.umich.edu BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 897259Sgblack@eecs.umich.edu interfaces[id] = bp; 907264Sgblack@eecs.umich.edu cachedBlockSizeValid = false; 917267Sgblack@eecs.umich.edu return bp; 927285Sgblack@eecs.umich.edu} 937265Sgblack@eecs.umich.edu 947266Sgblack@eecs.umich.eduvoid 957266Sgblack@eecs.umich.eduBus::deletePortRefs(Port *p) 967266Sgblack@eecs.umich.edu{ 977268Sgblack@eecs.umich.edu 987272Sgblack@eecs.umich.edu BusPort *bp = dynamic_cast<BusPort*>(p); 997272Sgblack@eecs.umich.edu if (bp == NULL) 1007271Sgblack@eecs.umich.edu panic("Couldn't convert Port* to BusPort*\n"); 1017273Sgblack@eecs.umich.edu // If this is our one functional port 1027287Sgblack@eecs.umich.edu if (funcPort == bp) 1037287Sgblack@eecs.umich.edu return; 1047274Sgblack@eecs.umich.edu interfaces.erase(bp->getId()); 1057275Sgblack@eecs.umich.edu clearBusCache(); 1067276Sgblack@eecs.umich.edu delete bp; 1077286Sgblack@eecs.umich.edu} 1087297Sgblack@eecs.umich.edu 1097297Sgblack@eecs.umich.edu/** Get the ranges of anyone other buses that we are connected to. */ 1107298Sgblack@eecs.umich.eduvoid 1117352Sgblack@eecs.umich.eduBus::init() 1127352Sgblack@eecs.umich.edu{ 1137354Sgblack@eecs.umich.edu m5::hash_map<short,BusPort*>::iterator intIter; 1147353Sgblack@eecs.umich.edu 1157355Sgblack@eecs.umich.edu for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 1167355Sgblack@eecs.umich.edu intIter->second->sendStatusChange(Port::RangeChange); 1177355Sgblack@eecs.umich.edu} 1187355Sgblack@eecs.umich.edu 1197355Sgblack@eecs.umich.eduBus::BusFreeEvent::BusFreeEvent(Bus *_bus) 1207355Sgblack@eecs.umich.edu : bus(_bus) 1217355Sgblack@eecs.umich.edu{} 1227355Sgblack@eecs.umich.edu 1237355Sgblack@eecs.umich.eduvoid 1247355Sgblack@eecs.umich.eduBus::BusFreeEvent::process() 1257355Sgblack@eecs.umich.edu{ 1267355Sgblack@eecs.umich.edu bus->recvRetry(-1); 1277355Sgblack@eecs.umich.edu} 1287355Sgblack@eecs.umich.edu 1297362Sgblack@eecs.umich.educonst char * 1307362Sgblack@eecs.umich.eduBus::BusFreeEvent::description() const 1317362Sgblack@eecs.umich.edu{ 1327362Sgblack@eecs.umich.edu return "bus became available"; 1337390Sgblack@eecs.umich.edu} 1347404SAli.Saidi@ARM.com 1357404SAli.Saidi@ARM.comTick 1367404SAli.Saidi@ARM.comBus::calcPacketTiming(PacketPtr pkt) 1377404SAli.Saidi@ARM.com{ 1387406SAli.Saidi@ARM.com // Bring tickNextIdle up to the present tick. 1397406SAli.Saidi@ARM.com // There is some potential ambiguity where a cycle starts, which 1407406SAli.Saidi@ARM.com // might make a difference when devices are acting right around a 1417436Sdam.sunwoo@arm.com // cycle boundary. Using a < allows things which happen exactly on 1427436Sdam.sunwoo@arm.com // a cycle boundary to take up only the following cycle. Anything 1437436Sdam.sunwoo@arm.com // that happens later will have to "wait" for the end of that 1447436Sdam.sunwoo@arm.com // cycle, and then start using the bus after that. 1457436Sdam.sunwoo@arm.com if (tickNextIdle < curTick) { 1467436Sdam.sunwoo@arm.com tickNextIdle = curTick; 1477436Sdam.sunwoo@arm.com if (tickNextIdle % clock != 0) 1487436Sdam.sunwoo@arm.com tickNextIdle = curTick - (curTick % clock) + clock; 1497436Sdam.sunwoo@arm.com } 1507583SAli.Saidi@arm.com 1517583SAli.Saidi@arm.com Tick headerTime = tickNextIdle + headerCycles * clock; 1527583SAli.Saidi@arm.com 1537583SAli.Saidi@arm.com // The packet will be sent. Figure out how long it occupies the bus, and 1547583SAli.Saidi@arm.com // how much of that time is for the first "word", aka bus width. 1557583SAli.Saidi@arm.com int numCycles = 0; 1567583SAli.Saidi@arm.com if (pkt->hasData()) { 1577583SAli.Saidi@arm.com // If a packet has data, it needs ceil(size/width) cycles to send it 1587583SAli.Saidi@arm.com int dataSize = pkt->getSize(); 1597583SAli.Saidi@arm.com numCycles += dataSize/width; 1607583SAli.Saidi@arm.com if (dataSize % width) 1617583SAli.Saidi@arm.com numCycles++; 1627583SAli.Saidi@arm.com } 1637583SAli.Saidi@arm.com 1647583SAli.Saidi@arm.com // The first word will be delivered after the current tick, the delivery 1657583SAli.Saidi@arm.com // of the address if any, and one bus cycle to deliver the data 1667259Sgblack@eecs.umich.edu pkt->firstWordTime = headerTime + clock; 1677406SAli.Saidi@ARM.com 1687259Sgblack@eecs.umich.edu pkt->finishTime = headerTime + numCycles * clock; 1697259Sgblack@eecs.umich.edu 1707259Sgblack@eecs.umich.edu return headerTime; 1717259Sgblack@eecs.umich.edu} 1727259Sgblack@eecs.umich.edu 1737259Sgblack@eecs.umich.eduvoid Bus::occupyBus(Tick until) 1747259Sgblack@eecs.umich.edu{ 1757259Sgblack@eecs.umich.edu if (until == 0) { 1767259Sgblack@eecs.umich.edu // shortcut for express snoop packets 1777259Sgblack@eecs.umich.edu return; 1787259Sgblack@eecs.umich.edu } 1797259Sgblack@eecs.umich.edu 1807259Sgblack@eecs.umich.edu tickNextIdle = until; 1817259Sgblack@eecs.umich.edu reschedule(busIdle, tickNextIdle, true); 1827259Sgblack@eecs.umich.edu 1837259Sgblack@eecs.umich.edu DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 1847259Sgblack@eecs.umich.edu curTick, tickNextIdle); 1857259Sgblack@eecs.umich.edu} 1867259Sgblack@eecs.umich.edu 1877351Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a Timing 1887351Sgblack@eecs.umich.edu * transaction.*/ 1897351Sgblack@eecs.umich.edubool 1907351Sgblack@eecs.umich.eduBus::recvTiming(PacketPtr pkt) 1917351Sgblack@eecs.umich.edu{ 1927351Sgblack@eecs.umich.edu short src = pkt->getSrc(); 1937259Sgblack@eecs.umich.edu 1947259Sgblack@eecs.umich.edu BusPort *src_port; 1957259Sgblack@eecs.umich.edu if (src == defaultId) 1967259Sgblack@eecs.umich.edu src_port = defaultPort; 1977259Sgblack@eecs.umich.edu else { 1987259Sgblack@eecs.umich.edu src_port = checkBusCache(src); 1997259Sgblack@eecs.umich.edu if (src_port == NULL) { 2006735Sgblack@eecs.umich.edu src_port = interfaces[src]; 2016261Sgblack@eecs.umich.edu updateBusCache(src, src_port); 2026261Sgblack@eecs.umich.edu } 2037259Sgblack@eecs.umich.edu } 2047259Sgblack@eecs.umich.edu 2057259Sgblack@eecs.umich.edu // If the bus is busy, or other devices are in line ahead of the current 2066261Sgblack@eecs.umich.edu // one, put this device on the retry list. 2077408Sgblack@eecs.umich.edu if (!pkt->isExpressSnoop() && 2087259Sgblack@eecs.umich.edu (tickNextIdle > curTick || 2097351Sgblack@eecs.umich.edu (retryList.size() && (!inRetry || src_port != retryList.front())))) 2107400SAli.Saidi@ARM.com { 2117285Sgblack@eecs.umich.edu addToRetryList(src_port); 2127267Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n", 2137287Sgblack@eecs.umich.edu src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 2147287Sgblack@eecs.umich.edu return false; 2157297Sgblack@eecs.umich.edu } 2167297Sgblack@eecs.umich.edu 2177355Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n", 2187355Sgblack@eecs.umich.edu src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 2197355Sgblack@eecs.umich.edu 2207355Sgblack@eecs.umich.edu Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt); 2217355Sgblack@eecs.umich.edu Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime; 2227390Sgblack@eecs.umich.edu 2237436Sdam.sunwoo@arm.com short dest = pkt->getDest(); 2247436Sdam.sunwoo@arm.com int dest_port_id; 2257436Sdam.sunwoo@arm.com Port *dest_port; 2267436Sdam.sunwoo@arm.com 2277583SAli.Saidi@arm.com if (dest == Packet::Broadcast) { 2287583SAli.Saidi@arm.com dest_port_id = findPort(pkt->getAddr()); 2297583SAli.Saidi@arm.com dest_port = (dest_port_id == defaultId) ? 2307583SAli.Saidi@arm.com defaultPort : interfaces[dest_port_id]; 2317583SAli.Saidi@arm.com SnoopIter s_end = snoopPorts.end(); 2327583SAli.Saidi@arm.com for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 2337406SAli.Saidi@ARM.com BusPort *p = *s_iter; 2347404SAli.Saidi@ARM.com if (p != dest_port && p != src_port) { 2357583SAli.Saidi@arm.com // cache is not allowed to refuse snoop 2367259Sgblack@eecs.umich.edu bool success M5_VAR_USED = p->sendTiming(pkt); 2377583SAli.Saidi@arm.com assert(success); 2387362Sgblack@eecs.umich.edu } 2397297Sgblack@eecs.umich.edu } 2407272Sgblack@eecs.umich.edu } else { 2417406SAli.Saidi@ARM.com assert(dest < maxId); 2427404SAli.Saidi@ARM.com assert(dest != src); // catch infinite loops 2437259Sgblack@eecs.umich.edu dest_port_id = dest; 2446242Sgblack@eecs.umich.edu if (dest_port_id == defaultId) 2456242Sgblack@eecs.umich.edu dest_port = defaultPort; 2466242Sgblack@eecs.umich.edu else { 2476242Sgblack@eecs.umich.edu dest_port = checkBusCache(dest); 2486242Sgblack@eecs.umich.edu if (dest_port == NULL) { 2496242Sgblack@eecs.umich.edu dest_port = interfaces[dest_port_id]; 2506242Sgblack@eecs.umich.edu // updateBusCache(dest_port_id, dest_port); 2516242Sgblack@eecs.umich.edu } 2526735Sgblack@eecs.umich.edu } 2536242Sgblack@eecs.umich.edu dest_port = (dest_port_id == defaultId) ? 2546242Sgblack@eecs.umich.edu defaultPort : interfaces[dest_port_id]; 2556735Sgblack@eecs.umich.edu } 2566242Sgblack@eecs.umich.edu 2576242Sgblack@eecs.umich.edu if (dest_port_id == src) { 2586242Sgblack@eecs.umich.edu // Must be forwarded snoop up from below... 2596242Sgblack@eecs.umich.edu assert(dest == Packet::Broadcast); 2606242Sgblack@eecs.umich.edu } else { 2616242Sgblack@eecs.umich.edu // send to actual target 2626242Sgblack@eecs.umich.edu if (!dest_port->sendTiming(pkt)) { 2636735Sgblack@eecs.umich.edu // Packet not successfully sent. Leave or put it on the retry list. 2647408Sgblack@eecs.umich.edu // illegal to block responses... can lead to deadlock 2657408Sgblack@eecs.umich.edu assert(!pkt->isResponse()); 2667408Sgblack@eecs.umich.edu // It's also illegal to force a transaction to retry after 2677408Sgblack@eecs.umich.edu // someone else has committed to respond. 2687408Sgblack@eecs.umich.edu assert(!pkt->memInhibitAsserted()); 2697408Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n", 2707408Sgblack@eecs.umich.edu src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 2717408Sgblack@eecs.umich.edu addToRetryList(src_port); 2726750Sgblack@eecs.umich.edu occupyBus(headerFinishTime); 2736750Sgblack@eecs.umich.edu return false; 2746750Sgblack@eecs.umich.edu } 2756750Sgblack@eecs.umich.edu // send OK, fall through... pkt may have been deleted by 2766735Sgblack@eecs.umich.edu // target at this point, so it should *not* be referenced 2777360Sgblack@eecs.umich.edu // again. We'll set it to NULL here just to be safe. 2786735Sgblack@eecs.umich.edu pkt = NULL; 2796735Sgblack@eecs.umich.edu } 2806735Sgblack@eecs.umich.edu 2816735Sgblack@eecs.umich.edu occupyBus(packetFinishTime); 2826735Sgblack@eecs.umich.edu 2836735Sgblack@eecs.umich.edu // Packet was successfully sent. 2847406SAli.Saidi@ARM.com // Also take care of retries 2856735Sgblack@eecs.umich.edu if (inRetry) { 2866735Sgblack@eecs.umich.edu DPRINTF(Bus, "Remove retry from list %d\n", src); 2877360Sgblack@eecs.umich.edu retryList.front()->onRetryList(false); 2886735Sgblack@eecs.umich.edu retryList.pop_front(); 2897360Sgblack@eecs.umich.edu inRetry = false; 2906735Sgblack@eecs.umich.edu } 2916735Sgblack@eecs.umich.edu return true; 2926735Sgblack@eecs.umich.edu} 2936735Sgblack@eecs.umich.edu 2946735Sgblack@eecs.umich.eduvoid 2956735Sgblack@eecs.umich.eduBus::recvRetry(int id) 2967406SAli.Saidi@ARM.com{ 2976735Sgblack@eecs.umich.edu // If there's anything waiting, and the bus isn't busy... 2986735Sgblack@eecs.umich.edu if (retryList.size() && curTick >= tickNextIdle) { 2996735Sgblack@eecs.umich.edu //retryingPort = retryList.front(); 3006735Sgblack@eecs.umich.edu inRetry = true; 3016735Sgblack@eecs.umich.edu DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 3026735Sgblack@eecs.umich.edu retryList.front()->sendRetry(); 3037320Sgblack@eecs.umich.edu // If inRetry is still true, sendTiming wasn't called 3047320Sgblack@eecs.umich.edu if (inRetry) 3057320Sgblack@eecs.umich.edu { 3067320Sgblack@eecs.umich.edu retryList.front()->onRetryList(false); 3077320Sgblack@eecs.umich.edu retryList.pop_front(); 3087320Sgblack@eecs.umich.edu inRetry = false; 3097320Sgblack@eecs.umich.edu 3107320Sgblack@eecs.umich.edu //Bring tickNextIdle up to the present 3117320Sgblack@eecs.umich.edu while (tickNextIdle < curTick) 3127320Sgblack@eecs.umich.edu tickNextIdle += clock; 3137320Sgblack@eecs.umich.edu 3147320Sgblack@eecs.umich.edu //Burn a cycle for the missed grant. 3157320Sgblack@eecs.umich.edu tickNextIdle += clock; 3167320Sgblack@eecs.umich.edu 3177320Sgblack@eecs.umich.edu reschedule(busIdle, tickNextIdle, true); 3187320Sgblack@eecs.umich.edu } 3197320Sgblack@eecs.umich.edu } 3207320Sgblack@eecs.umich.edu //If we weren't able to drain before, we might be able to now. 3217320Sgblack@eecs.umich.edu if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) { 3227362Sgblack@eecs.umich.edu drainEvent->process(); 3237362Sgblack@eecs.umich.edu // Clear the drain event once we're done with it. 3247362Sgblack@eecs.umich.edu drainEvent = NULL; 3257362Sgblack@eecs.umich.edu } 3267362Sgblack@eecs.umich.edu} 3277362Sgblack@eecs.umich.edu 3287362Sgblack@eecs.umich.eduint 3297362Sgblack@eecs.umich.eduBus::findPort(Addr addr) 3307376Sgblack@eecs.umich.edu{ 3317376Sgblack@eecs.umich.edu /* An interval tree would be a better way to do this. --ali. */ 3327376Sgblack@eecs.umich.edu int dest_id; 3337376Sgblack@eecs.umich.edu 3347376Sgblack@eecs.umich.edu dest_id = checkPortCache(addr); 3357376Sgblack@eecs.umich.edu if (dest_id != -1) 3367376Sgblack@eecs.umich.edu return dest_id; 3377376Sgblack@eecs.umich.edu 3387376Sgblack@eecs.umich.edu // Check normal port ranges 3397376Sgblack@eecs.umich.edu PortIter i = portMap.find(RangeSize(addr,1)); 3407376Sgblack@eecs.umich.edu if (i != portMap.end()) { 3417376Sgblack@eecs.umich.edu dest_id = i->second; 3427376Sgblack@eecs.umich.edu updatePortCache(dest_id, i->first.start, i->first.end); 3437376Sgblack@eecs.umich.edu return dest_id; 3447376Sgblack@eecs.umich.edu } 3457376Sgblack@eecs.umich.edu 3467376Sgblack@eecs.umich.edu // Check if this matches the default range 3477376Sgblack@eecs.umich.edu if (useDefaultRange) { 3487376Sgblack@eecs.umich.edu AddrRangeIter a_end = defaultRange.end(); 3497376Sgblack@eecs.umich.edu for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { 3507376Sgblack@eecs.umich.edu if (*i == addr) { 3517376Sgblack@eecs.umich.edu DPRINTF(Bus, " found addr %#llx on default\n", addr); 3527376Sgblack@eecs.umich.edu return defaultId; 3537376Sgblack@eecs.umich.edu } 3547376Sgblack@eecs.umich.edu } 3557376Sgblack@eecs.umich.edu 3567383Sgblack@eecs.umich.edu panic("Unable to find destination for addr %#llx\n", addr); 3577383Sgblack@eecs.umich.edu } 3587383Sgblack@eecs.umich.edu 3597383Sgblack@eecs.umich.edu DPRINTF(Bus, "Unable to find destination for addr %#llx, " 3607383Sgblack@eecs.umich.edu "will use default port\n", addr); 3617383Sgblack@eecs.umich.edu return defaultId; 3627383Sgblack@eecs.umich.edu} 3637383Sgblack@eecs.umich.edu 3647383Sgblack@eecs.umich.edu 3657383Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a Atomic 3667383Sgblack@eecs.umich.edu * transaction.*/ 3677383Sgblack@eecs.umich.eduTick 3687383Sgblack@eecs.umich.eduBus::recvAtomic(PacketPtr pkt) 3697383Sgblack@eecs.umich.edu{ 3707383Sgblack@eecs.umich.edu DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 3717383Sgblack@eecs.umich.edu pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 3727383Sgblack@eecs.umich.edu assert(pkt->getDest() == Packet::Broadcast); 3737383Sgblack@eecs.umich.edu assert(pkt->isRequest()); 3747383Sgblack@eecs.umich.edu 3757383Sgblack@eecs.umich.edu // Variables for recording original command and snoop response (if 3767383Sgblack@eecs.umich.edu // any)... if a snooper respondes, we will need to restore 3777383Sgblack@eecs.umich.edu // original command so that additional snoops can take place 3787404SAli.Saidi@ARM.com // properly 3797404SAli.Saidi@ARM.com MemCmd orig_cmd = pkt->cmd; 3807404SAli.Saidi@ARM.com MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 3817404SAli.Saidi@ARM.com Tick snoop_response_latency = 0; 3827404SAli.Saidi@ARM.com int orig_src = pkt->getSrc(); 3837404SAli.Saidi@ARM.com 3847404SAli.Saidi@ARM.com int target_port_id = findPort(pkt->getAddr()); 3857404SAli.Saidi@ARM.com BusPort *target_port; 3867404SAli.Saidi@ARM.com if (target_port_id == defaultId) 3877404SAli.Saidi@ARM.com target_port = defaultPort; 3887404SAli.Saidi@ARM.com else { 3897404SAli.Saidi@ARM.com target_port = checkBusCache(target_port_id); 3907404SAli.Saidi@ARM.com if (target_port == NULL) { 3917404SAli.Saidi@ARM.com target_port = interfaces[target_port_id]; 3927404SAli.Saidi@ARM.com updateBusCache(target_port_id, target_port); 3937404SAli.Saidi@ARM.com } 3947404SAli.Saidi@ARM.com } 3957404SAli.Saidi@ARM.com 3967404SAli.Saidi@ARM.com SnoopIter s_end = snoopPorts.end(); 3977404SAli.Saidi@ARM.com for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 3987404SAli.Saidi@ARM.com BusPort *p = *s_iter; 3997404SAli.Saidi@ARM.com // same port should not have both target addresses and snooping 4007404SAli.Saidi@ARM.com assert(p != target_port); 4017404SAli.Saidi@ARM.com if (p->getId() != pkt->getSrc()) { 4027404SAli.Saidi@ARM.com Tick latency = p->sendAtomic(pkt); 4037404SAli.Saidi@ARM.com if (pkt->isResponse()) { 4047404SAli.Saidi@ARM.com // response from snoop agent 4057404SAli.Saidi@ARM.com assert(pkt->cmd != orig_cmd); 4067404SAli.Saidi@ARM.com assert(pkt->memInhibitAsserted()); 4077404SAli.Saidi@ARM.com // should only happen once 4087404SAli.Saidi@ARM.com assert(snoop_response_cmd == MemCmd::InvalidCmd); 4097404SAli.Saidi@ARM.com // save response state 4107404SAli.Saidi@ARM.com snoop_response_cmd = pkt->cmd; 4117404SAli.Saidi@ARM.com snoop_response_latency = latency; 4127404SAli.Saidi@ARM.com // restore original packet state for remaining snoopers 4137404SAli.Saidi@ARM.com pkt->cmd = orig_cmd; 4147404SAli.Saidi@ARM.com pkt->setSrc(orig_src); 4157404SAli.Saidi@ARM.com pkt->setDest(Packet::Broadcast); 4167404SAli.Saidi@ARM.com } 4177404SAli.Saidi@ARM.com } 4187404SAli.Saidi@ARM.com } 4197404SAli.Saidi@ARM.com 4207404SAli.Saidi@ARM.com Tick response_latency = 0; 4216242Sgblack@eecs.umich.edu 4226242Sgblack@eecs.umich.edu // we can get requests sent up from the memory side of the bus for 4236242Sgblack@eecs.umich.edu // snooping... don't send them back down! 424 if (target_port_id != pkt->getSrc()) { 425 response_latency = target_port->sendAtomic(pkt); 426 } 427 428 // if we got a response from a snooper, restore it here 429 if (snoop_response_cmd != MemCmd::InvalidCmd) { 430 // no one else should have responded 431 assert(!pkt->isResponse()); 432 assert(pkt->cmd == orig_cmd); 433 pkt->cmd = snoop_response_cmd; 434 response_latency = snoop_response_latency; 435 } 436 437 // why do we have this packet field and the return value both??? 438 pkt->finishTime = curTick + response_latency; 439 return response_latency; 440} 441 442/** Function called by the port when the bus is receiving a Functional 443 * transaction.*/ 444void 445Bus::recvFunctional(PacketPtr pkt) 446{ 447 if (!pkt->isPrint()) { 448 // don't do DPRINTFs on PrintReq as it clutters up the output 449 DPRINTF(Bus, 450 "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 451 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), 452 pkt->cmdString()); 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 assert(pkt->isRequest()); // hasn't already been satisfied 463 464 SnoopIter s_end = snoopPorts.end(); 465 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 466 BusPort *p = *s_iter; 467 if (p != port && p->getId() != src_id) { 468 p->sendFunctional(pkt); 469 } 470 if (pkt->isResponse()) { 471 break; 472 } 473 pkt->setSrc(src_id); 474 } 475 476 // If the snooping hasn't found what we were looking for, keep going. 477 if (!pkt->isResponse() && port_id != pkt->getSrc()) { 478 port->sendFunctional(pkt); 479 } 480} 481 482/** Function called by the port when the bus is receiving a status change.*/ 483void 484Bus::recvStatusChange(Port::Status status, int id) 485{ 486 AddrRangeList ranges; 487 bool snoops; 488 AddrRangeIter iter; 489 490 if (inRecvStatusChange.count(id)) 491 return; 492 inRecvStatusChange.insert(id); 493 494 assert(status == Port::RangeChange && 495 "The other statuses need to be implemented."); 496 497 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 498 499 clearPortCache(); 500 if (id == defaultId) { 501 defaultRange.clear(); 502 // Only try to update these ranges if the user set a default responder. 503 if (useDefaultRange) { 504 defaultPort->getPeerAddressRanges(ranges, snoops); 505 assert(snoops == false); 506 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 507 defaultRange.push_back(*iter); 508 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 509 iter->start, iter->end); 510 } 511 } 512 } else { 513 514 assert((id < maxId && id >= 0) || id == defaultId); 515 BusPort *port = interfaces[id]; 516 517 // Clean out any previously existent ids 518 for (PortIter portIter = portMap.begin(); 519 portIter != portMap.end(); ) { 520 if (portIter->second == id) 521 portMap.erase(portIter++); 522 else 523 portIter++; 524 } 525 526 for (SnoopIter s_iter = snoopPorts.begin(); 527 s_iter != snoopPorts.end(); ) { 528 if ((*s_iter)->getId() == id) 529 s_iter = snoopPorts.erase(s_iter); 530 else 531 s_iter++; 532 } 533 534 port->getPeerAddressRanges(ranges, snoops); 535 536 if (snoops) { 537 DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id); 538 snoopPorts.push_back(port); 539 } 540 541 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 542 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 543 iter->start, iter->end, id); 544 if (portMap.insert(*iter, id) == portMap.end()) { 545 int conflict_id = portMap.find(*iter)->second; 546 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 547 name(), interfaces[id]->getPeer()->name(), 548 interfaces[conflict_id]->getPeer()->name()); 549 } 550 } 551 } 552 DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 553 554 // tell all our peers that our address range has changed. 555 // Don't tell the device that caused this change, it already knows 556 m5::hash_map<short,BusPort*>::iterator intIter; 557 558 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 559 if (intIter->first != id && intIter->first != funcPortId) 560 intIter->second->sendStatusChange(Port::RangeChange); 561 562 if (id != defaultId && defaultPort) 563 defaultPort->sendStatusChange(Port::RangeChange); 564 inRecvStatusChange.erase(id); 565} 566 567void 568Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) 569{ 570 resp.clear(); 571 snoop = false; 572 573 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 574 575 for (AddrRangeIter dflt_iter = defaultRange.begin(); 576 dflt_iter != defaultRange.end(); dflt_iter++) { 577 resp.push_back(*dflt_iter); 578 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 579 dflt_iter->end); 580 } 581 for (PortIter portIter = portMap.begin(); 582 portIter != portMap.end(); portIter++) { 583 bool subset = false; 584 for (AddrRangeIter dflt_iter = defaultRange.begin(); 585 dflt_iter != defaultRange.end(); dflt_iter++) { 586 if ((portIter->first.start < dflt_iter->start && 587 portIter->first.end >= dflt_iter->start) || 588 (portIter->first.start < dflt_iter->end && 589 portIter->first.end >= dflt_iter->end)) 590 fatal("Devices can not set ranges that itersect the default set\ 591 but are not a subset of the default set.\n"); 592 if (portIter->first.start >= dflt_iter->start && 593 portIter->first.end <= dflt_iter->end) { 594 subset = true; 595 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 596 portIter->first.start, portIter->first.end); 597 } 598 } 599 if (portIter->second != id && !subset) { 600 resp.push_back(portIter->first); 601 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 602 portIter->first.start, portIter->first.end); 603 } 604 } 605 606 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 607 s_iter++) { 608 if ((*s_iter)->getId() != id) { 609 snoop = true; 610 break; 611 } 612 } 613} 614 615unsigned 616Bus::findBlockSize(int id) 617{ 618 if (cachedBlockSizeValid) 619 return cachedBlockSize; 620 621 unsigned max_bs = 0; 622 623 PortIter p_end = portMap.end(); 624 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { 625 unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize(); 626 if (tmp_bs > max_bs) 627 max_bs = tmp_bs; 628 } 629 SnoopIter s_end = snoopPorts.end(); 630 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 631 unsigned tmp_bs = (*s_iter)->peerBlockSize(); 632 if (tmp_bs > max_bs) 633 max_bs = tmp_bs; 634 } 635 if (max_bs == 0) 636 max_bs = defaultBlockSize; 637 638 if (max_bs != 64) 639 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 640 cachedBlockSize = max_bs; 641 cachedBlockSizeValid = true; 642 return max_bs; 643} 644 645 646unsigned int 647Bus::drain(Event * de) 648{ 649 //We should check that we're not "doing" anything, and that noone is 650 //waiting. We might be idle but have someone waiting if the device we 651 //contacted for a retry didn't actually retry. 652 if (retryList.size() || (curTick < tickNextIdle && busIdle.scheduled())) { 653 drainEvent = de; 654 return 1; 655 } 656 return 0; 657} 658 659void 660Bus::startup() 661{ 662 if (tickNextIdle < curTick) 663 tickNextIdle = (curTick / clock) * clock + clock; 664} 665 666Bus * 667BusParams::create() 668{ 669 return new Bus(this); 670} 671