xbar.cc revision 3252
17404SAli.Saidi@ARM.com/*
210324SCurtis.Dunham@arm.com * Copyright (c) 2006 The Regents of The University of Michigan
37404SAli.Saidi@ARM.com * All rights reserved.
47404SAli.Saidi@ARM.com *
57404SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without
67404SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are
77404SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright
87404SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer;
97404SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright
107404SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the
117404SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
127404SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its
137404SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from
147404SAli.Saidi@ARM.com * this software without specific prior written permission.
157404SAli.Saidi@ARM.com *
167404SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177404SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187404SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197404SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207404SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217404SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227404SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237404SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247404SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257404SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267404SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277404SAli.Saidi@ARM.com *
287404SAli.Saidi@ARM.com * Authors: Ali Saidi
297404SAli.Saidi@ARM.com */
307404SAli.Saidi@ARM.com
317404SAli.Saidi@ARM.com/**
327404SAli.Saidi@ARM.com * @file
337404SAli.Saidi@ARM.com * Definition of a bus object.
347404SAli.Saidi@ARM.com */
357404SAli.Saidi@ARM.com
367404SAli.Saidi@ARM.com
377404SAli.Saidi@ARM.com#include "base/misc.hh"
3810037SARM gem5 Developers#include "base/trace.hh"
397404SAli.Saidi@ARM.com#include "mem/bus.hh"
407404SAli.Saidi@ARM.com#include "sim/builder.hh"
4110474Sandreas.hansson@arm.com
4210474Sandreas.hansson@arm.comPort *
437404SAli.Saidi@ARM.comBus::getPort(const std::string &if_name, int idx)
4410037SARM gem5 Developers{
4510037SARM gem5 Developers    if (if_name == "default")
467404SAli.Saidi@ARM.com        if (defaultPort == NULL) {
477404SAli.Saidi@ARM.com            defaultPort = new BusPort(csprintf("%s-default",name()), this,
487728SAli.Saidi@ARM.com                    defaultId);
497404SAli.Saidi@ARM.com            return defaultPort;
508245Snate@binkert.org        } else
519152Satgutier@umich.edu            fatal("Default port already set\n");
528245Snate@binkert.org
538245Snate@binkert.org    // if_name ignored?  forced to be empty?
547748SAli.Saidi@ARM.com    int id = interfaces.size();
557404SAli.Saidi@ARM.com    BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
567404SAli.Saidi@ARM.com    interfaces.push_back(bp);
577404SAli.Saidi@ARM.com    return bp;
587404SAli.Saidi@ARM.com}
5910037SARM gem5 Developers
6010037SARM gem5 Developers/** Get the ranges of anyone other buses that we are connected to. */
6110037SARM gem5 Developersvoid
629258SAli.Saidi@ARM.comBus::init()
6310621SCurtis.Dunham@arm.com{
6410621SCurtis.Dunham@arm.com    std::vector<BusPort*>::iterator intIter;
6510037SARM gem5 Developers
6610037SARM gem5 Developers    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
6710037SARM gem5 Developers        (*intIter)->sendStatusChange(Port::RangeChange);
6810037SARM gem5 Developers}
697439Sdam.sunwoo@arm.com
707576SAli.Saidi@ARM.comBus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus)
7110037SARM gem5 Developers{}
7210037SARM gem5 Developers
7310037SARM gem5 Developersvoid Bus::BusFreeEvent::process()
7410037SARM gem5 Developers{
7510037SARM gem5 Developers    bus->recvRetry(-1);
7610037SARM gem5 Developers}
7710037SARM gem5 Developers
7810037SARM gem5 Developersconst char * Bus::BusFreeEvent::description()
7910037SARM gem5 Developers{
8010037SARM gem5 Developers    return "bus became available";
8110037SARM gem5 Developers}
8210037SARM gem5 Developers
8310037SARM gem5 Developersvoid Bus::occupyBus(PacketPtr pkt)
8410037SARM gem5 Developers{
8510037SARM gem5 Developers    //Bring tickNextIdle up to the present tick
8610037SARM gem5 Developers    //There is some potential ambiguity where a cycle starts, which might make
8710037SARM gem5 Developers    //a difference when devices are acting right around a cycle boundary. Using
887439Sdam.sunwoo@arm.com    //a < allows things which happen exactly on a cycle boundary to take up only
897404SAli.Saidi@ARM.com    //the following cycle. Anthing that happens later will have to "wait" for
907404SAli.Saidi@ARM.com    //the end of that cycle, and then start using the bus after that.
917404SAli.Saidi@ARM.com    while (tickNextIdle < curTick)
927404SAli.Saidi@ARM.com        tickNextIdle += clock;
937404SAli.Saidi@ARM.com
947404SAli.Saidi@ARM.com    // The packet will be sent. Figure out how long it occupies the bus, and
9510537Sandreas.hansson@arm.com    // how much of that time is for the first "word", aka bus width.
9610537Sandreas.hansson@arm.com    int numCycles = 0;
9710537Sandreas.hansson@arm.com    // Requests need one cycle to send an address
9810537Sandreas.hansson@arm.com    if (pkt->isRequest())
9910537Sandreas.hansson@arm.com        numCycles++;
10010537Sandreas.hansson@arm.com    else if (pkt->isResponse() || pkt->hasData()) {
10110537Sandreas.hansson@arm.com        // If a packet has data, it needs ceil(size/width) cycles to send it
10210537Sandreas.hansson@arm.com        // We're using the "adding instead of dividing" trick again here
10310537Sandreas.hansson@arm.com        if (pkt->hasData()) {
10410037SARM gem5 Developers            int dataSize = pkt->getSize();
10510037SARM gem5 Developers            for (int transmitted = 0; transmitted < dataSize;
10610037SARM gem5 Developers                    transmitted += width) {
1079152Satgutier@umich.edu                numCycles++;
1089152Satgutier@umich.edu            }
1099152Satgutier@umich.edu        } else {
11010037SARM gem5 Developers            // If the packet didn't have data, it must have been a response.
1119152Satgutier@umich.edu            // Those use the bus for one cycle to send their data.
1129342SAndreas.Sandberg@arm.com            numCycles++;
1139152Satgutier@umich.edu        }
1149342SAndreas.Sandberg@arm.com    }
1159342SAndreas.Sandberg@arm.com
1169152Satgutier@umich.edu    // The first word will be delivered after the current tick, the delivery
1179152Satgutier@umich.edu    // of the address if any, and one bus cycle to deliver the data
1189152Satgutier@umich.edu    pkt->firstWordTime =
1197748SAli.Saidi@ARM.com        tickNextIdle +
1209342SAndreas.Sandberg@arm.com        pkt->isRequest() ? clock : 0 +
1217404SAli.Saidi@ARM.com        clock;
1229342SAndreas.Sandberg@arm.com
1239152Satgutier@umich.edu    //Advance it numCycles bus cycles.
12410037SARM gem5 Developers    //XXX Should this use the repeated addition trick as well?
1259152Satgutier@umich.edu    tickNextIdle += (numCycles * clock);
12610037SARM gem5 Developers    if (!busIdle.scheduled()) {
12710037SARM gem5 Developers        busIdle.schedule(tickNextIdle);
12810037SARM gem5 Developers    } else {
12910037SARM gem5 Developers        busIdle.reschedule(tickNextIdle);
13010037SARM gem5 Developers    }
13110037SARM gem5 Developers    DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
13210037SARM gem5 Developers            curTick, tickNextIdle);
13310037SARM gem5 Developers
1349342SAndreas.Sandberg@arm.com    // The bus will become idle once the current packet is delivered.
1359342SAndreas.Sandberg@arm.com    pkt->finishTime = tickNextIdle;
1369152Satgutier@umich.edu}
1379152Satgutier@umich.edu
1389152Satgutier@umich.edu/** Function called by the port when the bus is receiving a Timing
1399152Satgutier@umich.edu * transaction.*/
14010037SARM gem5 Developersbool
14110037SARM gem5 DevelopersBus::recvTiming(Packet *pkt)
14210037SARM gem5 Developers{
1439152Satgutier@umich.edu    Port *port;
14410037SARM gem5 Developers    DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
14510037SARM gem5 Developers            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
1467733SAli.Saidi@ARM.com
1477404SAli.Saidi@ARM.com    BusPort *pktPort = interfaces[pkt->getSrc()];
1487404SAli.Saidi@ARM.com
1497748SAli.Saidi@ARM.com    // If the bus is busy, or other devices are in line ahead of the current
1509342SAndreas.Sandberg@arm.com    // one, put this device on the retry list.
1517748SAli.Saidi@ARM.com    if (tickNextIdle > curTick ||
1529342SAndreas.Sandberg@arm.com            (retryList.size() && (!inRetry || pktPort != retryList.front()))) {
1539524SAndreas.Sandberg@ARM.com        addToRetryList(pktPort);
1549152Satgutier@umich.edu        return false;
1559152Satgutier@umich.edu    }
15610621SCurtis.Dunham@arm.com
1577748SAli.Saidi@ARM.com    short dest = pkt->getDest();
1587748SAli.Saidi@ARM.com    if (dest == Packet::Broadcast) {
1597748SAli.Saidi@ARM.com        if (timingSnoop(pkt)) {
1609294Sandreas.hansson@arm.com            pkt->flags |= SNOOP_COMMIT;
1619294Sandreas.hansson@arm.com            bool success = timingSnoop(pkt);
1627404SAli.Saidi@ARM.com            assert(success);
1637404SAli.Saidi@ARM.com            if (pkt->flags & SATISFIED) {
1648922Swilliam.wang@arm.com                //Cache-Cache transfer occuring
1657404SAli.Saidi@ARM.com                if (inRetry) {
1668922Swilliam.wang@arm.com                    retryList.front()->onRetryList(false);
1677404SAli.Saidi@ARM.com                    retryList.pop_front();
1687404SAli.Saidi@ARM.com                    inRetry = false;
1697404SAli.Saidi@ARM.com                }
17010037SARM gem5 Developers                occupyBus(pkt);
17110037SARM gem5 Developers                return true;
17210037SARM gem5 Developers            }
17310037SARM gem5 Developers            port = findPort(pkt->getAddr(), pkt->getSrc());
1747404SAli.Saidi@ARM.com        } else {
1758733Sgeoffrey.blake@arm.com            //Snoop didn't succeed
17610621SCurtis.Dunham@arm.com            addToRetryList(pktPort);
17710621SCurtis.Dunham@arm.com            return false;
17810109SGeoffrey.Blake@arm.com        }
17910037SARM gem5 Developers    } else {
18010109SGeoffrey.Blake@arm.com        assert(dest >= 0 && dest < interfaces.size());
1817439Sdam.sunwoo@arm.com        assert(dest != pkt->getSrc()); // catch infinite loops
1827439Sdam.sunwoo@arm.com        port = interfaces[dest];
1837439Sdam.sunwoo@arm.com    }
1847439Sdam.sunwoo@arm.com
1857404SAli.Saidi@ARM.com    occupyBus(pkt);
1867439Sdam.sunwoo@arm.com
1877439Sdam.sunwoo@arm.com    if (port->sendTiming(pkt))  {
18810109SGeoffrey.Blake@arm.com        // Packet was successfully sent. Return true.
18910109SGeoffrey.Blake@arm.com        // Also take care of retries
19010109SGeoffrey.Blake@arm.com        if (inRetry) {
19110109SGeoffrey.Blake@arm.com            DPRINTF(Bus, "Remove retry from list %i\n", retryList.front());
19210109SGeoffrey.Blake@arm.com            retryList.front()->onRetryList(false);
19310109SGeoffrey.Blake@arm.com            retryList.pop_front();
19410109SGeoffrey.Blake@arm.com            inRetry = false;
19510109SGeoffrey.Blake@arm.com        }
1968202SAli.Saidi@ARM.com        return true;
1978202SAli.Saidi@ARM.com    }
1988202SAli.Saidi@ARM.com
1998202SAli.Saidi@ARM.com    // Packet not successfully sent. Leave or put it on the retry list.
2008202SAli.Saidi@ARM.com    DPRINTF(Bus, "Adding a retry to RETRY list %i\n", pktPort);
2018202SAli.Saidi@ARM.com    addToRetryList(pktPort);
2028202SAli.Saidi@ARM.com    return false;
20310037SARM gem5 Developers}
20410621SCurtis.Dunham@arm.com
20510474Sandreas.hansson@arm.comvoid
2068202SAli.Saidi@ARM.comBus::recvRetry(int id)
2077439Sdam.sunwoo@arm.com{
20810621SCurtis.Dunham@arm.com    DPRINTF(Bus, "Received a retry\n");
2097439Sdam.sunwoo@arm.com    // If there's anything waiting...
21010621SCurtis.Dunham@arm.com    if (retryList.size()) {
2117439Sdam.sunwoo@arm.com        //retryingPort = retryList.front();
21210037SARM gem5 Developers        inRetry = true;
21310037SARM gem5 Developers        DPRINTF(Bus, "Sending a retry\n");
2147439Sdam.sunwoo@arm.com        retryList.front()->sendRetry();
2157439Sdam.sunwoo@arm.com        // If inRetry is still true, sendTiming wasn't called
2167439Sdam.sunwoo@arm.com        if (inRetry)
21710037SARM gem5 Developers        {
21810037SARM gem5 Developers            retryList.front()->onRetryList(false);
21910037SARM gem5 Developers            retryList.pop_front();
2207439Sdam.sunwoo@arm.com            inRetry = false;
2218733Sgeoffrey.blake@arm.com
2227439Sdam.sunwoo@arm.com            //Bring tickNextIdle up to the present
22310037SARM gem5 Developers            while (tickNextIdle < curTick)
22410037SARM gem5 Developers                tickNextIdle += clock;
22510037SARM gem5 Developers
2267404SAli.Saidi@ARM.com            //Burn a cycle for the missed grant.
2277436Sdam.sunwoo@arm.com            tickNextIdle += clock;
2287436Sdam.sunwoo@arm.com
22910037SARM gem5 Developers            if (!busIdle.scheduled()) {
23010037SARM gem5 Developers                busIdle.schedule(tickNextIdle);
23110037SARM gem5 Developers            } else {
23210037SARM gem5 Developers                busIdle.reschedule(tickNextIdle);
23310037SARM gem5 Developers            }
23410037SARM gem5 Developers        }
23510037SARM gem5 Developers    }
23610037SARM gem5 Developers}
23710037SARM gem5 Developers
23810037SARM gem5 DevelopersPort *
23910037SARM gem5 DevelopersBus::findPort(Addr addr, int id)
24010037SARM gem5 Developers{
24110324SCurtis.Dunham@arm.com    /* An interval tree would be a better way to do this. --ali. */
24210037SARM gem5 Developers    int dest_id = -1;
24310037SARM gem5 Developers    int i = 0;
24410037SARM gem5 Developers    bool found = false;
24510037SARM gem5 Developers    AddrRangeIter iter;
24610037SARM gem5 Developers
24710324SCurtis.Dunham@arm.com    while (i < portList.size() && !found)
24810037SARM gem5 Developers    {
24910037SARM gem5 Developers        if (portList[i].range == addr) {
25010037SARM gem5 Developers            dest_id = portList[i].portId;
25110037SARM gem5 Developers            found = true;
25210324SCurtis.Dunham@arm.com            DPRINTF(Bus, "  found addr %#llx on device %d\n", addr, dest_id);
25310037SARM gem5 Developers        }
25410037SARM gem5 Developers        i++;
25510037SARM gem5 Developers    }
25610037SARM gem5 Developers
25710037SARM gem5 Developers    // Check if this matches the default range
25810037SARM gem5 Developers    if (dest_id == -1) {
25910037SARM gem5 Developers        for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) {
26010037SARM gem5 Developers            if (*iter == addr) {
26110037SARM gem5 Developers                DPRINTF(Bus, "  found addr %#llx on default\n", addr);
26210037SARM gem5 Developers                return defaultPort;
26310037SARM gem5 Developers            }
26410037SARM gem5 Developers        }
26510037SARM gem5 Developers        panic("Unable to find destination for addr: %#llx", addr);
26610037SARM gem5 Developers    }
2677439Sdam.sunwoo@arm.com
2687439Sdam.sunwoo@arm.com
2697439Sdam.sunwoo@arm.com    // we shouldn't be sending this back to where it came from
2707439Sdam.sunwoo@arm.com    assert(dest_id != id);
2717439Sdam.sunwoo@arm.com
27210621SCurtis.Dunham@arm.com    return interfaces[dest_id];
27310621SCurtis.Dunham@arm.com}
27410037SARM gem5 Developers
27510037SARM gem5 Developersstd::vector<int>
27610037SARM gem5 DevelopersBus::findSnoopPorts(Addr addr, int id)
27710037SARM gem5 Developers{
27810037SARM gem5 Developers    int i = 0;
27910037SARM gem5 Developers    AddrRangeIter iter;
28010037SARM gem5 Developers    std::vector<int> ports;
2817728SAli.Saidi@ARM.com
28210037SARM gem5 Developers    while (i < portSnoopList.size())
28310037SARM gem5 Developers    {
28410037SARM gem5 Developers        if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) {
28510037SARM gem5 Developers            //Careful  to not overlap ranges
28610037SARM gem5 Developers            //or snoop will be called more than once on the port
28710037SARM gem5 Developers            ports.push_back(portSnoopList[i].portId);
28810037SARM gem5 Developers//            DPRINTF(Bus, "  found snoop addr %#llx on device%d\n", addr,
28910037SARM gem5 Developers//                    portSnoopList[i].portId);
29010037SARM gem5 Developers        }
29110037SARM gem5 Developers        i++;
29210037SARM gem5 Developers    }
29310621SCurtis.Dunham@arm.com    return ports;
29410621SCurtis.Dunham@arm.com}
29510621SCurtis.Dunham@arm.com
29610621SCurtis.Dunham@arm.comvoid
29710037SARM gem5 DevelopersBus::atomicSnoop(Packet *pkt)
29810037SARM gem5 Developers{
29910037SARM gem5 Developers    std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
30010109SGeoffrey.Blake@arm.com
30110037SARM gem5 Developers    while (!ports.empty())
30210109SGeoffrey.Blake@arm.com    {
30310037SARM gem5 Developers        interfaces[ports.back()]->sendAtomic(pkt);
30410109SGeoffrey.Blake@arm.com        ports.pop_back();
30510037SARM gem5 Developers    }
30610109SGeoffrey.Blake@arm.com}
30710109SGeoffrey.Blake@arm.com
30810109SGeoffrey.Blake@arm.comvoid
30910109SGeoffrey.Blake@arm.comBus::functionalSnoop(Packet *pkt)
31010109SGeoffrey.Blake@arm.com{
31110109SGeoffrey.Blake@arm.com    std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
31210109SGeoffrey.Blake@arm.com
31310109SGeoffrey.Blake@arm.com    while (!ports.empty())
31410109SGeoffrey.Blake@arm.com    {
31510037SARM gem5 Developers        interfaces[ports.back()]->sendFunctional(pkt);
3167728SAli.Saidi@ARM.com        ports.pop_back();
3178067SAli.Saidi@ARM.com    }
3187728SAli.Saidi@ARM.com}
3197728SAli.Saidi@ARM.com
32010621SCurtis.Dunham@arm.combool
3217728SAli.Saidi@ARM.comBus::timingSnoop(Packet *pkt)
3227728SAli.Saidi@ARM.com{
32310621SCurtis.Dunham@arm.com    std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
32410037SARM gem5 Developers    bool success = true;
32510037SARM gem5 Developers
32610037SARM gem5 Developers    while (!ports.empty() && success)
32710037SARM gem5 Developers    {
32810037SARM gem5 Developers        success = interfaces[ports.back()]->sendTiming(pkt);
32910037SARM gem5 Developers        ports.pop_back();
3307728SAli.Saidi@ARM.com    }
3317728SAli.Saidi@ARM.com
3327728SAli.Saidi@ARM.com    return success;
3337728SAli.Saidi@ARM.com}
3347728SAli.Saidi@ARM.com
3357728SAli.Saidi@ARM.com
3367728SAli.Saidi@ARM.com/** Function called by the port when the bus is receiving a Atomic
3377728SAli.Saidi@ARM.com * transaction.*/
3387728SAli.Saidi@ARM.comTick
3397728SAli.Saidi@ARM.comBus::recvAtomic(Packet *pkt)
34010621SCurtis.Dunham@arm.com{
3417728SAli.Saidi@ARM.com    DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
3429258SAli.Saidi@ARM.com            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
34310037SARM gem5 Developers    assert(pkt->getDest() == Packet::Broadcast);
34410037SARM gem5 Developers    atomicSnoop(pkt);
34510037SARM gem5 Developers    return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt);
34610037SARM gem5 Developers}
34710037SARM gem5 Developers
34810037SARM gem5 Developers/** Function called by the port when the bus is receiving a Functional
3499535Smrinmoy.ghosh@arm.com * transaction.*/
35010037SARM gem5 Developersvoid
35110037SARM gem5 DevelopersBus::recvFunctional(Packet *pkt)
35210037SARM gem5 Developers{
35310037SARM gem5 Developers    DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
3549258SAli.Saidi@ARM.com            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
3559535Smrinmoy.ghosh@arm.com    assert(pkt->getDest() == Packet::Broadcast);
3569535Smrinmoy.ghosh@arm.com    functionalSnoop(pkt);
3579535Smrinmoy.ghosh@arm.com    findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt);
3589535Smrinmoy.ghosh@arm.com}
3599535Smrinmoy.ghosh@arm.com
3609535Smrinmoy.ghosh@arm.com/** Function called by the port when the bus is receiving a status change.*/
3619258SAli.Saidi@ARM.comvoid
3629258SAli.Saidi@ARM.comBus::recvStatusChange(Port::Status status, int id)
3639258SAli.Saidi@ARM.com{
36410579SAndrew.Bardsley@arm.com    AddrRangeList ranges;
36510579SAndrew.Bardsley@arm.com    AddrRangeList snoops;
36610579SAndrew.Bardsley@arm.com    int x;
36710037SARM gem5 Developers    AddrRangeIter iter;
36810579SAndrew.Bardsley@arm.com
36910037SARM gem5 Developers    assert(status == Port::RangeChange &&
37010579SAndrew.Bardsley@arm.com           "The other statuses need to be implemented.");
37110037SARM gem5 Developers
37210579SAndrew.Bardsley@arm.com    DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
37310579SAndrew.Bardsley@arm.com
37410579SAndrew.Bardsley@arm.com    if (id == defaultId) {
37510579SAndrew.Bardsley@arm.com        defaultRange.clear();
37610579SAndrew.Bardsley@arm.com        defaultPort->getPeerAddressRanges(ranges, snoops);
37710579SAndrew.Bardsley@arm.com        assert(snoops.size() == 0);
37810579SAndrew.Bardsley@arm.com        for(iter = ranges.begin(); iter != ranges.end(); iter++) {
37910579SAndrew.Bardsley@arm.com            defaultRange.push_back(*iter);
3809258SAli.Saidi@ARM.com            DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
3819258SAli.Saidi@ARM.com                    iter->start, iter->end);
3829258SAli.Saidi@ARM.com        }
3839258SAli.Saidi@ARM.com    } else {
3849258SAli.Saidi@ARM.com
3859258SAli.Saidi@ARM.com        assert((id < interfaces.size() && id >= 0) || id == -1);
3869258SAli.Saidi@ARM.com        Port *port = interfaces[id];
3879258SAli.Saidi@ARM.com        std::vector<DevMap>::iterator portIter;
3889258SAli.Saidi@ARM.com        std::vector<DevMap>::iterator snoopIter;
3899535Smrinmoy.ghosh@arm.com
3909258SAli.Saidi@ARM.com        // Clean out any previously existent ids
3919258SAli.Saidi@ARM.com        for (portIter = portList.begin(); portIter != portList.end(); ) {
39210621SCurtis.Dunham@arm.com            if (portIter->portId == id)
3939258SAli.Saidi@ARM.com                portIter = portList.erase(portIter);
39410037SARM gem5 Developers            else
39510037SARM gem5 Developers                portIter++;
3969258SAli.Saidi@ARM.com        }
3979535Smrinmoy.ghosh@arm.com
3989535Smrinmoy.ghosh@arm.com        for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) {
39910474Sandreas.hansson@arm.com            if (snoopIter->portId == id)
40010474Sandreas.hansson@arm.com                snoopIter = portSnoopList.erase(snoopIter);
40110474Sandreas.hansson@arm.com            else
4029535Smrinmoy.ghosh@arm.com                snoopIter++;
4039535Smrinmoy.ghosh@arm.com        }
40410621SCurtis.Dunham@arm.com
40510037SARM gem5 Developers        port->getPeerAddressRanges(ranges, snoops);
40610037SARM gem5 Developers
40710037SARM gem5 Developers        for(iter = snoops.begin(); iter != snoops.end(); iter++) {
4089535Smrinmoy.ghosh@arm.com            DevMap dm;
4099258SAli.Saidi@ARM.com            dm.portId = id;
4109258SAli.Saidi@ARM.com            dm.range = *iter;
4119258SAli.Saidi@ARM.com
4129258SAli.Saidi@ARM.com            DPRINTF(BusAddrRanges, "Adding snoop range %#llx - %#llx for id %d\n",
4139258SAli.Saidi@ARM.com                    dm.range.start, dm.range.end, id);
4149535Smrinmoy.ghosh@arm.com            portSnoopList.push_back(dm);
4159258SAli.Saidi@ARM.com        }
41610037SARM gem5 Developers
41710037SARM gem5 Developers        for(iter = ranges.begin(); iter != ranges.end(); iter++) {
41810037SARM gem5 Developers            DevMap dm;
4199535Smrinmoy.ghosh@arm.com            dm.portId = id;
4209535Smrinmoy.ghosh@arm.com            dm.range = *iter;
4219258SAli.Saidi@ARM.com
4229535Smrinmoy.ghosh@arm.com            DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
4239258SAli.Saidi@ARM.com                    dm.range.start, dm.range.end, id);
42410621SCurtis.Dunham@arm.com            portList.push_back(dm);
4259258SAli.Saidi@ARM.com        }
42610621SCurtis.Dunham@arm.com    }
4279258SAli.Saidi@ARM.com    DPRINTF(MMU, "port list has %d entries\n", portList.size());
4289258SAli.Saidi@ARM.com
4297728SAli.Saidi@ARM.com    // tell all our peers that our address range has changed.
4307728SAli.Saidi@ARM.com    // Don't tell the device that caused this change, it already knows
4317728SAli.Saidi@ARM.com    for (x = 0; x < interfaces.size(); x++)
4327728SAli.Saidi@ARM.com        if (x != id)
4337728SAli.Saidi@ARM.com            interfaces[x]->sendStatusChange(Port::RangeChange);
4347404SAli.Saidi@ARM.com
4357404SAli.Saidi@ARM.com    if (id != defaultId && defaultPort)
4367404SAli.Saidi@ARM.com        defaultPort->sendStatusChange(Port::RangeChange);
43710037SARM gem5 Developers}
4387404SAli.Saidi@ARM.com
43910037SARM gem5 Developersvoid
44010037SARM gem5 DevelopersBus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
44110037SARM gem5 Developers{
4427406SAli.Saidi@ARM.com    std::vector<DevMap>::iterator portIter;
44310621SCurtis.Dunham@arm.com    AddrRangeIter dflt_iter;
44410621SCurtis.Dunham@arm.com    bool subset;
44510037SARM gem5 Developers
44610037SARM gem5 Developers    resp.clear();
4477406SAli.Saidi@ARM.com    snoop.clear();
44810037SARM gem5 Developers
44910037SARM gem5 Developers    DPRINTF(BusAddrRanges, "received address range request, returning:\n");
45010037SARM gem5 Developers
45110474Sandreas.hansson@arm.com    for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
45210474Sandreas.hansson@arm.com            dflt_iter++) {
45310474Sandreas.hansson@arm.com        resp.push_back(*dflt_iter);
45410474Sandreas.hansson@arm.com        DPRINTF(BusAddrRanges, "  -- %#llx : %#llx\n",dflt_iter->start,
45510474Sandreas.hansson@arm.com                dflt_iter->end);
45610037SARM gem5 Developers    }
45710474Sandreas.hansson@arm.com    for (portIter = portList.begin(); portIter != portList.end(); portIter++) {
45810474Sandreas.hansson@arm.com        subset = false;
45910474Sandreas.hansson@arm.com        for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
46010474Sandreas.hansson@arm.com                dflt_iter++) {
46110474Sandreas.hansson@arm.com            if ((portIter->range.start < dflt_iter->start &&
46210037SARM gem5 Developers                portIter->range.end >= dflt_iter->start) ||
46310037SARM gem5 Developers               (portIter->range.start < dflt_iter->end &&
46410037SARM gem5 Developers                portIter->range.end >= dflt_iter->end))
4657404SAli.Saidi@ARM.com                fatal("Devices can not set ranges that itersect the default set\
4667406SAli.Saidi@ARM.com                        but are not a subset of the default set.\n");
46710037SARM gem5 Developers            if (portIter->range.start >= dflt_iter->start &&
46810037SARM gem5 Developers                portIter->range.end <= dflt_iter->end) {
46910037SARM gem5 Developers                subset = true;
47010474Sandreas.hansson@arm.com                DPRINTF(BusAddrRanges, "  -- %#llx : %#llx is a SUBSET\n",
47110474Sandreas.hansson@arm.com                    portIter->range.start, portIter->range.end);
47210474Sandreas.hansson@arm.com            }
47310474Sandreas.hansson@arm.com        }
47410474Sandreas.hansson@arm.com        if (portIter->portId != id && !subset) {
47510037SARM gem5 Developers            resp.push_back(portIter->range);
47610474Sandreas.hansson@arm.com            DPRINTF(BusAddrRanges, "  -- %#llx : %#llx\n",
47710474Sandreas.hansson@arm.com                    portIter->range.start, portIter->range.end);
47810474Sandreas.hansson@arm.com        }
47910474Sandreas.hansson@arm.com    }
48010474Sandreas.hansson@arm.com}
48110037SARM gem5 Developers
48210037SARM gem5 DevelopersBEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
48310037SARM gem5 Developers
48410037SARM gem5 Developers    Param<int> bus_id;
4857404SAli.Saidi@ARM.com    Param<int> clock;
4867404SAli.Saidi@ARM.com    Param<int> width;
48710037SARM gem5 Developers
48810037SARM gem5 DevelopersEND_DECLARE_SIM_OBJECT_PARAMS(Bus)
48910037SARM gem5 Developers
49010037SARM gem5 DevelopersBEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
4917404SAli.Saidi@ARM.com    INIT_PARAM(bus_id, "a globally unique bus id"),
4927404SAli.Saidi@ARM.com    INIT_PARAM(clock, "bus clock speed"),
4937439Sdam.sunwoo@arm.com    INIT_PARAM(width, "width of the bus (bits)")
49410037SARM gem5 DevelopersEND_INIT_SIM_OBJECT_PARAMS(Bus)
49510037SARM gem5 Developers
49610037SARM gem5 DevelopersCREATE_SIM_OBJECT(Bus)
4977439Sdam.sunwoo@arm.com{
49810037SARM gem5 Developers    return new Bus(getInstanceName(), bus_id, clock, width);
4997579Sminkyu.jeong@arm.com}
5007728SAli.Saidi@ARM.com
5017728SAli.Saidi@ARM.comREGISTER_SIM_OBJECT("Bus", Bus)
5027579Sminkyu.jeong@arm.com