coherent_xbar.cc revision 5197
17405SAli.Saidi@ARM.com/* 27405SAli.Saidi@ARM.com * Copyright (c) 2006 The Regents of The University of Michigan 37405SAli.Saidi@ARM.com * All rights reserved. 47405SAli.Saidi@ARM.com * 57405SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 67405SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 77405SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright 87405SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 97405SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 107405SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 117405SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 127405SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its 137405SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 147405SAli.Saidi@ARM.com * this software without specific prior written permission. 157405SAli.Saidi@ARM.com * 167405SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177405SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187405SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197405SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207405SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217405SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227405SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237405SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247405SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257405SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267405SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277405SAli.Saidi@ARM.com * 287405SAli.Saidi@ARM.com * Authors: Ali Saidi 297405SAli.Saidi@ARM.com */ 307405SAli.Saidi@ARM.com 317405SAli.Saidi@ARM.com/** 327405SAli.Saidi@ARM.com * @file 337405SAli.Saidi@ARM.com * Definition of a bus object. 347405SAli.Saidi@ARM.com */ 357405SAli.Saidi@ARM.com 367405SAli.Saidi@ARM.com#include <algorithm> 377405SAli.Saidi@ARM.com#include <limits> 387405SAli.Saidi@ARM.com 397405SAli.Saidi@ARM.com#include "base/misc.hh" 407405SAli.Saidi@ARM.com#include "base/trace.hh" 417405SAli.Saidi@ARM.com#include "mem/bus.hh" 427405SAli.Saidi@ARM.com 437405SAli.Saidi@ARM.comPort * 447405SAli.Saidi@ARM.comBus::getPort(const std::string &if_name, int idx) 457405SAli.Saidi@ARM.com{ 467427Sgblack@eecs.umich.edu if (if_name == "default") { 477427Sgblack@eecs.umich.edu if (defaultPort == NULL) { 487427Sgblack@eecs.umich.edu defaultPort = new BusPort(csprintf("%s-default",name()), this, 497427Sgblack@eecs.umich.edu defaultId); 507427Sgblack@eecs.umich.edu cachedBlockSizeValid = false; 517427Sgblack@eecs.umich.edu return defaultPort; 527427Sgblack@eecs.umich.edu } else 537427Sgblack@eecs.umich.edu fatal("Default port already set\n"); 547427Sgblack@eecs.umich.edu } 557427Sgblack@eecs.umich.edu int id; 567427Sgblack@eecs.umich.edu if (if_name == "functional") { 577427Sgblack@eecs.umich.edu if (!funcPort) { 587427Sgblack@eecs.umich.edu id = maxId++; 597427Sgblack@eecs.umich.edu funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); 607427Sgblack@eecs.umich.edu funcPortId = id; 617427Sgblack@eecs.umich.edu interfaces[id] = funcPort; 627427Sgblack@eecs.umich.edu } 637427Sgblack@eecs.umich.edu return funcPort; 647427Sgblack@eecs.umich.edu } 657427Sgblack@eecs.umich.edu 667427Sgblack@eecs.umich.edu // if_name ignored? forced to be empty? 677427Sgblack@eecs.umich.edu id = maxId++; 687427Sgblack@eecs.umich.edu assert(maxId < std::numeric_limits<typeof(maxId)>::max()); 697427Sgblack@eecs.umich.edu BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 707427Sgblack@eecs.umich.edu interfaces[id] = bp; 717427Sgblack@eecs.umich.edu cachedBlockSizeValid = false; 727427Sgblack@eecs.umich.edu return bp; 737427Sgblack@eecs.umich.edu} 747427Sgblack@eecs.umich.edu 757427Sgblack@eecs.umich.eduvoid 767427Sgblack@eecs.umich.eduBus::deletePortRefs(Port *p) 777427Sgblack@eecs.umich.edu{ 787427Sgblack@eecs.umich.edu 797427Sgblack@eecs.umich.edu BusPort *bp = dynamic_cast<BusPort*>(p); 807427Sgblack@eecs.umich.edu if (bp == NULL) 817427Sgblack@eecs.umich.edu panic("Couldn't convert Port* to BusPort*\n"); 827427Sgblack@eecs.umich.edu // If this is our one functional port 837427Sgblack@eecs.umich.edu if (funcPort == bp) 847427Sgblack@eecs.umich.edu return; 857427Sgblack@eecs.umich.edu interfaces.erase(bp->getId()); 867427Sgblack@eecs.umich.edu clearBusCache(); 877427Sgblack@eecs.umich.edu delete bp; 887427Sgblack@eecs.umich.edu} 897427Sgblack@eecs.umich.edu 907427Sgblack@eecs.umich.edu/** Get the ranges of anyone other buses that we are connected to. */ 917427Sgblack@eecs.umich.eduvoid 927427Sgblack@eecs.umich.eduBus::init() 937427Sgblack@eecs.umich.edu{ 947427Sgblack@eecs.umich.edu m5::hash_map<short,BusPort*>::iterator intIter; 957427Sgblack@eecs.umich.edu 967427Sgblack@eecs.umich.edu for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 977427Sgblack@eecs.umich.edu intIter->second->sendStatusChange(Port::RangeChange); 987427Sgblack@eecs.umich.edu} 997427Sgblack@eecs.umich.edu 1007427Sgblack@eecs.umich.eduBus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) 1017427Sgblack@eecs.umich.edu{} 1027427Sgblack@eecs.umich.edu 1037427Sgblack@eecs.umich.eduvoid Bus::BusFreeEvent::process() 1047427Sgblack@eecs.umich.edu{ 1057427Sgblack@eecs.umich.edu bus->recvRetry(-1); 1067427Sgblack@eecs.umich.edu} 1077427Sgblack@eecs.umich.edu 1087427Sgblack@eecs.umich.educonst char * Bus::BusFreeEvent::description() 1097427Sgblack@eecs.umich.edu{ 1107427Sgblack@eecs.umich.edu return "bus became available"; 1117427Sgblack@eecs.umich.edu} 1127427Sgblack@eecs.umich.edu 1137427Sgblack@eecs.umich.eduvoid Bus::occupyBus(PacketPtr pkt) 1147427Sgblack@eecs.umich.edu{ 1157427Sgblack@eecs.umich.edu //Bring tickNextIdle up to the present tick 1167427Sgblack@eecs.umich.edu //There is some potential ambiguity where a cycle starts, which might make 1177427Sgblack@eecs.umich.edu //a difference when devices are acting right around a cycle boundary. Using 1187427Sgblack@eecs.umich.edu //a < allows things which happen exactly on a cycle boundary to take up 1197427Sgblack@eecs.umich.edu //only the following cycle. Anything that happens later will have to "wait" 1207436Sdam.sunwoo@arm.com //for the end of that cycle, and then start using the bus after that. 1217436Sdam.sunwoo@arm.com if (tickNextIdle < curTick) { 1227436Sdam.sunwoo@arm.com tickNextIdle = curTick; 1237436Sdam.sunwoo@arm.com if (tickNextIdle % clock != 0) 1247436Sdam.sunwoo@arm.com tickNextIdle = curTick - (curTick % clock) + clock; 1257436Sdam.sunwoo@arm.com } 1267436Sdam.sunwoo@arm.com 1277436Sdam.sunwoo@arm.com // The packet will be sent. Figure out how long it occupies the bus, and 1287436Sdam.sunwoo@arm.com // how much of that time is for the first "word", aka bus width. 1297436Sdam.sunwoo@arm.com int numCycles = 0; 1307436Sdam.sunwoo@arm.com // Requests need one cycle to send an address 1317436Sdam.sunwoo@arm.com if (pkt->isRequest()) 1327436Sdam.sunwoo@arm.com numCycles++; 1337436Sdam.sunwoo@arm.com else if (pkt->isResponse() || pkt->hasData()) { 1347436Sdam.sunwoo@arm.com // If a packet has data, it needs ceil(size/width) cycles to send it 1357436Sdam.sunwoo@arm.com // We're using the "adding instead of dividing" trick again here 1367436Sdam.sunwoo@arm.com if (pkt->hasData()) { 1377436Sdam.sunwoo@arm.com int dataSize = pkt->getSize(); 1387436Sdam.sunwoo@arm.com numCycles += dataSize/width; 1397436Sdam.sunwoo@arm.com if (dataSize % width) 1407436Sdam.sunwoo@arm.com numCycles++; 1417436Sdam.sunwoo@arm.com } else { 1427436Sdam.sunwoo@arm.com // If the packet didn't have data, it must have been a response. 1437436Sdam.sunwoo@arm.com // Those use the bus for one cycle to send their data. 1447436Sdam.sunwoo@arm.com numCycles++; 1457436Sdam.sunwoo@arm.com } 1467436Sdam.sunwoo@arm.com } 1477436Sdam.sunwoo@arm.com 1487436Sdam.sunwoo@arm.com // The first word will be delivered after the current tick, the delivery 1497436Sdam.sunwoo@arm.com // of the address if any, and one bus cycle to deliver the data 1507436Sdam.sunwoo@arm.com pkt->firstWordTime = tickNextIdle + (pkt->isRequest() ? clock : 0) + clock; 1517436Sdam.sunwoo@arm.com 1527427Sgblack@eecs.umich.edu //Advance it numCycles bus cycles. 1537427Sgblack@eecs.umich.edu //XXX Should this use the repeated addition trick as well? 1547427Sgblack@eecs.umich.edu tickNextIdle += (numCycles * clock); 1557405SAli.Saidi@ARM.com if (!busIdle.scheduled()) { 1567405SAli.Saidi@ARM.com busIdle.schedule(tickNextIdle); 1577405SAli.Saidi@ARM.com } else { 1587405SAli.Saidi@ARM.com busIdle.reschedule(tickNextIdle); 1597405SAli.Saidi@ARM.com } 1607405SAli.Saidi@ARM.com DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 1617405SAli.Saidi@ARM.com curTick, tickNextIdle); 1627405SAli.Saidi@ARM.com 1637405SAli.Saidi@ARM.com // The bus will become idle once the current packet is delivered. 1647405SAli.Saidi@ARM.com pkt->finishTime = tickNextIdle; 1657405SAli.Saidi@ARM.com} 1667405SAli.Saidi@ARM.com 1677405SAli.Saidi@ARM.com/** Function called by the port when the bus is receiving a Timing 1687405SAli.Saidi@ARM.com * transaction.*/ 1697405SAli.Saidi@ARM.combool 1707405SAli.Saidi@ARM.comBus::recvTiming(PacketPtr pkt) 1717405SAli.Saidi@ARM.com{ 1727405SAli.Saidi@ARM.com short src = pkt->getSrc(); 1737405SAli.Saidi@ARM.com 1747405SAli.Saidi@ARM.com BusPort *src_port; 1757405SAli.Saidi@ARM.com if (src == defaultId) 1767405SAli.Saidi@ARM.com src_port = defaultPort; 1777405SAli.Saidi@ARM.com else { 1787405SAli.Saidi@ARM.com src_port = checkBusCache(src); 1797405SAli.Saidi@ARM.com if (src_port == NULL) { 1807405SAli.Saidi@ARM.com src_port = interfaces[src]; 1817405SAli.Saidi@ARM.com updateBusCache(src, src_port); 1827405SAli.Saidi@ARM.com } 1837405SAli.Saidi@ARM.com } 1847405SAli.Saidi@ARM.com 1857405SAli.Saidi@ARM.com // If the bus is busy, or other devices are in line ahead of the current 1867405SAli.Saidi@ARM.com // one, put this device on the retry list. 1877405SAli.Saidi@ARM.com if (!pkt->isExpressSnoop() && 1887405SAli.Saidi@ARM.com (tickNextIdle > curTick || 1897405SAli.Saidi@ARM.com (retryList.size() && (!inRetry || src_port != retryList.front())))) 1907405SAli.Saidi@ARM.com { 1917405SAli.Saidi@ARM.com addToRetryList(src_port); 1927405SAli.Saidi@ARM.com DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n", 1937405SAli.Saidi@ARM.com src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 1947405SAli.Saidi@ARM.com return false; 1957405SAli.Saidi@ARM.com } 1967405SAli.Saidi@ARM.com 1977405SAli.Saidi@ARM.com DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n", 1987405SAli.Saidi@ARM.com src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 1997405SAli.Saidi@ARM.com 2007405SAli.Saidi@ARM.com if (!pkt->isExpressSnoop()) { 2017405SAli.Saidi@ARM.com occupyBus(pkt); 2027405SAli.Saidi@ARM.com } 2037405SAli.Saidi@ARM.com 2047405SAli.Saidi@ARM.com short dest = pkt->getDest(); 2057405SAli.Saidi@ARM.com int dest_port_id; 2067405SAli.Saidi@ARM.com Port *dest_port; 2077405SAli.Saidi@ARM.com 2087405SAli.Saidi@ARM.com if (dest == Packet::Broadcast) { 2097405SAli.Saidi@ARM.com dest_port_id = findPort(pkt->getAddr()); 2107405SAli.Saidi@ARM.com dest_port = (dest_port_id == defaultId) ? 2117405SAli.Saidi@ARM.com defaultPort : interfaces[dest_port_id]; 2127405SAli.Saidi@ARM.com SnoopIter s_end = snoopPorts.end(); 2137405SAli.Saidi@ARM.com for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 2147405SAli.Saidi@ARM.com BusPort *p = *s_iter; 2157583SAli.Saidi@arm.com if (p != dest_port && p != src_port) { 2167583SAli.Saidi@arm.com // cache is not allowed to refuse snoop 2177583SAli.Saidi@arm.com bool success M5_VAR_USED = p->sendTiming(pkt); 2187583SAli.Saidi@arm.com assert(success); 2197583SAli.Saidi@arm.com } 2207583SAli.Saidi@arm.com } 2217583SAli.Saidi@arm.com } else { 2227583SAli.Saidi@arm.com assert(dest >= 0 && dest < maxId); 2237583SAli.Saidi@arm.com assert(dest != src); // catch infinite loops 2247583SAli.Saidi@arm.com dest_port_id = dest; 2257583SAli.Saidi@arm.com if (dest_port_id == defaultId) 2267583SAli.Saidi@arm.com dest_port = defaultPort; 2277583SAli.Saidi@arm.com else { 2287583SAli.Saidi@arm.com dest_port = checkBusCache(dest); 2297405SAli.Saidi@ARM.com if (dest_port == NULL) { 2307405SAli.Saidi@ARM.com dest_port = interfaces[dest_port_id]; 2317405SAli.Saidi@ARM.com // updateBusCache(dest_port_id, dest_port); 2327405SAli.Saidi@ARM.com } 2337405SAli.Saidi@ARM.com } 2347405SAli.Saidi@ARM.com dest_port = (dest_port_id == defaultId) ? 2357405SAli.Saidi@ARM.com defaultPort : interfaces[dest_port_id]; 2367405SAli.Saidi@ARM.com } 2377405SAli.Saidi@ARM.com 2387405SAli.Saidi@ARM.com if (dest_port_id == src) { 2397405SAli.Saidi@ARM.com // Must be forwarded snoop up from below... 2407405SAli.Saidi@ARM.com assert(dest == Packet::Broadcast); 2417405SAli.Saidi@ARM.com assert(src != defaultId); // catch infinite loops 2427405SAli.Saidi@ARM.com } else { 2437405SAli.Saidi@ARM.com // send to actual target 2447405SAli.Saidi@ARM.com if (!dest_port->sendTiming(pkt)) { 2457405SAli.Saidi@ARM.com // Packet not successfully sent. Leave or put it on the retry list. 2467405SAli.Saidi@ARM.com // illegal to block responses... can lead to deadlock 2477405SAli.Saidi@ARM.com assert(!pkt->isResponse()); 2487405SAli.Saidi@ARM.com DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n", 2497405SAli.Saidi@ARM.com src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 2507405SAli.Saidi@ARM.com addToRetryList(src_port); 2517405SAli.Saidi@ARM.com return false; 2527405SAli.Saidi@ARM.com } 2537405SAli.Saidi@ARM.com // send OK, fall through 2547405SAli.Saidi@ARM.com } 2557405SAli.Saidi@ARM.com 2567405SAli.Saidi@ARM.com // Packet was successfully sent. 2577405SAli.Saidi@ARM.com // Also take care of retries 2587405SAli.Saidi@ARM.com if (inRetry) { 2597405SAli.Saidi@ARM.com DPRINTF(Bus, "Remove retry from list %d\n", src); 2607405SAli.Saidi@ARM.com retryList.front()->onRetryList(false); 2617405SAli.Saidi@ARM.com retryList.pop_front(); 2627405SAli.Saidi@ARM.com inRetry = false; 2637405SAli.Saidi@ARM.com } 2647405SAli.Saidi@ARM.com return true; 2657405SAli.Saidi@ARM.com} 2667405SAli.Saidi@ARM.com 2677405SAli.Saidi@ARM.comvoid 2687405SAli.Saidi@ARM.comBus::recvRetry(int id) 2697405SAli.Saidi@ARM.com{ 2707405SAli.Saidi@ARM.com // If there's anything waiting, and the bus isn't busy... 2717405SAli.Saidi@ARM.com if (retryList.size() && curTick >= tickNextIdle) { 2727405SAli.Saidi@ARM.com //retryingPort = retryList.front(); 2737405SAli.Saidi@ARM.com inRetry = true; 2747405SAli.Saidi@ARM.com DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 2757405SAli.Saidi@ARM.com retryList.front()->sendRetry(); 2767405SAli.Saidi@ARM.com // If inRetry is still true, sendTiming wasn't called 2777405SAli.Saidi@ARM.com if (inRetry) 2787405SAli.Saidi@ARM.com { 2797405SAli.Saidi@ARM.com retryList.front()->onRetryList(false); 2807405SAli.Saidi@ARM.com retryList.pop_front(); 2817405SAli.Saidi@ARM.com inRetry = false; 2827405SAli.Saidi@ARM.com 2837405SAli.Saidi@ARM.com //Bring tickNextIdle up to the present 2847405SAli.Saidi@ARM.com while (tickNextIdle < curTick) 2857408Sgblack@eecs.umich.edu tickNextIdle += clock; 2867405SAli.Saidi@ARM.com 2877405SAli.Saidi@ARM.com //Burn a cycle for the missed grant. 2887405SAli.Saidi@ARM.com tickNextIdle += clock; 2897408Sgblack@eecs.umich.edu 2907408Sgblack@eecs.umich.edu busIdle.reschedule(tickNextIdle, true); 2917408Sgblack@eecs.umich.edu } 2927408Sgblack@eecs.umich.edu } 2937408Sgblack@eecs.umich.edu //If we weren't able to drain before, we might be able to now. 2947408Sgblack@eecs.umich.edu if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) { 2957408Sgblack@eecs.umich.edu drainEvent->process(); 2967408Sgblack@eecs.umich.edu // Clear the drain event once we're done with it. 2977408Sgblack@eecs.umich.edu drainEvent = NULL; 2987408Sgblack@eecs.umich.edu } 2997408Sgblack@eecs.umich.edu} 3007408Sgblack@eecs.umich.edu 3017405SAli.Saidi@ARM.comint 3027408Sgblack@eecs.umich.eduBus::findPort(Addr addr) 3037408Sgblack@eecs.umich.edu{ 3047408Sgblack@eecs.umich.edu /* An interval tree would be a better way to do this. --ali. */ 3057408Sgblack@eecs.umich.edu int dest_id = -1; 3067408Sgblack@eecs.umich.edu 3077408Sgblack@eecs.umich.edu dest_id = checkPortCache(addr); 3087408Sgblack@eecs.umich.edu if (dest_id == -1) { 3097408Sgblack@eecs.umich.edu PortIter i = portMap.find(RangeSize(addr,1)); 3107408Sgblack@eecs.umich.edu if (i != portMap.end()) 3117408Sgblack@eecs.umich.edu dest_id = i->second; 3127408Sgblack@eecs.umich.edu updatePortCache(dest_id, i->first.start, i->first.end); 3137408Sgblack@eecs.umich.edu } 3147408Sgblack@eecs.umich.edu 3157408Sgblack@eecs.umich.edu // Check if this matches the default range 3167408Sgblack@eecs.umich.edu if (dest_id == -1) { 3177408Sgblack@eecs.umich.edu AddrRangeIter a_end = defaultRange.end(); 3187408Sgblack@eecs.umich.edu for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { 3197408Sgblack@eecs.umich.edu if (*i == addr) { 3207408Sgblack@eecs.umich.edu DPRINTF(Bus, " found addr %#llx on default\n", addr); 3217408Sgblack@eecs.umich.edu return defaultId; 3227408Sgblack@eecs.umich.edu } 3237408Sgblack@eecs.umich.edu } 3247408Sgblack@eecs.umich.edu 3257408Sgblack@eecs.umich.edu if (responderSet) { 3267408Sgblack@eecs.umich.edu panic("Unable to find destination for addr (user set default " 3277408Sgblack@eecs.umich.edu "responder): %#llx", addr); 3287408Sgblack@eecs.umich.edu } else { 3297408Sgblack@eecs.umich.edu DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use " 3307408Sgblack@eecs.umich.edu "default port", addr); 3317408Sgblack@eecs.umich.edu 3327408Sgblack@eecs.umich.edu return defaultId; 3337408Sgblack@eecs.umich.edu } 3347408Sgblack@eecs.umich.edu } 3357408Sgblack@eecs.umich.edu 3367408Sgblack@eecs.umich.edu return dest_id; 3377408Sgblack@eecs.umich.edu} 3387408Sgblack@eecs.umich.edu 3397408Sgblack@eecs.umich.edu 3407408Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a Atomic 3417408Sgblack@eecs.umich.edu * transaction.*/ 3427408Sgblack@eecs.umich.eduTick 3437408Sgblack@eecs.umich.eduBus::recvAtomic(PacketPtr pkt) 3447408Sgblack@eecs.umich.edu{ 3457408Sgblack@eecs.umich.edu DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 3467408Sgblack@eecs.umich.edu pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 3477408Sgblack@eecs.umich.edu assert(pkt->getDest() == Packet::Broadcast); 3487408Sgblack@eecs.umich.edu assert(pkt->isRequest()); 3497408Sgblack@eecs.umich.edu 3507408Sgblack@eecs.umich.edu // Variables for recording original command and snoop response (if 3517408Sgblack@eecs.umich.edu // any)... if a snooper respondes, we will need to restore 3527408Sgblack@eecs.umich.edu // original command so that additional snoops can take place 3537408Sgblack@eecs.umich.edu // properly 3547408Sgblack@eecs.umich.edu MemCmd orig_cmd = pkt->cmd; 3557408Sgblack@eecs.umich.edu MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 3567408Sgblack@eecs.umich.edu Tick snoop_response_latency = 0; 3577408Sgblack@eecs.umich.edu int orig_src = pkt->getSrc(); 3587408Sgblack@eecs.umich.edu 3597408Sgblack@eecs.umich.edu int target_port_id = findPort(pkt->getAddr()); 3607408Sgblack@eecs.umich.edu BusPort *target_port; 3617408Sgblack@eecs.umich.edu if (target_port_id == defaultId) 3627408Sgblack@eecs.umich.edu target_port = defaultPort; 3637408Sgblack@eecs.umich.edu else { 3647408Sgblack@eecs.umich.edu target_port = checkBusCache(target_port_id); 3657408Sgblack@eecs.umich.edu if (target_port == NULL) { 3667408Sgblack@eecs.umich.edu target_port = interfaces[target_port_id]; 3677408Sgblack@eecs.umich.edu updateBusCache(target_port_id, target_port); 3687408Sgblack@eecs.umich.edu } 3697408Sgblack@eecs.umich.edu } 3707408Sgblack@eecs.umich.edu 3717408Sgblack@eecs.umich.edu SnoopIter s_end = snoopPorts.end(); 3727408Sgblack@eecs.umich.edu for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 3737408Sgblack@eecs.umich.edu BusPort *p = *s_iter; 3747408Sgblack@eecs.umich.edu // same port should not have both target addresses and snooping 3757408Sgblack@eecs.umich.edu assert(p != target_port); 3767408Sgblack@eecs.umich.edu if (p->getId() != pkt->getSrc()) { 3777408Sgblack@eecs.umich.edu Tick latency = p->sendAtomic(pkt); 3787408Sgblack@eecs.umich.edu if (pkt->isResponse()) { 3797408Sgblack@eecs.umich.edu // response from snoop agent 3807408Sgblack@eecs.umich.edu assert(pkt->cmd != orig_cmd); 3817408Sgblack@eecs.umich.edu assert(pkt->memInhibitAsserted()); 3827408Sgblack@eecs.umich.edu // should only happen once 3837408Sgblack@eecs.umich.edu assert(snoop_response_cmd == MemCmd::InvalidCmd); 3847408Sgblack@eecs.umich.edu // save response state 3857408Sgblack@eecs.umich.edu snoop_response_cmd = pkt->cmd; 3867408Sgblack@eecs.umich.edu snoop_response_latency = latency; 3877408Sgblack@eecs.umich.edu // restore original packet state for remaining snoopers 3887408Sgblack@eecs.umich.edu pkt->cmd = orig_cmd; 3897408Sgblack@eecs.umich.edu pkt->setSrc(orig_src); 3907408Sgblack@eecs.umich.edu pkt->setDest(Packet::Broadcast); 3917408Sgblack@eecs.umich.edu } 3927408Sgblack@eecs.umich.edu } 3937408Sgblack@eecs.umich.edu } 3947408Sgblack@eecs.umich.edu 3957408Sgblack@eecs.umich.edu Tick response_latency = 0; 3967408Sgblack@eecs.umich.edu 3977408Sgblack@eecs.umich.edu // we can get requests sent up from the memory side of the bus for 3987408Sgblack@eecs.umich.edu // snooping... don't send them back down! 3997408Sgblack@eecs.umich.edu if (target_port_id != pkt->getSrc()) { 4007408Sgblack@eecs.umich.edu response_latency = target_port->sendAtomic(pkt); 4017408Sgblack@eecs.umich.edu } 4027408Sgblack@eecs.umich.edu 4037408Sgblack@eecs.umich.edu // if we got a response from a snooper, restore it here 4047408Sgblack@eecs.umich.edu if (snoop_response_cmd != MemCmd::InvalidCmd) { 4057408Sgblack@eecs.umich.edu // no one else should have responded 4067408Sgblack@eecs.umich.edu assert(!pkt->isResponse()); 4077408Sgblack@eecs.umich.edu assert(pkt->cmd == orig_cmd); 4087408Sgblack@eecs.umich.edu pkt->cmd = snoop_response_cmd; 4097408Sgblack@eecs.umich.edu response_latency = snoop_response_latency; 4107405SAli.Saidi@ARM.com } 4117583SAli.Saidi@arm.com 4127583SAli.Saidi@arm.com // why do we have this packet field and the return value both??? 4137583SAli.Saidi@arm.com pkt->finishTime = curTick + response_latency; 4147583SAli.Saidi@arm.com return response_latency; 4157583SAli.Saidi@arm.com} 4167583SAli.Saidi@arm.com 4177583SAli.Saidi@arm.com/** Function called by the port when the bus is receiving a Functional 4187583SAli.Saidi@arm.com * transaction.*/ 4197583SAli.Saidi@arm.comvoid 4207436Sdam.sunwoo@arm.comBus::recvFunctional(PacketPtr pkt) 4217436Sdam.sunwoo@arm.com{ 4227436Sdam.sunwoo@arm.com DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 4237436Sdam.sunwoo@arm.com pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 4247436Sdam.sunwoo@arm.com assert(pkt->getDest() == Packet::Broadcast); 4257436Sdam.sunwoo@arm.com 4267436Sdam.sunwoo@arm.com int port_id = findPort(pkt->getAddr()); 4277436Sdam.sunwoo@arm.com Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id]; 4287436Sdam.sunwoo@arm.com // The packet may be changed by another bus on snoops, restore the 4297436Sdam.sunwoo@arm.com // id after each 4307436Sdam.sunwoo@arm.com int src_id = pkt->getSrc(); 4317436Sdam.sunwoo@arm.com 4327436Sdam.sunwoo@arm.com assert(pkt->isRequest()); // hasn't already been satisfied 4337436Sdam.sunwoo@arm.com 4347436Sdam.sunwoo@arm.com SnoopIter s_end = snoopPorts.end(); 4357436Sdam.sunwoo@arm.com for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 4367436Sdam.sunwoo@arm.com BusPort *p = *s_iter; 4377436Sdam.sunwoo@arm.com if (p != port && p->getId() != src_id) { 4387436Sdam.sunwoo@arm.com p->sendFunctional(pkt); 4397436Sdam.sunwoo@arm.com } 4407436Sdam.sunwoo@arm.com if (pkt->isResponse()) { 4417436Sdam.sunwoo@arm.com break; 4427436Sdam.sunwoo@arm.com } 4437436Sdam.sunwoo@arm.com pkt->setSrc(src_id); 4447436Sdam.sunwoo@arm.com } 4457436Sdam.sunwoo@arm.com 4467436Sdam.sunwoo@arm.com // If the snooping hasn't found what we were looking for, keep going. 4477436Sdam.sunwoo@arm.com if (!pkt->isResponse() && port_id != pkt->getSrc()) { 4487436Sdam.sunwoo@arm.com port->sendFunctional(pkt); 4497436Sdam.sunwoo@arm.com } 4507442Ssaidi@eecs.umich.edu} 4517436Sdam.sunwoo@arm.com 4527436Sdam.sunwoo@arm.com/** Function called by the port when the bus is receiving a status change.*/ 4537436Sdam.sunwoo@arm.comvoid 4547436Sdam.sunwoo@arm.comBus::recvStatusChange(Port::Status status, int id) 4557436Sdam.sunwoo@arm.com{ 4567436Sdam.sunwoo@arm.com AddrRangeList ranges; 4577436Sdam.sunwoo@arm.com bool snoops; 4587436Sdam.sunwoo@arm.com AddrRangeIter iter; 4597436Sdam.sunwoo@arm.com 4607436Sdam.sunwoo@arm.com if (inRecvStatusChange.count(id)) 4617436Sdam.sunwoo@arm.com return; 4627436Sdam.sunwoo@arm.com inRecvStatusChange.insert(id); 4637436Sdam.sunwoo@arm.com 4647436Sdam.sunwoo@arm.com assert(status == Port::RangeChange && 4657436Sdam.sunwoo@arm.com "The other statuses need to be implemented."); 4667436Sdam.sunwoo@arm.com 4677436Sdam.sunwoo@arm.com DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 4687436Sdam.sunwoo@arm.com 4697436Sdam.sunwoo@arm.com clearPortCache(); 4707436Sdam.sunwoo@arm.com if (id == defaultId) { 4717436Sdam.sunwoo@arm.com defaultRange.clear(); 4727436Sdam.sunwoo@arm.com // Only try to update these ranges if the user set a default responder. 4737436Sdam.sunwoo@arm.com if (responderSet) { 4747405SAli.Saidi@ARM.com defaultPort->getPeerAddressRanges(ranges, snoops); 4757405SAli.Saidi@ARM.com assert(snoops == false); 4767405SAli.Saidi@ARM.com for(iter = ranges.begin(); iter != ranges.end(); iter++) { 4777405SAli.Saidi@ARM.com defaultRange.push_back(*iter); 4787405SAli.Saidi@ARM.com DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 4797405SAli.Saidi@ARM.com iter->start, iter->end); 480 } 481 } 482 } else { 483 484 assert((id < maxId && id >= 0) || id == defaultId); 485 BusPort *port = interfaces[id]; 486 487 // Clean out any previously existent ids 488 for (PortIter portIter = portMap.begin(); 489 portIter != portMap.end(); ) { 490 if (portIter->second == id) 491 portMap.erase(portIter++); 492 else 493 portIter++; 494 } 495 496 for (SnoopIter s_iter = snoopPorts.begin(); 497 s_iter != snoopPorts.end(); ) { 498 if ((*s_iter)->getId() == id) 499 s_iter = snoopPorts.erase(s_iter); 500 else 501 s_iter++; 502 } 503 504 port->getPeerAddressRanges(ranges, snoops); 505 506 if (snoops) { 507 DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id); 508 snoopPorts.push_back(port); 509 } 510 511 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 512 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 513 iter->start, iter->end, id); 514 if (portMap.insert(*iter, id) == portMap.end()) 515 panic("Two devices with same range\n"); 516 517 } 518 } 519 DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 520 521 // tell all our peers that our address range has changed. 522 // Don't tell the device that caused this change, it already knows 523 m5::hash_map<short,BusPort*>::iterator intIter; 524 525 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 526 if (intIter->first != id && intIter->first != funcPortId) 527 intIter->second->sendStatusChange(Port::RangeChange); 528 529 if (id != defaultId && defaultPort) 530 defaultPort->sendStatusChange(Port::RangeChange); 531 inRecvStatusChange.erase(id); 532} 533 534void 535Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) 536{ 537 resp.clear(); 538 snoop = false; 539 540 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 541 542 for (AddrRangeIter dflt_iter = defaultRange.begin(); 543 dflt_iter != defaultRange.end(); dflt_iter++) { 544 resp.push_back(*dflt_iter); 545 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 546 dflt_iter->end); 547 } 548 for (PortIter portIter = portMap.begin(); 549 portIter != portMap.end(); portIter++) { 550 bool subset = false; 551 for (AddrRangeIter dflt_iter = defaultRange.begin(); 552 dflt_iter != defaultRange.end(); dflt_iter++) { 553 if ((portIter->first.start < dflt_iter->start && 554 portIter->first.end >= dflt_iter->start) || 555 (portIter->first.start < dflt_iter->end && 556 portIter->first.end >= dflt_iter->end)) 557 fatal("Devices can not set ranges that itersect the default set\ 558 but are not a subset of the default set.\n"); 559 if (portIter->first.start >= dflt_iter->start && 560 portIter->first.end <= dflt_iter->end) { 561 subset = true; 562 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 563 portIter->first.start, portIter->first.end); 564 } 565 } 566 if (portIter->second != id && !subset) { 567 resp.push_back(portIter->first); 568 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 569 portIter->first.start, portIter->first.end); 570 } 571 } 572 573 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 574 s_iter++) { 575 if ((*s_iter)->getId() != id) { 576 snoop = true; 577 break; 578 } 579 } 580} 581 582int 583Bus::findBlockSize(int id) 584{ 585 if (cachedBlockSizeValid) 586 return cachedBlockSize; 587 588 int max_bs = -1; 589 590 PortIter p_end = portMap.end(); 591 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { 592 int tmp_bs = interfaces[p_iter->second]->peerBlockSize(); 593 if (tmp_bs > max_bs) 594 max_bs = tmp_bs; 595 } 596 SnoopIter s_end = snoopPorts.end(); 597 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 598 int tmp_bs = (*s_iter)->peerBlockSize(); 599 if (tmp_bs > max_bs) 600 max_bs = tmp_bs; 601 } 602 if (max_bs <= 0) 603 max_bs = defaultBlockSize; 604 605 if (max_bs != 64) 606 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 607 cachedBlockSize = max_bs; 608 cachedBlockSizeValid = true; 609 return max_bs; 610} 611 612 613unsigned int 614Bus::drain(Event * de) 615{ 616 //We should check that we're not "doing" anything, and that noone is 617 //waiting. We might be idle but have someone waiting if the device we 618 //contacted for a retry didn't actually retry. 619 if (retryList.size() || (curTick < tickNextIdle && busIdle.scheduled())) { 620 drainEvent = de; 621 return 1; 622 } 623 return 0; 624} 625 626void 627Bus::startup() 628{ 629 if (tickNextIdle < curTick) 630 tickNextIdle = (curTick / clock) * clock + clock; 631} 632 633Bus * 634BusParams::create() 635{ 636 return new Bus(this); 637} 638