coherent_xbar.cc revision 4879
11060SN/A/* 214025Sgiacomo.gabrielli@arm.com * Copyright (c) 2006 The Regents of The University of Michigan 39920Syasuko.eckert@amd.com * All rights reserved. 47944SGiacomo.Gabrielli@arm.com * 57944SGiacomo.Gabrielli@arm.com * Redistribution and use in source and binary forms, with or without 67944SGiacomo.Gabrielli@arm.com * modification, are permitted provided that the following conditions are 77944SGiacomo.Gabrielli@arm.com * met: redistributions of source code must retain the above copyright 87944SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer; 97944SGiacomo.Gabrielli@arm.com * redistributions in binary form must reproduce the above copyright 107944SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer in the 117944SGiacomo.Gabrielli@arm.com * documentation and/or other materials provided with the distribution; 127944SGiacomo.Gabrielli@arm.com * neither the name of the copyright holders nor the names of its 137944SGiacomo.Gabrielli@arm.com * contributors may be used to endorse or promote products derived from 147944SGiacomo.Gabrielli@arm.com * this software without specific prior written permission. 152702Sktlim@umich.edu * 166973Stjones1@inf.ed.ac.uk * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171060SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181060SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191060SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201060SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211060SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221060SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231060SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241060SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251060SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261060SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 271060SN/A * 281060SN/A * Authors: Ali Saidi 291060SN/A */ 301060SN/A 311060SN/A/** 321060SN/A * @file 331060SN/A * Definition of a bus object. 341060SN/A */ 351060SN/A 361060SN/A#include <algorithm> 371060SN/A#include <limits> 381060SN/A 391060SN/A#include "base/misc.hh" 401060SN/A#include "base/trace.hh" 412665Ssaidi@eecs.umich.edu#include "mem/bus.hh" 422665Ssaidi@eecs.umich.edu#include "sim/builder.hh" 436973Stjones1@inf.ed.ac.uk 441060SN/APort * 451060SN/ABus::getPort(const std::string &if_name, int idx) 461464SN/A{ 471464SN/A if (if_name == "default") { 481060SN/A if (defaultPort == NULL) { 4910835Sandreas.hansson@arm.com defaultPort = new BusPort(csprintf("%s-default",name()), this, 502731Sktlim@umich.edu defaultId); 5112109SRekai.GonzalezAlberquilla@arm.com cachedBlockSizeValid = false; 522292SN/A return defaultPort; 531464SN/A } else 541060SN/A fatal("Default port already set\n"); 5510687SAndreas.Sandberg@ARM.com } 567720Sgblack@eecs.umich.edu int id; 571060SN/A if (if_name == "functional") { 586658Snate@binkert.org if (!funcPort) { 598887Sgeoffrey.blake@arm.com id = maxId++; 6010319SAndreas.Sandberg@ARM.com funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); 611464SN/A funcPortId = id; 6212107SRekai.GonzalezAlberquilla@arm.com interfaces[id] = funcPort; 631464SN/A } 642669Sktlim@umich.edu return funcPort; 651060SN/A } 666973Stjones1@inf.ed.ac.uk 672669Sktlim@umich.edu // if_name ignored? forced to be empty? 6811608Snikos.nikoleris@arm.com id = maxId++; 697678Sgblack@eecs.umich.edu assert(maxId < std::numeric_limits<typeof(maxId)>::max()); 702292SN/A BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 711060SN/A interfaces[id] = bp; 721060SN/A cachedBlockSizeValid = false; 731060SN/A return bp; 741060SN/A} 751060SN/A 761060SN/Avoid 771060SN/ABus::deletePortRefs(Port *p) 7810319SAndreas.Sandberg@ARM.com{ 791060SN/A 801060SN/A BusPort *bp = dynamic_cast<BusPort*>(p); 811060SN/A if (bp == NULL) 822733Sktlim@umich.edu panic("Couldn't convert Port* to BusPort*\n"); 832733Sktlim@umich.edu // If this is our one functional port 8412109SRekai.GonzalezAlberquilla@arm.com if (funcPort == bp) 851060SN/A return; 8613590Srekai.gonzalezalberquilla@arm.com interfaces.erase(bp->getId()); 8713590Srekai.gonzalezalberquilla@arm.com delete bp; 8813590Srekai.gonzalezalberquilla@arm.com} 8913590Srekai.gonzalezalberquilla@arm.com 902292SN/A/** Get the ranges of anyone other buses that we are connected to. */ 912292SN/Avoid 928486Sgblack@eecs.umich.eduBus::init() 932292SN/A{ 942292SN/A m5::hash_map<short,BusPort*>::iterator intIter; 952292SN/A 962292SN/A for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 971060SN/A intIter->second->sendStatusChange(Port::RangeChange); 985543Ssaidi@eecs.umich.edu} 998902Sandreas.hansson@arm.com 1001060SN/ABus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) 1011060SN/A{} 1029046SAli.Saidi@ARM.com 1039046SAli.Saidi@ARM.comvoid Bus::BusFreeEvent::process() 1049046SAli.Saidi@ARM.com{ 1059046SAli.Saidi@ARM.com bus->recvRetry(-1); 1069046SAli.Saidi@ARM.com} 1079046SAli.Saidi@ARM.com 1089046SAli.Saidi@ARM.comconst char * Bus::BusFreeEvent::description() 1099046SAli.Saidi@ARM.com{ 1109046SAli.Saidi@ARM.com return "bus became available"; 1119046SAli.Saidi@ARM.com} 1129046SAli.Saidi@ARM.com 1139046SAli.Saidi@ARM.comvoid Bus::occupyBus(PacketPtr pkt) 1149046SAli.Saidi@ARM.com{ 1159046SAli.Saidi@ARM.com //Bring tickNextIdle up to the present tick 1169046SAli.Saidi@ARM.com //There is some potential ambiguity where a cycle starts, which might make 1179046SAli.Saidi@ARM.com //a difference when devices are acting right around a cycle boundary. Using 1189046SAli.Saidi@ARM.com //a < allows things which happen exactly on a cycle boundary to take up 11914025Sgiacomo.gabrielli@arm.com //only the following cycle. Anything that happens later will have to "wait" 12014025Sgiacomo.gabrielli@arm.com //for the end of that cycle, and then start using the bus after that. 12114025Sgiacomo.gabrielli@arm.com if (tickNextIdle < curTick) { 1229046SAli.Saidi@ARM.com tickNextIdle = curTick; 1239046SAli.Saidi@ARM.com if (tickNextIdle % clock != 0) 1249046SAli.Saidi@ARM.com tickNextIdle = curTick - (curTick % clock) + clock; 1259046SAli.Saidi@ARM.com } 1269046SAli.Saidi@ARM.com 1279046SAli.Saidi@ARM.com // The packet will be sent. Figure out how long it occupies the bus, and 1289046SAli.Saidi@ARM.com // how much of that time is for the first "word", aka bus width. 1299046SAli.Saidi@ARM.com int numCycles = 0; 1309046SAli.Saidi@ARM.com // Requests need one cycle to send an address 1319046SAli.Saidi@ARM.com if (pkt->isRequest()) 1329046SAli.Saidi@ARM.com numCycles++; 13312421Sgabeblack@google.com else if (pkt->isResponse() || pkt->hasData()) { 1349046SAli.Saidi@ARM.com // If a packet has data, it needs ceil(size/width) cycles to send it 1359046SAli.Saidi@ARM.com // We're using the "adding instead of dividing" trick again here 1369046SAli.Saidi@ARM.com if (pkt->hasData()) { 1379046SAli.Saidi@ARM.com int dataSize = pkt->getSize(); 1389046SAli.Saidi@ARM.com numCycles += dataSize/width; 1399046SAli.Saidi@ARM.com if (dataSize % width) 1409046SAli.Saidi@ARM.com numCycles++; 14113953Sgiacomo.gabrielli@arm.com } else { 1429046SAli.Saidi@ARM.com // If the packet didn't have data, it must have been a response. 14310824SAndreas.Sandberg@ARM.com // Those use the bus for one cycle to send their data. 1449046SAli.Saidi@ARM.com numCycles++; 1459046SAli.Saidi@ARM.com } 1469046SAli.Saidi@ARM.com } 1479046SAli.Saidi@ARM.com 1489046SAli.Saidi@ARM.com // The first word will be delivered after the current tick, the delivery 1499046SAli.Saidi@ARM.com // of the address if any, and one bus cycle to deliver the data 1509046SAli.Saidi@ARM.com pkt->firstWordTime = 1519046SAli.Saidi@ARM.com tickNextIdle + 1529046SAli.Saidi@ARM.com pkt->isRequest() ? clock : 0 + 1532292SN/A clock; 15410417Sandreas.hansson@arm.com 1559046SAli.Saidi@ARM.com //Advance it numCycles bus cycles. 1569046SAli.Saidi@ARM.com //XXX Should this use the repeated addition trick as well? 1579046SAli.Saidi@ARM.com tickNextIdle += (numCycles * clock); 1589046SAli.Saidi@ARM.com if (!busIdle.scheduled()) { 15910030SAli.Saidi@ARM.com busIdle.schedule(tickNextIdle); 16010030SAli.Saidi@ARM.com } else { 1619046SAli.Saidi@ARM.com busIdle.reschedule(tickNextIdle); 1629046SAli.Saidi@ARM.com } 1639046SAli.Saidi@ARM.com DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 1649046SAli.Saidi@ARM.com curTick, tickNextIdle); 1659046SAli.Saidi@ARM.com 1669046SAli.Saidi@ARM.com // The bus will become idle once the current packet is delivered. 1679046SAli.Saidi@ARM.com pkt->finishTime = tickNextIdle; 1689046SAli.Saidi@ARM.com} 1699046SAli.Saidi@ARM.com 1709046SAli.Saidi@ARM.com/** Function called by the port when the bus is receiving a Timing 1719046SAli.Saidi@ARM.com * transaction.*/ 1729046SAli.Saidi@ARM.combool 1739046SAli.Saidi@ARM.comBus::recvTiming(PacketPtr pkt) 17412107SRekai.GonzalezAlberquilla@arm.com{ 1759046SAli.Saidi@ARM.com Port *port; 1769046SAli.Saidi@ARM.com DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", 1779046SAli.Saidi@ARM.com pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 1789046SAli.Saidi@ARM.com 17914025Sgiacomo.gabrielli@arm.com BusPort *pktPort; 1809046SAli.Saidi@ARM.com if (pkt->getSrc() == defaultId) 1819046SAli.Saidi@ARM.com pktPort = defaultPort; 1829046SAli.Saidi@ARM.com else pktPort = interfaces[pkt->getSrc()]; 1839046SAli.Saidi@ARM.com 1849046SAli.Saidi@ARM.com // If the bus is busy, or other devices are in line ahead of the current 1859046SAli.Saidi@ARM.com // one, put this device on the retry list. 18614025Sgiacomo.gabrielli@arm.com if (tickNextIdle > curTick || 1879046SAli.Saidi@ARM.com (retryList.size() && (!inRetry || pktPort != retryList.front()))) 1889046SAli.Saidi@ARM.com { 1899046SAli.Saidi@ARM.com addToRetryList(pktPort); 1909046SAli.Saidi@ARM.com DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n"); 1919046SAli.Saidi@ARM.com return false; 1929046SAli.Saidi@ARM.com } 1939046SAli.Saidi@ARM.com 1949046SAli.Saidi@ARM.com short dest = pkt->getDest(); 1959046SAli.Saidi@ARM.com 1969046SAli.Saidi@ARM.com // Make sure to clear the snoop commit flag so it doesn't think an 1979046SAli.Saidi@ARM.com // access has been handled twice. 1989046SAli.Saidi@ARM.com if (dest == Packet::Broadcast) { 1999046SAli.Saidi@ARM.com port = findPort(pkt->getAddr(), pkt->getSrc()); 2009046SAli.Saidi@ARM.com timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]); 2019046SAli.Saidi@ARM.com 2029046SAli.Saidi@ARM.com if (pkt->memInhibitAsserted()) { 2039046SAli.Saidi@ARM.com //Cache-Cache transfer occuring 20410417Sandreas.hansson@arm.com if (inRetry) { 2051060SN/A retryList.front()->onRetryList(false); 2069046SAli.Saidi@ARM.com retryList.pop_front(); 2079046SAli.Saidi@ARM.com inRetry = false; 2089046SAli.Saidi@ARM.com } 2099046SAli.Saidi@ARM.com occupyBus(pkt); 2109046SAli.Saidi@ARM.com DPRINTF(Bus, "recvTiming: Packet sucessfully sent\n"); 2119046SAli.Saidi@ARM.com return true; 2129046SAli.Saidi@ARM.com } 2139046SAli.Saidi@ARM.com } else { 2149046SAli.Saidi@ARM.com assert(dest >= 0 && dest < maxId); 21513590Srekai.gonzalezalberquilla@arm.com assert(dest != pkt->getSrc()); // catch infinite loops 2169046SAli.Saidi@ARM.com port = interfaces[dest]; 2179046SAli.Saidi@ARM.com } 2189046SAli.Saidi@ARM.com 2199046SAli.Saidi@ARM.com occupyBus(pkt); 2209046SAli.Saidi@ARM.com 2219046SAli.Saidi@ARM.com if (port) { 2229046SAli.Saidi@ARM.com if (port->sendTiming(pkt)) { 2239046SAli.Saidi@ARM.com // Packet was successfully sent. Return true. 22414112Sgabor.dozsa@arm.com // Also take care of retries 2259046SAli.Saidi@ARM.com if (inRetry) { 2269046SAli.Saidi@ARM.com DPRINTF(Bus, "Remove retry from list %d\n", 2279046SAli.Saidi@ARM.com retryList.front()->getId()); 2289046SAli.Saidi@ARM.com retryList.front()->onRetryList(false); 2299046SAli.Saidi@ARM.com retryList.pop_front(); 2309046SAli.Saidi@ARM.com inRetry = false; 23113590Srekai.gonzalezalberquilla@arm.com } 2329046SAli.Saidi@ARM.com return true; 2339046SAli.Saidi@ARM.com } 2349046SAli.Saidi@ARM.com 23513590Srekai.gonzalezalberquilla@arm.com // Packet not successfully sent. Leave or put it on the retry list. 2369046SAli.Saidi@ARM.com DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n", 2379046SAli.Saidi@ARM.com pktPort->getId()); 2389046SAli.Saidi@ARM.com addToRetryList(pktPort); 2399046SAli.Saidi@ARM.com return false; 24013590Srekai.gonzalezalberquilla@arm.com } 2419046SAli.Saidi@ARM.com else { 2429046SAli.Saidi@ARM.com //Forwarding up from responder, just return true; 24313590Srekai.gonzalezalberquilla@arm.com DPRINTF(Bus, "recvTiming: can we be here?\n"); 2449046SAli.Saidi@ARM.com return true; 2459046SAli.Saidi@ARM.com } 2469046SAli.Saidi@ARM.com} 2479046SAli.Saidi@ARM.com 2489046SAli.Saidi@ARM.comvoid 2499046SAli.Saidi@ARM.comBus::recvRetry(int id) 2509046SAli.Saidi@ARM.com{ 2519046SAli.Saidi@ARM.com DPRINTF(Bus, "Received a retry from %s\n", id == -1 ? "self" : interfaces[id]->getPeer()->name()); 2529046SAli.Saidi@ARM.com // If there's anything waiting, and the bus isn't busy... 25312104Snathanael.premillieu@arm.com if (retryList.size() && curTick >= tickNextIdle) { 2549046SAli.Saidi@ARM.com //retryingPort = retryList.front(); 2559046SAli.Saidi@ARM.com inRetry = true; 2569046SAli.Saidi@ARM.com DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 2579046SAli.Saidi@ARM.com retryList.front()->sendRetry(); 25812105Snathanael.premillieu@arm.com // If inRetry is still true, sendTiming wasn't called 2599046SAli.Saidi@ARM.com if (inRetry) 2609046SAli.Saidi@ARM.com { 2619046SAli.Saidi@ARM.com retryList.front()->onRetryList(false); 2629046SAli.Saidi@ARM.com retryList.pop_front(); 26312105Snathanael.premillieu@arm.com inRetry = false; 2649046SAli.Saidi@ARM.com 2659046SAli.Saidi@ARM.com //Bring tickNextIdle up to the present 2669046SAli.Saidi@ARM.com while (tickNextIdle < curTick) 2679046SAli.Saidi@ARM.com tickNextIdle += clock; 26812105Snathanael.premillieu@arm.com 2699046SAli.Saidi@ARM.com //Burn a cycle for the missed grant. 2709046SAli.Saidi@ARM.com tickNextIdle += clock; 2719046SAli.Saidi@ARM.com 2729046SAli.Saidi@ARM.com busIdle.reschedule(tickNextIdle, true); 2739046SAli.Saidi@ARM.com } 2749046SAli.Saidi@ARM.com } 2759046SAli.Saidi@ARM.com //If we weren't able to drain before, we might be able to now. 2769046SAli.Saidi@ARM.com if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) { 27713590Srekai.gonzalezalberquilla@arm.com drainEvent->process(); 2789046SAli.Saidi@ARM.com // Clear the drain event once we're done with it. 2799046SAli.Saidi@ARM.com drainEvent = NULL; 2809046SAli.Saidi@ARM.com } 2819046SAli.Saidi@ARM.com} 2829046SAli.Saidi@ARM.com 28312421Sgabeblack@google.comPort * 28412421Sgabeblack@google.comBus::findPort(Addr addr, int id) 28512421Sgabeblack@google.com{ 2869046SAli.Saidi@ARM.com /* An interval tree would be a better way to do this. --ali. */ 2871060SN/A int dest_id = -1; 2881060SN/A 2891060SN/A PortIter i = portMap.find(RangeSize(addr,1)); 2901060SN/A if (i != portMap.end()) 2911060SN/A dest_id = i->second; 2921060SN/A 2935358Sgblack@eecs.umich.edu // Check if this matches the default range 2945358Sgblack@eecs.umich.edu if (dest_id == -1) { 2955358Sgblack@eecs.umich.edu for (AddrRangeIter iter = defaultRange.begin(); 2965358Sgblack@eecs.umich.edu iter != defaultRange.end(); iter++) { 2975358Sgblack@eecs.umich.edu if (*iter == addr) { 2985358Sgblack@eecs.umich.edu DPRINTF(Bus, " found addr %#llx on default\n", addr); 2995358Sgblack@eecs.umich.edu return defaultPort; 3005358Sgblack@eecs.umich.edu } 3015358Sgblack@eecs.umich.edu } 3025358Sgblack@eecs.umich.edu 3035358Sgblack@eecs.umich.edu if (responderSet) { 3045358Sgblack@eecs.umich.edu panic("Unable to find destination for addr (user set default " 3055358Sgblack@eecs.umich.edu "responder): %#llx", addr); 30613954Sgiacomo.gabrielli@arm.com } else { 30713954Sgiacomo.gabrielli@arm.com DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use " 3087520Sgblack@eecs.umich.edu "default port", addr); 30911608Snikos.nikoleris@arm.com 31013954Sgiacomo.gabrielli@arm.com return defaultPort; 31113954Sgiacomo.gabrielli@arm.com } 3127520Sgblack@eecs.umich.edu } 31313652Sqtt2@cornell.edu 31414297Sjordi.vaquero@metempsy.com 31513652Sqtt2@cornell.edu // we shouldn't be sending this back to where it came from 3167944SGiacomo.Gabrielli@arm.com // do the snoop access and then we should terminate 3179046SAli.Saidi@ARM.com // the cyclical call. 3189046SAli.Saidi@ARM.com if (dest_id == id) 3197944SGiacomo.Gabrielli@arm.com return 0; 3207944SGiacomo.Gabrielli@arm.com 3219046SAli.Saidi@ARM.com return interfaces[dest_id]; 3229046SAli.Saidi@ARM.com} 3237944SGiacomo.Gabrielli@arm.com 3248545Ssaidi@eecs.umich.eduvoid 3258545Ssaidi@eecs.umich.eduBus::functionalSnoop(PacketPtr pkt, Port *responder) 3268545Ssaidi@eecs.umich.edu{ 3278545Ssaidi@eecs.umich.edu // The packet may be changed by another bus on snoops, restore the 3288545Ssaidi@eecs.umich.edu // id after each 3299046SAli.Saidi@ARM.com int src_id = pkt->getSrc(); 3309046SAli.Saidi@ARM.com 3318545Ssaidi@eecs.umich.edu assert(pkt->isRequest()); // hasn't already been satisfied 3328545Ssaidi@eecs.umich.edu 3338545Ssaidi@eecs.umich.edu for (SnoopIter s_iter = snoopPorts.begin(); 3348545Ssaidi@eecs.umich.edu s_iter != snoopPorts.end(); 3358545Ssaidi@eecs.umich.edu s_iter++) { 3369046SAli.Saidi@ARM.com BusPort *p = *s_iter; 3379046SAli.Saidi@ARM.com if (p != responder && p->getId() != src_id) { 3388545Ssaidi@eecs.umich.edu p->sendFunctional(pkt); 3397944SGiacomo.Gabrielli@arm.com } 3407944SGiacomo.Gabrielli@arm.com if (pkt->isResponse()) { 3417944SGiacomo.Gabrielli@arm.com break; 3427944SGiacomo.Gabrielli@arm.com } 3437944SGiacomo.Gabrielli@arm.com pkt->setSrc(src_id); 3447944SGiacomo.Gabrielli@arm.com } 3459046SAli.Saidi@ARM.com} 3467944SGiacomo.Gabrielli@arm.com 3477944SGiacomo.Gabrielli@arm.combool 3481060SN/ABus::timingSnoop(PacketPtr pkt, Port* responder) 3492292SN/A{ 3502292SN/A for (SnoopIter s_iter = snoopPorts.begin(); 3512292SN/A s_iter != snoopPorts.end(); 3522292SN/A s_iter++) { 3533770Sgblack@eecs.umich.edu BusPort *p = *s_iter; 3543770Sgblack@eecs.umich.edu if (p != responder && p->getId() != pkt->getSrc()) { 3553770Sgblack@eecs.umich.edu bool success = p->sendTiming(pkt); 35612105Snathanael.premillieu@arm.com if (!success) 3573770Sgblack@eecs.umich.edu return false; 3583770Sgblack@eecs.umich.edu } 3593770Sgblack@eecs.umich.edu } 3603770Sgblack@eecs.umich.edu 3613770Sgblack@eecs.umich.edu return true; 36212105Snathanael.premillieu@arm.com} 3633770Sgblack@eecs.umich.edu 3649046SAli.Saidi@ARM.com 3653770Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a Atomic 3663770Sgblack@eecs.umich.edu * transaction.*/ 3673770Sgblack@eecs.umich.eduTick 3683770Sgblack@eecs.umich.eduBus::recvAtomic(PacketPtr pkt) 3693770Sgblack@eecs.umich.edu{ 3703770Sgblack@eecs.umich.edu DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 37112106SRekai.GonzalezAlberquilla@arm.com pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 3723770Sgblack@eecs.umich.edu assert(pkt->getDest() == Packet::Broadcast); 3733770Sgblack@eecs.umich.edu assert(pkt->isRequest()); 3743770Sgblack@eecs.umich.edu 3753770Sgblack@eecs.umich.edu // Variables for recording original command and snoop response (if 3763770Sgblack@eecs.umich.edu // any)... if a snooper respondes, we will need to restore 3773770Sgblack@eecs.umich.edu // original command so that additional snoops can take place 3783770Sgblack@eecs.umich.edu // properly 37912105Snathanael.premillieu@arm.com MemCmd orig_cmd = pkt->cmd; 3803770Sgblack@eecs.umich.edu MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 3813770Sgblack@eecs.umich.edu Tick snoop_response_latency = 0; 3823770Sgblack@eecs.umich.edu int orig_src = pkt->getSrc(); 3833770Sgblack@eecs.umich.edu 3843770Sgblack@eecs.umich.edu Port *target_port = findPort(pkt->getAddr(), pkt->getSrc()); 3853770Sgblack@eecs.umich.edu 3863770Sgblack@eecs.umich.edu SnoopIter s_end = snoopPorts.end(); 3873770Sgblack@eecs.umich.edu for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 38812105Snathanael.premillieu@arm.com BusPort *p = *s_iter; 38912105Snathanael.premillieu@arm.com // same port should not have both target addresses and snooping 3903770Sgblack@eecs.umich.edu assert(p != target_port); 3913770Sgblack@eecs.umich.edu if (p->getId() != pkt->getSrc()) { 3923770Sgblack@eecs.umich.edu Tick latency = p->sendAtomic(pkt); 39314025Sgiacomo.gabrielli@arm.com if (pkt->isResponse()) { 39414025Sgiacomo.gabrielli@arm.com // response from snoop agent 3953770Sgblack@eecs.umich.edu assert(pkt->cmd != orig_cmd); 3963770Sgblack@eecs.umich.edu assert(pkt->memInhibitAsserted()); 3973770Sgblack@eecs.umich.edu // should only happen once 3983770Sgblack@eecs.umich.edu assert(snoop_response_cmd == MemCmd::InvalidCmd); 3993770Sgblack@eecs.umich.edu // save response state 4003770Sgblack@eecs.umich.edu snoop_response_cmd = pkt->cmd; 40112105Snathanael.premillieu@arm.com snoop_response_latency = latency; 4023770Sgblack@eecs.umich.edu // restore original packet state for remaining snoopers 4033770Sgblack@eecs.umich.edu pkt->cmd = orig_cmd; 4043770Sgblack@eecs.umich.edu pkt->setSrc(orig_src); 4053770Sgblack@eecs.umich.edu pkt->setDest(Packet::Broadcast); 4063770Sgblack@eecs.umich.edu } 4073770Sgblack@eecs.umich.edu } 4083770Sgblack@eecs.umich.edu } 40912106SRekai.GonzalezAlberquilla@arm.com 4103770Sgblack@eecs.umich.edu Tick response_latency = target_port->sendAtomic(pkt); 4113770Sgblack@eecs.umich.edu 4123770Sgblack@eecs.umich.edu // if we got a response from a snooper, restore it here 4134636Sgblack@eecs.umich.edu if (snoop_response_cmd != MemCmd::InvalidCmd) { 4144636Sgblack@eecs.umich.edu // no one else should have responded 4157720Sgblack@eecs.umich.edu assert(!pkt->isResponse()); 4167720Sgblack@eecs.umich.edu assert(pkt->cmd == orig_cmd); 4174636Sgblack@eecs.umich.edu pkt->cmd = snoop_response_cmd; 4184636Sgblack@eecs.umich.edu response_latency = snoop_response_latency; 4194636Sgblack@eecs.umich.edu } 42010417Sandreas.hansson@arm.com 4218502Sgblack@eecs.umich.edu // why do we have this packet field and the return value both??? 4228502Sgblack@eecs.umich.edu pkt->finishTime = curTick + response_latency; 4233770Sgblack@eecs.umich.edu return response_latency; 4242292SN/A} 4252292SN/A 4262292SN/A/** Function called by the port when the bus is receiving a Functional 42710417Sandreas.hansson@arm.com * transaction.*/ 4281060SN/Avoid 4291060SN/ABus::recvFunctional(PacketPtr pkt) 4301060SN/A{ 4311060SN/A DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 4321464SN/A pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 4331684SN/A assert(pkt->getDest() == Packet::Broadcast); 4341464SN/A 4351060SN/A Port* port = findPort(pkt->getAddr(), pkt->getSrc()); 4361464SN/A functionalSnoop(pkt, port ? port : interfaces[pkt->getSrc()]); 4371060SN/A 4381060SN/A // If the snooping hasn't found what we were looking for, keep going. 4391060SN/A if (!pkt->isResponse() && port) { 4401060SN/A port->sendFunctional(pkt); 4411060SN/A } 4421060SN/A} 4433326Sktlim@umich.edu 44410110Sandreas.hansson@arm.com/** Function called by the port when the bus is receiving a status change.*/ 4453326Sktlim@umich.eduvoid 44610190Sakash.bagdia@arm.comBus::recvStatusChange(Port::Status status, int id) 44710190Sakash.bagdia@arm.com{ 44810190Sakash.bagdia@arm.com AddrRangeList ranges; 4498832SAli.Saidi@ARM.com bool snoops; 45010110Sandreas.hansson@arm.com AddrRangeIter iter; 4518832SAli.Saidi@ARM.com 4525714Shsul@eecs.umich.edu assert(status == Port::RangeChange && 45311005Sandreas.sandberg@arm.com "The other statuses need to be implemented."); 4545714Shsul@eecs.umich.edu 4551060SN/A DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 45610110Sandreas.hansson@arm.com 45713590Srekai.gonzalezalberquilla@arm.com if (id == defaultId) { 45813590Srekai.gonzalezalberquilla@arm.com defaultRange.clear(); 45913590Srekai.gonzalezalberquilla@arm.com // Only try to update these ranges if the user set a default responder. 4601060SN/A if (responderSet) { 4611060SN/A defaultPort->getPeerAddressRanges(ranges, snoops); 4621060SN/A assert(snoops == false); 4631060SN/A for(iter = ranges.begin(); iter != ranges.end(); iter++) { 4642292SN/A defaultRange.push_back(*iter); 4651060SN/A DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 4661060SN/A iter->start, iter->end); 4671060SN/A } 4687720Sgblack@eecs.umich.edu } 4697720Sgblack@eecs.umich.edu } else { 4703965Sgblack@eecs.umich.edu 4717720Sgblack@eecs.umich.edu assert((id < maxId && id >= 0) || id == defaultId); 4723965Sgblack@eecs.umich.edu BusPort *port = interfaces[id]; 4732935Sksewell@umich.edu 4747720Sgblack@eecs.umich.edu // Clean out any previously existent ids 4751060SN/A for (PortIter portIter = portMap.begin(); 4763794Sgblack@eecs.umich.edu portIter != portMap.end(); ) { 4777720Sgblack@eecs.umich.edu if (portIter->second == id) 4783794Sgblack@eecs.umich.edu portMap.erase(portIter++); 4793794Sgblack@eecs.umich.edu else 4807720Sgblack@eecs.umich.edu portIter++; 4811060SN/A } 4824636Sgblack@eecs.umich.edu 4837720Sgblack@eecs.umich.edu for (SnoopIter s_iter = snoopPorts.begin(); 4844636Sgblack@eecs.umich.edu s_iter != snoopPorts.end(); ) { 4851060SN/A if ((*s_iter)->getId() == id) 4863794Sgblack@eecs.umich.edu s_iter = snoopPorts.erase(s_iter); 4873794Sgblack@eecs.umich.edu else 4889046SAli.Saidi@ARM.com s_iter++; 4893794Sgblack@eecs.umich.edu } 4903794Sgblack@eecs.umich.edu 4913794Sgblack@eecs.umich.edu port->getPeerAddressRanges(ranges, snoops); 4923794Sgblack@eecs.umich.edu 4939046SAli.Saidi@ARM.com if (snoops) { 4943794Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id); 4951060SN/A snoopPorts.push_back(port); 4961060SN/A } 4972935Sksewell@umich.edu 4983794Sgblack@eecs.umich.edu for (iter = ranges.begin(); iter != ranges.end(); iter++) { 4997720Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 5007720Sgblack@eecs.umich.edu iter->start, iter->end, id); 5017720Sgblack@eecs.umich.edu if (portMap.insert(*iter, id) == portMap.end()) 5023794Sgblack@eecs.umich.edu panic("Two devices with same range\n"); 5033794Sgblack@eecs.umich.edu 5041060SN/A } 5051060SN/A } 5061060SN/A DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 5075543Ssaidi@eecs.umich.edu 5085543Ssaidi@eecs.umich.edu // tell all our peers that our address range has changed. 5095543Ssaidi@eecs.umich.edu // Don't tell the device that caused this change, it already knows 5105543Ssaidi@eecs.umich.edu m5::hash_map<short,BusPort*>::iterator intIter; 51112768Sqtt2@cornell.edu 5122336SN/A for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 5132336SN/A if (intIter->first != id && intIter->first != funcPortId) 5141060SN/A intIter->second->sendStatusChange(Port::RangeChange); 5151060SN/A 5165543Ssaidi@eecs.umich.edu if (id != defaultId && defaultPort) 5175543Ssaidi@eecs.umich.edu defaultPort->sendStatusChange(Port::RangeChange); 51812110SRekai.GonzalezAlberquilla@arm.com} 5195543Ssaidi@eecs.umich.edu 5205543Ssaidi@eecs.umich.eduvoid 5215543Ssaidi@eecs.umich.eduBus::addressRanges(AddrRangeList &resp, bool &snoop, int id) 5225543Ssaidi@eecs.umich.edu{ 5231060SN/A resp.clear(); 5245543Ssaidi@eecs.umich.edu snoop = false; 5255543Ssaidi@eecs.umich.edu 5262935Sksewell@umich.edu DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 5271060SN/A 5281060SN/A for (AddrRangeIter dflt_iter = defaultRange.begin(); 5292292SN/A dflt_iter != defaultRange.end(); dflt_iter++) { 5302731Sktlim@umich.edu resp.push_back(*dflt_iter); 5312292SN/A DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 5322731Sktlim@umich.edu dflt_iter->end); 5337784SAli.Saidi@ARM.com } 5341060SN/A for (PortIter portIter = portMap.begin(); 5351060SN/A portIter != portMap.end(); portIter++) { 5361060SN/A bool subset = false; 5372292SN/A for (AddrRangeIter dflt_iter = defaultRange.begin(); 5382336SN/A dflt_iter != defaultRange.end(); dflt_iter++) { 5392308SN/A if ((portIter->first.start < dflt_iter->start && 5404828Sgblack@eecs.umich.edu portIter->first.end >= dflt_iter->start) || 5414654Sgblack@eecs.umich.edu (portIter->first.start < dflt_iter->end && 5424654Sgblack@eecs.umich.edu portIter->first.end >= dflt_iter->end)) 5434636Sgblack@eecs.umich.edu fatal("Devices can not set ranges that itersect the default set\ 5444654Sgblack@eecs.umich.edu but are not a subset of the default set.\n"); 5454654Sgblack@eecs.umich.edu if (portIter->first.start >= dflt_iter->start && 5464636Sgblack@eecs.umich.edu portIter->first.end <= dflt_iter->end) { 5472292SN/A subset = true; 5482292SN/A DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 5492731Sktlim@umich.edu portIter->first.start, portIter->first.end); 5502292SN/A } 5512292SN/A } 5522731Sktlim@umich.edu if (portIter->second != id && !subset) { 5532292SN/A resp.push_back(portIter->first); 5542292SN/A DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 5552731Sktlim@umich.edu portIter->first.start, portIter->first.end); 5562292SN/A } 5572292SN/A } 5582731Sktlim@umich.edu 5592292SN/A for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 5602292SN/A s_iter++) { 5612731Sktlim@umich.edu if ((*s_iter)->getId() != id) { 5622292SN/A snoop = true; 5632292SN/A break; 5642731Sktlim@umich.edu } 5652292SN/A } 5662731Sktlim@umich.edu} 5672731Sktlim@umich.edu 5682292SN/Aint 5692292SN/ABus::findBlockSize(int id) 5702292SN/A{ 5712292SN/A if (cachedBlockSizeValid) 5722292SN/A return cachedBlockSize; 5732292SN/A 5742731Sktlim@umich.edu int max_bs = -1; 5751060SN/A 5761464SN/A for (PortIter portIter = portMap.begin(); 5771464SN/A portIter != portMap.end(); portIter++) { 5781464SN/A int tmp_bs = interfaces[portIter->second]->peerBlockSize(); 5791464SN/A if (tmp_bs > max_bs) 5807720Sgblack@eecs.umich.edu max_bs = tmp_bs; 5817720Sgblack@eecs.umich.edu } 5821464SN/A for (SnoopIter s_iter = snoopPorts.begin(); 5832292SN/A s_iter != snoopPorts.end(); s_iter++) { 5845543Ssaidi@eecs.umich.edu int tmp_bs = (*s_iter)->peerBlockSize(); 5851684SN/A if (tmp_bs > max_bs) 5862292SN/A max_bs = tmp_bs; 5871060SN/A } 5881060SN/A if (max_bs <= 0) 5891060SN/A max_bs = defaultBlockSize; 5901060SN/A 5911060SN/A if (max_bs != 64) 5921060SN/A warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 59310715SRekai.GonzalezAlberquilla@arm.com cachedBlockSize = max_bs; 59412109SRekai.GonzalezAlberquilla@arm.com cachedBlockSizeValid = true; 59513590Srekai.gonzalezalberquilla@arm.com return max_bs; 59613590Srekai.gonzalezalberquilla@arm.com} 59712109SRekai.GonzalezAlberquilla@arm.com 59812109SRekai.GonzalezAlberquilla@arm.com 59913610Sgiacomo.gabrielli@arm.comunsigned int 60013610Sgiacomo.gabrielli@arm.comBus::drain(Event * de) 60113610Sgiacomo.gabrielli@arm.com{ 60213610Sgiacomo.gabrielli@arm.com //We should check that we're not "doing" anything, and that noone is 60313610Sgiacomo.gabrielli@arm.com //waiting. We might be idle but have someone waiting if the device we 6041060SN/A //contacted for a retry didn't actually retry. 6051060SN/A if (curTick >= tickNextIdle && retryList.size() == 0) { 60612106SRekai.GonzalezAlberquilla@arm.com return 0; 6071060SN/A } else { 6081060SN/A drainEvent = de; 60912106SRekai.GonzalezAlberquilla@arm.com return 1; 6101060SN/A } 61112107SRekai.GonzalezAlberquilla@arm.com} 61212107SRekai.GonzalezAlberquilla@arm.com 61312107SRekai.GonzalezAlberquilla@arm.comvoid 61412107SRekai.GonzalezAlberquilla@arm.comBus::startup() 61512107SRekai.GonzalezAlberquilla@arm.com{ 61612107SRekai.GonzalezAlberquilla@arm.com if (tickNextIdle < curTick) 61712107SRekai.GonzalezAlberquilla@arm.com tickNextIdle = (curTick / clock) * clock + clock; 6188733Sgeoffrey.blake@arm.com} 6198733Sgeoffrey.blake@arm.com 62012107SRekai.GonzalezAlberquilla@arm.comBEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) 6218733Sgeoffrey.blake@arm.com 62212107SRekai.GonzalezAlberquilla@arm.com Param<int> bus_id; 6238733Sgeoffrey.blake@arm.com Param<int> clock; 62412107SRekai.GonzalezAlberquilla@arm.com Param<int> width; 6258733Sgeoffrey.blake@arm.com Param<bool> responder_set; 6261684SN/A Param<int> block_size; 62712107SRekai.GonzalezAlberquilla@arm.com 62812109SRekai.GonzalezAlberquilla@arm.comEND_DECLARE_SIM_OBJECT_PARAMS(Bus) 62912109SRekai.GonzalezAlberquilla@arm.com 63012107SRekai.GonzalezAlberquilla@arm.comBEGIN_INIT_SIM_OBJECT_PARAMS(Bus) 63112107SRekai.GonzalezAlberquilla@arm.com INIT_PARAM(bus_id, "a globally unique bus id"), 6328733Sgeoffrey.blake@arm.com INIT_PARAM(clock, "bus clock speed"), 6339046SAli.Saidi@ARM.com INIT_PARAM(width, "width of the bus (bits)"), 63412107SRekai.GonzalezAlberquilla@arm.com INIT_PARAM(responder_set, "Is a default responder set by the user"), 63512107SRekai.GonzalezAlberquilla@arm.com INIT_PARAM(block_size, "Default blocksize if no device has one") 6368733Sgeoffrey.blake@arm.comEND_INIT_SIM_OBJECT_PARAMS(Bus) 6378733Sgeoffrey.blake@arm.com 6381060SN/ACREATE_SIM_OBJECT(Bus) 63912109SRekai.GonzalezAlberquilla@arm.com{ 64012109SRekai.GonzalezAlberquilla@arm.com return new Bus(getInstanceName(), bus_id, clock, width, responder_set, 64112109SRekai.GonzalezAlberquilla@arm.com block_size); 64212109SRekai.GonzalezAlberquilla@arm.com} 64312109SRekai.GonzalezAlberquilla@arm.com 64412109SRekai.GonzalezAlberquilla@arm.comREGISTER_SIM_OBJECT("Bus", Bus) 64512109SRekai.GonzalezAlberquilla@arm.com