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