xbar.cc revision 3244
15245Sgblack@eecs.umich.edu/*
25245Sgblack@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan
35245Sgblack@eecs.umich.edu * All rights reserved.
45245Sgblack@eecs.umich.edu *
55245Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
65245Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
75245Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
85245Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
95245Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
105245Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
115245Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
125245Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
135245Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
145245Sgblack@eecs.umich.edu * this software without specific prior written permission.
155245Sgblack@eecs.umich.edu *
165245Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175245Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185245Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195245Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205245Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215245Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225245Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235245Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245245Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255245Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265245Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275245Sgblack@eecs.umich.edu *
285245Sgblack@eecs.umich.edu * Authors: Ali Saidi
295245Sgblack@eecs.umich.edu */
305245Sgblack@eecs.umich.edu
315245Sgblack@eecs.umich.edu/**
325245Sgblack@eecs.umich.edu * @file
335245Sgblack@eecs.umich.edu * Definition of a bus object.
345245Sgblack@eecs.umich.edu */
355245Sgblack@eecs.umich.edu
365245Sgblack@eecs.umich.edu
375245Sgblack@eecs.umich.edu#include "base/misc.hh"
385245Sgblack@eecs.umich.edu#include "base/trace.hh"
395245Sgblack@eecs.umich.edu#include "mem/bus.hh"
405245Sgblack@eecs.umich.edu#include "sim/builder.hh"
415245Sgblack@eecs.umich.edu
425245Sgblack@eecs.umich.eduPort *
435245Sgblack@eecs.umich.eduBus::getPort(const std::string &if_name, int idx)
445245Sgblack@eecs.umich.edu{
455245Sgblack@eecs.umich.edu    if (if_name == "default")
465245Sgblack@eecs.umich.edu        if (defaultPort == NULL) {
475245Sgblack@eecs.umich.edu            defaultPort = new BusPort(csprintf("%s-default",name()), this,
485245Sgblack@eecs.umich.edu                    defaultId);
495245Sgblack@eecs.umich.edu            return defaultPort;
505245Sgblack@eecs.umich.edu        } else
515245Sgblack@eecs.umich.edu            fatal("Default port already set\n");
525245Sgblack@eecs.umich.edu
535245Sgblack@eecs.umich.edu    // if_name ignored?  forced to be empty?
545245Sgblack@eecs.umich.edu    int id = interfaces.size();
555245Sgblack@eecs.umich.edu    BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
565245Sgblack@eecs.umich.edu    interfaces.push_back(bp);
575245Sgblack@eecs.umich.edu    return bp;
585245Sgblack@eecs.umich.edu}
595245Sgblack@eecs.umich.edu
605245Sgblack@eecs.umich.edu/** Get the ranges of anyone other buses that we are connected to. */
615245Sgblack@eecs.umich.eduvoid
625245Sgblack@eecs.umich.eduBus::init()
635245Sgblack@eecs.umich.edu{
645245Sgblack@eecs.umich.edu    std::vector<BusPort*>::iterator intIter;
655245Sgblack@eecs.umich.edu
665245Sgblack@eecs.umich.edu    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
675245Sgblack@eecs.umich.edu        (*intIter)->sendStatusChange(Port::RangeChange);
685245Sgblack@eecs.umich.edu}
695245Sgblack@eecs.umich.edu
705245Sgblack@eecs.umich.eduBus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus)
715245Sgblack@eecs.umich.edu{}
725245Sgblack@eecs.umich.edu
735245Sgblack@eecs.umich.eduvoid Bus::BusFreeEvent::process()
745245Sgblack@eecs.umich.edu{
755245Sgblack@eecs.umich.edu    bus->recvRetry(-1);
765245Sgblack@eecs.umich.edu}
775245Sgblack@eecs.umich.edu
785245Sgblack@eecs.umich.educonst char * Bus::BusFreeEvent::description()
795245Sgblack@eecs.umich.edu{
805245Sgblack@eecs.umich.edu    return "bus became available";
815245Sgblack@eecs.umich.edu}
825245Sgblack@eecs.umich.edu
835245Sgblack@eecs.umich.eduvoid Bus::occupyBus(PacketPtr pkt)
845245Sgblack@eecs.umich.edu{
855245Sgblack@eecs.umich.edu    //Bring tickNextIdle up to the present tick
865245Sgblack@eecs.umich.edu    //There is some potential ambiguity where a cycle starts, which might make
875895Sgblack@eecs.umich.edu    //a difference when devices are acting right around a cycle boundary. Using
885897Sgblack@eecs.umich.edu    //a < allows things which happen exactly on a cycle boundary to take up only
895245Sgblack@eecs.umich.edu    //the following cycle. Anthing that happens later will have to "wait" for
905245Sgblack@eecs.umich.edu    //the end of that cycle, and then start using the bus after that.
915245Sgblack@eecs.umich.edu    while (tickNextIdle < curTick)
925245Sgblack@eecs.umich.edu        tickNextIdle += clock;
935245Sgblack@eecs.umich.edu
945245Sgblack@eecs.umich.edu    // The packet will be sent. Figure out how long it occupies the bus, and
955245Sgblack@eecs.umich.edu    // how much of that time is for the first "word", aka bus width.
965245Sgblack@eecs.umich.edu    int numCycles = 0;
975245Sgblack@eecs.umich.edu    // Requests need one cycle to send an address
985245Sgblack@eecs.umich.edu    if (pkt->isRequest())
995245Sgblack@eecs.umich.edu        numCycles++;
1005245Sgblack@eecs.umich.edu    else if (pkt->isResponse() || pkt->hasData()) {
1016027Sgblack@eecs.umich.edu        // If a packet has data, it needs ceil(size/width) cycles to send it
1025245Sgblack@eecs.umich.edu        // We're using the "adding instead of dividing" trick again here
1035245Sgblack@eecs.umich.edu        if (pkt->hasData()) {
1045904Sgblack@eecs.umich.edu            int dataSize = pkt->getSize();
1055904Sgblack@eecs.umich.edu            for (int transmitted = 0; transmitted < dataSize;
1065245Sgblack@eecs.umich.edu                    transmitted += width) {
1075245Sgblack@eecs.umich.edu                numCycles++;
1085245Sgblack@eecs.umich.edu            }
1095245Sgblack@eecs.umich.edu        } else {
1105245Sgblack@eecs.umich.edu            // If the packet didn't have data, it must have been a response.
1115895Sgblack@eecs.umich.edu            // Those use the bus for one cycle to send their data.
1125895Sgblack@eecs.umich.edu            numCycles++;
1135895Sgblack@eecs.umich.edu        }
1145895Sgblack@eecs.umich.edu    }
1155245Sgblack@eecs.umich.edu
1165245Sgblack@eecs.umich.edu    // The first word will be delivered after the current tick, the delivery
1175245Sgblack@eecs.umich.edu    // of the address if any, and one bus cycle to deliver the data
1185245Sgblack@eecs.umich.edu    pkt->firstWordTime =
1195904Sgblack@eecs.umich.edu        tickNextIdle +
1205904Sgblack@eecs.umich.edu        pkt->isRequest() ? clock : 0 +
1215245Sgblack@eecs.umich.edu        clock;
1225245Sgblack@eecs.umich.edu
1235245Sgblack@eecs.umich.edu    //Advance it numCycles bus cycles.
1245245Sgblack@eecs.umich.edu    //XXX Should this use the repeated addition trick as well?
1255245Sgblack@eecs.umich.edu    tickNextIdle += (numCycles * clock);
1265895Sgblack@eecs.umich.edu    if (!busIdle.scheduled()) {
1275895Sgblack@eecs.umich.edu        busIdle.schedule(tickNextIdle);
1285895Sgblack@eecs.umich.edu    } else {
1295895Sgblack@eecs.umich.edu        busIdle.reschedule(tickNextIdle);
1305245Sgblack@eecs.umich.edu    }
1315245Sgblack@eecs.umich.edu    DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
1325245Sgblack@eecs.umich.edu            curTick, tickNextIdle);
1335904Sgblack@eecs.umich.edu
1345904Sgblack@eecs.umich.edu    // The bus will become idle once the current packet is delivered.
1355245Sgblack@eecs.umich.edu    pkt->finishTime = tickNextIdle;
1365245Sgblack@eecs.umich.edu}
1375245Sgblack@eecs.umich.edu
1385245Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a Timing
1395895Sgblack@eecs.umich.edu * transaction.*/
1405895Sgblack@eecs.umich.edubool
1415895Sgblack@eecs.umich.eduBus::recvTiming(Packet *pkt)
1425895Sgblack@eecs.umich.edu{
1435245Sgblack@eecs.umich.edu    Port *port;
1445245Sgblack@eecs.umich.edu    DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
1455245Sgblack@eecs.umich.edu            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
1465245Sgblack@eecs.umich.edu
1475245Sgblack@eecs.umich.edu    BusPort *pktPort = interfaces[pkt->getSrc()];
1485245Sgblack@eecs.umich.edu
1495245Sgblack@eecs.umich.edu    // If the bus is busy, or other devices are in line ahead of the current
1505245Sgblack@eecs.umich.edu    // one, put this device on the retry list.
1515245Sgblack@eecs.umich.edu    if (tickNextIdle > curTick ||
1525245Sgblack@eecs.umich.edu            (retryList.size() && (!inRetry || pktPort != retryList.front()))) {
1535245Sgblack@eecs.umich.edu        addToRetryList(pktPort);
1545245Sgblack@eecs.umich.edu        return false;
1555245Sgblack@eecs.umich.edu    }
1565245Sgblack@eecs.umich.edu
1575245Sgblack@eecs.umich.edu    short dest = pkt->getDest();
1585245Sgblack@eecs.umich.edu    if (dest == Packet::Broadcast) {
1595895Sgblack@eecs.umich.edu        if (timingSnoop(pkt)) {
1605895Sgblack@eecs.umich.edu            pkt->flags |= SNOOP_COMMIT;
1615245Sgblack@eecs.umich.edu            bool success = timingSnoop(pkt);
1625245Sgblack@eecs.umich.edu            assert(success);
1635904Sgblack@eecs.umich.edu            if (pkt->flags & SATISFIED) {
1645904Sgblack@eecs.umich.edu                //Cache-Cache transfer occuring
1655245Sgblack@eecs.umich.edu                if (inRetry) {
1665245Sgblack@eecs.umich.edu                    retryList.front()->onRetryList(false);
1675245Sgblack@eecs.umich.edu                    retryList.pop_front();
1685245Sgblack@eecs.umich.edu                    inRetry = false;
1695895Sgblack@eecs.umich.edu                }
1705895Sgblack@eecs.umich.edu                occupyBus(pkt);
1715895Sgblack@eecs.umich.edu                return true;
1725895Sgblack@eecs.umich.edu            }
1735245Sgblack@eecs.umich.edu            port = findPort(pkt->getAddr(), pkt->getSrc());
1745245Sgblack@eecs.umich.edu        } else {
1755245Sgblack@eecs.umich.edu            //Snoop didn't succeed
1765245Sgblack@eecs.umich.edu            addToRetryList(pktPort);
1775245Sgblack@eecs.umich.edu            return false;
1785245Sgblack@eecs.umich.edu        }
1795895Sgblack@eecs.umich.edu    } else {
1805895Sgblack@eecs.umich.edu        assert(dest >= 0 && dest < interfaces.size());
1815245Sgblack@eecs.umich.edu        assert(dest != pkt->getSrc()); // catch infinite loops
1825904Sgblack@eecs.umich.edu        port = interfaces[dest];
1835904Sgblack@eecs.umich.edu    }
1845245Sgblack@eecs.umich.edu
1855895Sgblack@eecs.umich.edu    occupyBus(pkt);
1865895Sgblack@eecs.umich.edu
1875895Sgblack@eecs.umich.edu    if (port->sendTiming(pkt))  {
1885895Sgblack@eecs.umich.edu        // Packet was successfully sent. Return true.
1895245Sgblack@eecs.umich.edu        // Also take care of retries
1905245Sgblack@eecs.umich.edu        if (inRetry) {
1915245Sgblack@eecs.umich.edu            retryList.front()->onRetryList(false);
1925904Sgblack@eecs.umich.edu            retryList.pop_front();
1935904Sgblack@eecs.umich.edu            inRetry = false;
1945245Sgblack@eecs.umich.edu        }
1955245Sgblack@eecs.umich.edu        return true;
1965245Sgblack@eecs.umich.edu    }
1975245Sgblack@eecs.umich.edu
1985895Sgblack@eecs.umich.edu    // Packet not successfully sent. Leave or put it on the retry list.
1995895Sgblack@eecs.umich.edu    addToRetryList(pktPort);
2005895Sgblack@eecs.umich.edu    return false;
2015895Sgblack@eecs.umich.edu}
2025245Sgblack@eecs.umich.edu
2035245Sgblack@eecs.umich.eduvoid
2045245Sgblack@eecs.umich.eduBus::recvRetry(int id)
2055245Sgblack@eecs.umich.edu{
2065245Sgblack@eecs.umich.edu    // If there's anything waiting...
2075245Sgblack@eecs.umich.edu    if (retryList.size()) {
2085245Sgblack@eecs.umich.edu        //retryingPort = retryList.front();
2095245Sgblack@eecs.umich.edu        inRetry = true;
2105245Sgblack@eecs.umich.edu        retryList.front()->sendRetry();
2115245Sgblack@eecs.umich.edu        // If inRetry is still true, sendTiming wasn't called
2125245Sgblack@eecs.umich.edu        if (inRetry)
2135245Sgblack@eecs.umich.edu            panic("Port %s didn't call sendTiming in it's recvRetry\n",\
2145245Sgblack@eecs.umich.edu                    retryList.front()->getPeer()->name());
2155245Sgblack@eecs.umich.edu        //assert(!inRetry);
2165245Sgblack@eecs.umich.edu    }
2175895Sgblack@eecs.umich.edu}
2185895Sgblack@eecs.umich.edu
2195245Sgblack@eecs.umich.eduPort *
2205245Sgblack@eecs.umich.eduBus::findPort(Addr addr, int id)
2215904Sgblack@eecs.umich.edu{
2225904Sgblack@eecs.umich.edu    /* An interval tree would be a better way to do this. --ali. */
2235245Sgblack@eecs.umich.edu    int dest_id = -1;
2245245Sgblack@eecs.umich.edu    int i = 0;
2255245Sgblack@eecs.umich.edu    bool found = false;
2265245Sgblack@eecs.umich.edu    AddrRangeIter iter;
2275895Sgblack@eecs.umich.edu
2285895Sgblack@eecs.umich.edu    while (i < portList.size() && !found)
2295895Sgblack@eecs.umich.edu    {
2305895Sgblack@eecs.umich.edu        if (portList[i].range == addr) {
2315245Sgblack@eecs.umich.edu            dest_id = portList[i].portId;
2325245Sgblack@eecs.umich.edu            found = true;
2335245Sgblack@eecs.umich.edu            DPRINTF(Bus, "  found addr %#llx on device %d\n", addr, dest_id);
2345245Sgblack@eecs.umich.edu        }
2355245Sgblack@eecs.umich.edu        i++;
2365245Sgblack@eecs.umich.edu    }
2375895Sgblack@eecs.umich.edu
2385895Sgblack@eecs.umich.edu    // Check if this matches the default range
2395245Sgblack@eecs.umich.edu    if (dest_id == -1) {
2405904Sgblack@eecs.umich.edu        for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) {
2415904Sgblack@eecs.umich.edu            if (*iter == addr) {
2425245Sgblack@eecs.umich.edu                DPRINTF(Bus, "  found addr %#llx on default\n", addr);
2435245Sgblack@eecs.umich.edu                return defaultPort;
2445245Sgblack@eecs.umich.edu            }
2455245Sgblack@eecs.umich.edu        }
2465895Sgblack@eecs.umich.edu        panic("Unable to find destination for addr: %#llx", addr);
2475895Sgblack@eecs.umich.edu    }
2485895Sgblack@eecs.umich.edu
2495895Sgblack@eecs.umich.edu
2505245Sgblack@eecs.umich.edu    // we shouldn't be sending this back to where it came from
2515245Sgblack@eecs.umich.edu    assert(dest_id != id);
2525245Sgblack@eecs.umich.edu
2535245Sgblack@eecs.umich.edu    return interfaces[dest_id];
2545245Sgblack@eecs.umich.edu}
2555245Sgblack@eecs.umich.edu
2565245Sgblack@eecs.umich.edustd::vector<int>
2575245Sgblack@eecs.umich.eduBus::findSnoopPorts(Addr addr, int id)
2585245Sgblack@eecs.umich.edu{
2595245Sgblack@eecs.umich.edu    int i = 0;
2605245Sgblack@eecs.umich.edu    AddrRangeIter iter;
2615245Sgblack@eecs.umich.edu    std::vector<int> ports;
2625245Sgblack@eecs.umich.edu
2635245Sgblack@eecs.umich.edu    while (i < portSnoopList.size())
2645245Sgblack@eecs.umich.edu    {
2655245Sgblack@eecs.umich.edu        if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) {
2665895Sgblack@eecs.umich.edu            //Careful  to not overlap ranges
2675895Sgblack@eecs.umich.edu            //or snoop will be called more than once on the port
2685245Sgblack@eecs.umich.edu            ports.push_back(portSnoopList[i].portId);
2695245Sgblack@eecs.umich.edu            DPRINTF(Bus, "  found snoop addr %#llx on device%d\n", addr,
2705904Sgblack@eecs.umich.edu                    portSnoopList[i].portId);
2715904Sgblack@eecs.umich.edu        }
2725245Sgblack@eecs.umich.edu        i++;
2735245Sgblack@eecs.umich.edu    }
2745245Sgblack@eecs.umich.edu    return ports;
2755245Sgblack@eecs.umich.edu}
2765895Sgblack@eecs.umich.edu
2775895Sgblack@eecs.umich.eduvoid
2785895Sgblack@eecs.umich.eduBus::atomicSnoop(Packet *pkt)
2795895Sgblack@eecs.umich.edu{
2805245Sgblack@eecs.umich.edu    std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
2815245Sgblack@eecs.umich.edu
2825245Sgblack@eecs.umich.edu    while (!ports.empty())
2835245Sgblack@eecs.umich.edu    {
2845245Sgblack@eecs.umich.edu        interfaces[ports.back()]->sendAtomic(pkt);
2855245Sgblack@eecs.umich.edu        ports.pop_back();
2865904Sgblack@eecs.umich.edu    }
2875904Sgblack@eecs.umich.edu}
2885245Sgblack@eecs.umich.edu
2895245Sgblack@eecs.umich.eduvoid
2905245Sgblack@eecs.umich.eduBus::functionalSnoop(Packet *pkt)
2915245Sgblack@eecs.umich.edu{
2925895Sgblack@eecs.umich.edu    std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
2935895Sgblack@eecs.umich.edu
2945895Sgblack@eecs.umich.edu    while (!ports.empty())
2955895Sgblack@eecs.umich.edu    {
2965245Sgblack@eecs.umich.edu        interfaces[ports.back()]->sendFunctional(pkt);
2975245Sgblack@eecs.umich.edu        ports.pop_back();
2985245Sgblack@eecs.umich.edu    }
2995245Sgblack@eecs.umich.edu}
3005245Sgblack@eecs.umich.edu
3015245Sgblack@eecs.umich.edubool
3025895Sgblack@eecs.umich.eduBus::timingSnoop(Packet *pkt)
3035895Sgblack@eecs.umich.edu{
3045245Sgblack@eecs.umich.edu    std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
3055245Sgblack@eecs.umich.edu    bool success = true;
3065245Sgblack@eecs.umich.edu
3075245Sgblack@eecs.umich.edu    while (!ports.empty() && success)
3085245Sgblack@eecs.umich.edu    {
3095736Snate@binkert.org        success = interfaces[ports.back()]->sendTiming(pkt);
3105736Snate@binkert.org        ports.pop_back();
3115245Sgblack@eecs.umich.edu    }
3125245Sgblack@eecs.umich.edu
3135245Sgblack@eecs.umich.edu    return success;
3145245Sgblack@eecs.umich.edu}
3155245Sgblack@eecs.umich.edu
3165245Sgblack@eecs.umich.edu
3175245Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a Atomic
3185245Sgblack@eecs.umich.edu * transaction.*/
3195245Sgblack@eecs.umich.eduTick
3205245Sgblack@eecs.umich.eduBus::recvAtomic(Packet *pkt)
3215245Sgblack@eecs.umich.edu{
3225245Sgblack@eecs.umich.edu    DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
3235245Sgblack@eecs.umich.edu            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
3245245Sgblack@eecs.umich.edu    assert(pkt->getDest() == Packet::Broadcast);
3255245Sgblack@eecs.umich.edu    atomicSnoop(pkt);
3265245Sgblack@eecs.umich.edu    return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt);
3275895Sgblack@eecs.umich.edu}
3285245Sgblack@eecs.umich.edu
3295245Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a Functional
3305895Sgblack@eecs.umich.edu * transaction.*/
3315895Sgblack@eecs.umich.eduvoid
3326023Snate@binkert.orgBus::recvFunctional(Packet *pkt)
3335245Sgblack@eecs.umich.edu{
3345245Sgblack@eecs.umich.edu    DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
3355245Sgblack@eecs.umich.edu            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
3365895Sgblack@eecs.umich.edu    assert(pkt->getDest() == Packet::Broadcast);
3375895Sgblack@eecs.umich.edu    functionalSnoop(pkt);
3386023Snate@binkert.org    findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt);
3395895Sgblack@eecs.umich.edu}
3405245Sgblack@eecs.umich.edu
3415245Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a status change.*/
3425245Sgblack@eecs.umich.eduvoid
3435245Sgblack@eecs.umich.eduBus::recvStatusChange(Port::Status status, int id)
3445245Sgblack@eecs.umich.edu{
3455245Sgblack@eecs.umich.edu    AddrRangeList ranges;
3465245Sgblack@eecs.umich.edu    AddrRangeList snoops;
3475245Sgblack@eecs.umich.edu    int x;
3485245Sgblack@eecs.umich.edu    AddrRangeIter iter;
3495245Sgblack@eecs.umich.edu
3505245Sgblack@eecs.umich.edu    assert(status == Port::RangeChange &&
3515245Sgblack@eecs.umich.edu           "The other statuses need to be implemented.");
3525245Sgblack@eecs.umich.edu
3535895Sgblack@eecs.umich.edu    DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
3545245Sgblack@eecs.umich.edu
3555245Sgblack@eecs.umich.edu    if (id == defaultId) {
3565245Sgblack@eecs.umich.edu        defaultRange.clear();
3575245Sgblack@eecs.umich.edu        defaultPort->getPeerAddressRanges(ranges, snoops);
3585245Sgblack@eecs.umich.edu        assert(snoops.size() == 0);
3595245Sgblack@eecs.umich.edu        for(iter = ranges.begin(); iter != ranges.end(); iter++) {
3605245Sgblack@eecs.umich.edu            defaultRange.push_back(*iter);
3615895Sgblack@eecs.umich.edu            DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
3625245Sgblack@eecs.umich.edu                    iter->start, iter->end);
3635245Sgblack@eecs.umich.edu        }
3645245Sgblack@eecs.umich.edu    } else {
3655245Sgblack@eecs.umich.edu
3665245Sgblack@eecs.umich.edu        assert((id < interfaces.size() && id >= 0) || id == -1);
3675245Sgblack@eecs.umich.edu        Port *port = interfaces[id];
3685245Sgblack@eecs.umich.edu        std::vector<DevMap>::iterator portIter;
3695245Sgblack@eecs.umich.edu        std::vector<DevMap>::iterator snoopIter;
3705245Sgblack@eecs.umich.edu
3715245Sgblack@eecs.umich.edu        // Clean out any previously existent ids
3725895Sgblack@eecs.umich.edu        for (portIter = portList.begin(); portIter != portList.end(); ) {
3735245Sgblack@eecs.umich.edu            if (portIter->portId == id)
3745245Sgblack@eecs.umich.edu                portIter = portList.erase(portIter);
3755245Sgblack@eecs.umich.edu            else
3765245Sgblack@eecs.umich.edu                portIter++;
3775245Sgblack@eecs.umich.edu        }
3785245Sgblack@eecs.umich.edu
3795736Snate@binkert.org        for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) {
3805736Snate@binkert.org            if (snoopIter->portId == id)
3815736Snate@binkert.org                snoopIter = portSnoopList.erase(snoopIter);
3825736Snate@binkert.org            else
3835245Sgblack@eecs.umich.edu                snoopIter++;
3845245Sgblack@eecs.umich.edu        }
3855245Sgblack@eecs.umich.edu
3865245Sgblack@eecs.umich.edu        port->getPeerAddressRanges(ranges, snoops);
3875897Sgblack@eecs.umich.edu
3885897Sgblack@eecs.umich.edu        for(iter = snoops.begin(); iter != snoops.end(); iter++) {
3895895Sgblack@eecs.umich.edu            DevMap dm;
3905897Sgblack@eecs.umich.edu            dm.portId = id;
3915245Sgblack@eecs.umich.edu            dm.range = *iter;
3925895Sgblack@eecs.umich.edu
3935245Sgblack@eecs.umich.edu            DPRINTF(BusAddrRanges, "Adding snoop range %#llx - %#llx for id %d\n",
3945245Sgblack@eecs.umich.edu                    dm.range.start, dm.range.end, id);
3955245Sgblack@eecs.umich.edu            portSnoopList.push_back(dm);
3965897Sgblack@eecs.umich.edu        }
3975895Sgblack@eecs.umich.edu
3985245Sgblack@eecs.umich.edu        for(iter = ranges.begin(); iter != ranges.end(); iter++) {
3995245Sgblack@eecs.umich.edu            DevMap dm;
4005245Sgblack@eecs.umich.edu            dm.portId = id;
4015245Sgblack@eecs.umich.edu            dm.range = *iter;
4025245Sgblack@eecs.umich.edu
4035245Sgblack@eecs.umich.edu            DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
4045245Sgblack@eecs.umich.edu                    dm.range.start, dm.range.end, id);
4055895Sgblack@eecs.umich.edu            portList.push_back(dm);
4065245Sgblack@eecs.umich.edu        }
4075245Sgblack@eecs.umich.edu    }
4085245Sgblack@eecs.umich.edu    DPRINTF(MMU, "port list has %d entries\n", portList.size());
4095895Sgblack@eecs.umich.edu
4105245Sgblack@eecs.umich.edu    // tell all our peers that our address range has changed.
4115245Sgblack@eecs.umich.edu    // Don't tell the device that caused this change, it already knows
4125245Sgblack@eecs.umich.edu    for (x = 0; x < interfaces.size(); x++)
4135245Sgblack@eecs.umich.edu        if (x != id)
4145245Sgblack@eecs.umich.edu            interfaces[x]->sendStatusChange(Port::RangeChange);
4155245Sgblack@eecs.umich.edu
4165245Sgblack@eecs.umich.edu    if (id != defaultId && defaultPort)
4175245Sgblack@eecs.umich.edu        defaultPort->sendStatusChange(Port::RangeChange);
4185245Sgblack@eecs.umich.edu}
4195245Sgblack@eecs.umich.edu
4205245Sgblack@eecs.umich.eduvoid
4215245Sgblack@eecs.umich.eduBus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
4225897Sgblack@eecs.umich.edu{
4235897Sgblack@eecs.umich.edu    std::vector<DevMap>::iterator portIter;
4245897Sgblack@eecs.umich.edu    AddrRangeIter dflt_iter;
4255897Sgblack@eecs.umich.edu    bool subset;
4265245Sgblack@eecs.umich.edu
4275245Sgblack@eecs.umich.edu    resp.clear();
4285245Sgblack@eecs.umich.edu    snoop.clear();
4295245Sgblack@eecs.umich.edu
4305897Sgblack@eecs.umich.edu    DPRINTF(BusAddrRanges, "received address range request, returning:\n");
4315897Sgblack@eecs.umich.edu
4325245Sgblack@eecs.umich.edu    for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
4335895Sgblack@eecs.umich.edu            dflt_iter++) {
4345245Sgblack@eecs.umich.edu        resp.push_back(*dflt_iter);
4355245Sgblack@eecs.umich.edu        DPRINTF(BusAddrRanges, "  -- %#llx : %#llx\n",dflt_iter->start,
4365245Sgblack@eecs.umich.edu                dflt_iter->end);
4375245Sgblack@eecs.umich.edu    }
4385245Sgblack@eecs.umich.edu    for (portIter = portList.begin(); portIter != portList.end(); portIter++) {
4395245Sgblack@eecs.umich.edu        subset = false;
4405245Sgblack@eecs.umich.edu        for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
4415245Sgblack@eecs.umich.edu                dflt_iter++) {
4425245Sgblack@eecs.umich.edu            if ((portIter->range.start < dflt_iter->start &&
4435245Sgblack@eecs.umich.edu                portIter->range.end >= dflt_iter->start) ||
4445895Sgblack@eecs.umich.edu               (portIter->range.start < dflt_iter->end &&
4455895Sgblack@eecs.umich.edu                portIter->range.end >= dflt_iter->end))
4465895Sgblack@eecs.umich.edu                fatal("Devices can not set ranges that itersect the default set\
4475895Sgblack@eecs.umich.edu                        but are not a subset of the default set.\n");
4485895Sgblack@eecs.umich.edu            if (portIter->range.start >= dflt_iter->start &&
4495895Sgblack@eecs.umich.edu                portIter->range.end <= dflt_iter->end) {
4505895Sgblack@eecs.umich.edu                subset = true;
4515895Sgblack@eecs.umich.edu                DPRINTF(BusAddrRanges, "  -- %#llx : %#llx is a SUBSET\n",
4525895Sgblack@eecs.umich.edu                    portIter->range.start, portIter->range.end);
4536023Snate@binkert.org            }
4545895Sgblack@eecs.umich.edu        }
4555895Sgblack@eecs.umich.edu        if (portIter->portId != id && !subset) {
4565895Sgblack@eecs.umich.edu            resp.push_back(portIter->range);
4576023Snate@binkert.org            DPRINTF(BusAddrRanges, "  -- %#llx : %#llx\n",
4585895Sgblack@eecs.umich.edu                    portIter->range.start, portIter->range.end);
4595895Sgblack@eecs.umich.edu        }
4606023Snate@binkert.org    }
4615895Sgblack@eecs.umich.edu}
4625245Sgblack@eecs.umich.edu
4635245Sgblack@eecs.umich.eduBEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
4645245Sgblack@eecs.umich.edu
4655245Sgblack@eecs.umich.edu    Param<int> bus_id;
4665897Sgblack@eecs.umich.edu    Param<int> clock;
4675245Sgblack@eecs.umich.edu    Param<int> width;
4685245Sgblack@eecs.umich.edu
4695245Sgblack@eecs.umich.eduEND_DECLARE_SIM_OBJECT_PARAMS(Bus)
4705245Sgblack@eecs.umich.edu
4715245Sgblack@eecs.umich.eduBEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
4725245Sgblack@eecs.umich.edu    INIT_PARAM(bus_id, "a globally unique bus id"),
4735245Sgblack@eecs.umich.edu    INIT_PARAM(clock, "bus clock speed"),
4745245Sgblack@eecs.umich.edu    INIT_PARAM(width, "width of the bus (bits)")
4755245Sgblack@eecs.umich.eduEND_INIT_SIM_OBJECT_PARAMS(Bus)
4765245Sgblack@eecs.umich.edu
4775245Sgblack@eecs.umich.eduCREATE_SIM_OBJECT(Bus)
4785245Sgblack@eecs.umich.edu{
4795245Sgblack@eecs.umich.edu    return new Bus(getInstanceName(), bus_id, clock, width);
4805245Sgblack@eecs.umich.edu}
4815245Sgblack@eecs.umich.edu
4825245Sgblack@eecs.umich.eduREGISTER_SIM_OBJECT("Bus", Bus)
4835245Sgblack@eecs.umich.edu