coherent_xbar.cc revision 8711
12568SN/A/*
22568SN/A * Copyright (c) 2011 ARM Limited
32568SN/A * All rights reserved
42568SN/A *
52568SN/A * The license below extends only to copyright in the software and shall
62568SN/A * not be construed as granting a license to any other intellectual
72568SN/A * property including but not limited to intellectual property relating
82568SN/A * to a hardware implementation of the functionality of the software
92568SN/A * licensed hereunder.  You may use the software subject to the license
102568SN/A * terms below provided that you ensure that this notice is replicated
112568SN/A * unmodified and in its entirety in all distributions of the software,
122568SN/A * modified or unmodified, in source code or in binary form.
132568SN/A *
142568SN/A * Copyright (c) 2006 The Regents of The University of Michigan
152568SN/A * All rights reserved.
162568SN/A *
172568SN/A * Redistribution and use in source and binary forms, with or without
182568SN/A * modification, are permitted provided that the following conditions are
192568SN/A * met: redistributions of source code must retain the above copyright
202568SN/A * notice, this list of conditions and the following disclaimer;
212568SN/A * redistributions in binary form must reproduce the above copyright
222568SN/A * notice, this list of conditions and the following disclaimer in the
232568SN/A * documentation and/or other materials provided with the distribution;
242568SN/A * neither the name of the copyright holders nor the names of its
252568SN/A * contributors may be used to endorse or promote products derived from
262568SN/A * this software without specific prior written permission.
272568SN/A *
282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312568SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322568SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332568SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342982Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352982Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362568SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372568SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382643Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392568SN/A *
404965Ssaidi@eecs.umich.edu * Authors: Ali Saidi
412568SN/A */
422568SN/A
434762Snate@binkert.org/**
442568SN/A * @file
452643Sstever@eecs.umich.edu * Definition of a bus object.
462643Sstever@eecs.umich.edu */
474435Ssaidi@eecs.umich.edu
484965Ssaidi@eecs.umich.edu#include <algorithm>
494965Ssaidi@eecs.umich.edu#include <limits>
505606Snate@binkert.org
514965Ssaidi@eecs.umich.edu#include "base/misc.hh"
524435Ssaidi@eecs.umich.edu#include "base/trace.hh"
534435Ssaidi@eecs.umich.edu#include "debug/Bus.hh"
542643Sstever@eecs.umich.edu#include "debug/BusAddrRanges.hh"
552643Sstever@eecs.umich.edu#include "debug/MMU.hh"
562643Sstever@eecs.umich.edu#include "mem/bus.hh"
574435Ssaidi@eecs.umich.edu
585034Smilesck@eecs.umich.eduBus::Bus(const BusParams *p)
594435Ssaidi@eecs.umich.edu    : MemObject(p), busId(p->bus_id), clock(p->clock),
604965Ssaidi@eecs.umich.edu      headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
614435Ssaidi@eecs.umich.edu      drainEvent(NULL), busIdle(this), inRetry(false), maxId(0),
624965Ssaidi@eecs.umich.edu      defaultPort(NULL), funcPort(NULL), funcPortId(-4),
634435Ssaidi@eecs.umich.edu      useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size),
642643Sstever@eecs.umich.edu      cachedBlockSize(0), cachedBlockSizeValid(false)
654432Ssaidi@eecs.umich.edu{
664432Ssaidi@eecs.umich.edu    //width, clock period, and header cycles must be positive
672643Sstever@eecs.umich.edu    if (width <= 0)
682643Sstever@eecs.umich.edu        fatal("Bus width must be positive\n");
692643Sstever@eecs.umich.edu    if (clock <= 0)
702738Sstever@eecs.umich.edu        fatal("Bus clock period must be positive\n");
712643Sstever@eecs.umich.edu    if (headerCycles <= 0)
722643Sstever@eecs.umich.edu        fatal("Number of header cycles must be positive\n");
732643Sstever@eecs.umich.edu    clearBusCache();
742643Sstever@eecs.umich.edu    clearPortCache();
752643Sstever@eecs.umich.edu}
762643Sstever@eecs.umich.edu
772643Sstever@eecs.umich.eduPort *
782643Sstever@eecs.umich.eduBus::getPort(const std::string &if_name, int idx)
792643Sstever@eecs.umich.edu{
802643Sstever@eecs.umich.edu    if (if_name == "default") {
815283Sgblack@eecs.umich.edu        if (defaultPort == NULL) {
825283Sgblack@eecs.umich.edu            defaultPort = new BusPort(csprintf("%s-default",name()), this,
835283Sgblack@eecs.umich.edu                                      defaultId);
842643Sstever@eecs.umich.edu            cachedBlockSizeValid = false;
852643Sstever@eecs.umich.edu            return defaultPort;
862643Sstever@eecs.umich.edu        } else
872643Sstever@eecs.umich.edu            fatal("Default port already set\n");
882568SN/A    }
892568SN/A    int id;
902568SN/A    if (if_name == "functional") {
912568SN/A        if (!funcPort) {
925476Snate@binkert.org            id = maxId++;
934432Ssaidi@eecs.umich.edu            funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id);
944432Ssaidi@eecs.umich.edu            funcPortId = id;
954432Ssaidi@eecs.umich.edu            interfaces[id] = funcPort;
966764SBrad.Beckmann@amd.com        }
976764SBrad.Beckmann@amd.com        return funcPort;
986764SBrad.Beckmann@amd.com    }
992568SN/A
1002568SN/A    // if_name ignored?  forced to be empty?
1014433Ssaidi@eecs.umich.edu    id = maxId++;
1024435Ssaidi@eecs.umich.edu    assert(maxId < std::numeric_limits<typeof(maxId)>::max());
1034433Ssaidi@eecs.umich.edu    BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
1044435Ssaidi@eecs.umich.edu    interfaces[id] = bp;
1054435Ssaidi@eecs.umich.edu    cachedBlockSizeValid = false;
1064435Ssaidi@eecs.umich.edu    return bp;
1074435Ssaidi@eecs.umich.edu}
1084435Ssaidi@eecs.umich.edu
1094435Ssaidi@eecs.umich.eduvoid
1104435Ssaidi@eecs.umich.eduBus::init()
1114435Ssaidi@eecs.umich.edu{
1124435Ssaidi@eecs.umich.edu    m5::hash_map<short,BusPort*>::iterator intIter;
1134433Ssaidi@eecs.umich.edu
1142568SN/A    // iterate over our interfaces and determine which of our neighbours
1152643Sstever@eecs.umich.edu    // are snooping and add them as snoopers
1162568SN/A    for (intIter = interfaces.begin(); intIter != interfaces.end();
1172568SN/A         intIter++) {
1183349Sbinkertn@umich.edu        if (intIter->second->getPeer()->isSnooping()) {
1192568SN/A            DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
1204433Ssaidi@eecs.umich.edu                    intIter->second->getPeer()->name());
1213662Srdreslin@umich.edu            snoopPorts.push_back(intIter->second);
1222643Sstever@eecs.umich.edu        }
1234450Ssaidi@eecs.umich.edu    }
1244450Ssaidi@eecs.umich.edu}
1254986Ssaidi@eecs.umich.edu
1264450Ssaidi@eecs.umich.eduBus::BusFreeEvent::BusFreeEvent(Bus *_bus)
1274450Ssaidi@eecs.umich.edu    : bus(_bus)
1284450Ssaidi@eecs.umich.edu{}
1294986Ssaidi@eecs.umich.edu
1304433Ssaidi@eecs.umich.eduvoid
1314433Ssaidi@eecs.umich.eduBus::BusFreeEvent::process()
1324433Ssaidi@eecs.umich.edu{
1333662Srdreslin@umich.edu    bus->recvRetry(-1);
1344433Ssaidi@eecs.umich.edu}
1355562Snate@binkert.org
1364435Ssaidi@eecs.umich.educonst char *
1374433Ssaidi@eecs.umich.eduBus::BusFreeEvent::description() const
1384433Ssaidi@eecs.umich.edu{
1394433Ssaidi@eecs.umich.edu    return "bus became available";
1404433Ssaidi@eecs.umich.edu}
1414433Ssaidi@eecs.umich.edu
1424433Ssaidi@eecs.umich.eduTick
1434433Ssaidi@eecs.umich.eduBus::calcPacketTiming(PacketPtr pkt)
1444433Ssaidi@eecs.umich.edu{
1454433Ssaidi@eecs.umich.edu    // Bring tickNextIdle up to the present tick.
1465562Snate@binkert.org    // There is some potential ambiguity where a cycle starts, which
1474433Ssaidi@eecs.umich.edu    // might make a difference when devices are acting right around a
1484433Ssaidi@eecs.umich.edu    // cycle boundary. Using a < allows things which happen exactly on
1494433Ssaidi@eecs.umich.edu    // a cycle boundary to take up only the following cycle. Anything
1504433Ssaidi@eecs.umich.edu    // that happens later will have to "wait" for the end of that
1512657Ssaidi@eecs.umich.edu    // cycle, and then start using the bus after that.
1522657Ssaidi@eecs.umich.edu    if (tickNextIdle < curTick()) {
1534433Ssaidi@eecs.umich.edu        tickNextIdle = curTick();
1544433Ssaidi@eecs.umich.edu        if (tickNextIdle % clock != 0)
1554433Ssaidi@eecs.umich.edu            tickNextIdle = curTick() - (curTick() % clock) + clock;
1564433Ssaidi@eecs.umich.edu    }
1574986Ssaidi@eecs.umich.edu
1584870Sstever@eecs.umich.edu    Tick headerTime = tickNextIdle + headerCycles * clock;
1592657Ssaidi@eecs.umich.edu
1604433Ssaidi@eecs.umich.edu    // The packet will be sent. Figure out how long it occupies the bus, and
1614435Ssaidi@eecs.umich.edu    // how much of that time is for the first "word", aka bus width.
1624433Ssaidi@eecs.umich.edu    int numCycles = 0;
1634435Ssaidi@eecs.umich.edu    if (pkt->hasData()) {
1644435Ssaidi@eecs.umich.edu        // If a packet has data, it needs ceil(size/width) cycles to send it
1654433Ssaidi@eecs.umich.edu        int dataSize = pkt->getSize();
1664435Ssaidi@eecs.umich.edu        numCycles += dataSize/width;
1675606Snate@binkert.org        if (dataSize % width)
1684435Ssaidi@eecs.umich.edu            numCycles++;
1694435Ssaidi@eecs.umich.edu    }
1704433Ssaidi@eecs.umich.edu
1714435Ssaidi@eecs.umich.edu    // The first word will be delivered after the current tick, the delivery
1724435Ssaidi@eecs.umich.edu    // of the address if any, and one bus cycle to deliver the data
1734435Ssaidi@eecs.umich.edu    pkt->firstWordTime = headerTime + clock;
1744435Ssaidi@eecs.umich.edu
1754435Ssaidi@eecs.umich.edu    pkt->finishTime = headerTime + numCycles * clock;
1764435Ssaidi@eecs.umich.edu
1774435Ssaidi@eecs.umich.edu    return headerTime;
1784435Ssaidi@eecs.umich.edu}
1794435Ssaidi@eecs.umich.edu
1804435Ssaidi@eecs.umich.eduvoid Bus::occupyBus(Tick until)
1814435Ssaidi@eecs.umich.edu{
1824435Ssaidi@eecs.umich.edu    if (until == 0) {
1834435Ssaidi@eecs.umich.edu        // shortcut for express snoop packets
1844435Ssaidi@eecs.umich.edu        return;
1854435Ssaidi@eecs.umich.edu    }
1864435Ssaidi@eecs.umich.edu
1874435Ssaidi@eecs.umich.edu    tickNextIdle = until;
1884435Ssaidi@eecs.umich.edu    reschedule(busIdle, tickNextIdle, true);
1895606Snate@binkert.org
1904435Ssaidi@eecs.umich.edu    DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
1914435Ssaidi@eecs.umich.edu            curTick(), tickNextIdle);
1924435Ssaidi@eecs.umich.edu}
1934435Ssaidi@eecs.umich.edu
1944435Ssaidi@eecs.umich.edu/** Function called by the port when the bus is receiving a Timing
1954435Ssaidi@eecs.umich.edu * transaction.*/
1964433Ssaidi@eecs.umich.edubool
1974433Ssaidi@eecs.umich.eduBus::recvTiming(PacketPtr pkt)
1984433Ssaidi@eecs.umich.edu{
1994433Ssaidi@eecs.umich.edu    short src = pkt->getSrc();
2003349Sbinkertn@umich.edu
2012657Ssaidi@eecs.umich.edu    BusPort *src_port;
2024986Ssaidi@eecs.umich.edu    if (src == defaultId)
2032643Sstever@eecs.umich.edu        src_port = defaultPort;
2042643Sstever@eecs.umich.edu    else {
2052643Sstever@eecs.umich.edu        src_port = checkBusCache(src);
2064986Ssaidi@eecs.umich.edu        if (src_port == NULL) {
2072643Sstever@eecs.umich.edu            src_port = interfaces[src];
2082643Sstever@eecs.umich.edu            updateBusCache(src, src_port);
2092643Sstever@eecs.umich.edu        }
2102643Sstever@eecs.umich.edu    }
2112643Sstever@eecs.umich.edu
2124433Ssaidi@eecs.umich.edu    // If the bus is busy, or other devices are in line ahead of the current
2134739Sstever@eecs.umich.edu    // one, put this device on the retry list.
2142643Sstever@eecs.umich.edu    if (!pkt->isExpressSnoop() &&
2152643Sstever@eecs.umich.edu        (tickNextIdle > curTick() ||
2162643Sstever@eecs.umich.edu         (retryList.size() && (!inRetry || src_port != retryList.front()))))
2174450Ssaidi@eecs.umich.edu    {
2184986Ssaidi@eecs.umich.edu        addToRetryList(src_port);
2194450Ssaidi@eecs.umich.edu        DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",
2204450Ssaidi@eecs.umich.edu                src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
2214450Ssaidi@eecs.umich.edu        return false;
2224450Ssaidi@eecs.umich.edu    }
2234450Ssaidi@eecs.umich.edu
2242643Sstever@eecs.umich.edu    DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",
2252643Sstever@eecs.umich.edu            src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
2262643Sstever@eecs.umich.edu
2272643Sstever@eecs.umich.edu    Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
2282643Sstever@eecs.umich.edu    Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
2292643Sstever@eecs.umich.edu
2302643Sstever@eecs.umich.edu    short dest = pkt->getDest();
2312643Sstever@eecs.umich.edu    int dest_port_id;
2325606Snate@binkert.org    Port *dest_port;
2332568SN/A
2342643Sstever@eecs.umich.edu    if (dest == Packet::Broadcast) {
2352568SN/A        dest_port_id = findPort(pkt->getAddr());
2362568SN/A        dest_port = (dest_port_id == defaultId) ?
2372568SN/A            defaultPort : interfaces[dest_port_id];
2382643Sstever@eecs.umich.edu        SnoopIter s_end = snoopPorts.end();
2392568SN/A        for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
2402643Sstever@eecs.umich.edu            BusPort *p = *s_iter;
2412568SN/A            if (p != dest_port && p != src_port) {
2422643Sstever@eecs.umich.edu                // cache is not allowed to refuse snoop
2432643Sstever@eecs.umich.edu                bool success M5_VAR_USED = p->sendTiming(pkt);
2442643Sstever@eecs.umich.edu                assert(success);
2452643Sstever@eecs.umich.edu            }
2463349Sbinkertn@umich.edu        }
2472643Sstever@eecs.umich.edu    } else {
2482643Sstever@eecs.umich.edu        assert(dest < maxId);
2492643Sstever@eecs.umich.edu        assert(dest != src); // catch infinite loops
2502643Sstever@eecs.umich.edu        dest_port_id = dest;
2514450Ssaidi@eecs.umich.edu        if (dest_port_id == defaultId)
2524986Ssaidi@eecs.umich.edu            dest_port = defaultPort;
2534986Ssaidi@eecs.umich.edu        else {
2544986Ssaidi@eecs.umich.edu            dest_port = checkBusCache(dest);
2554986Ssaidi@eecs.umich.edu            if (dest_port == NULL) {
2564986Ssaidi@eecs.umich.edu                dest_port = interfaces[dest_port_id];
2574986Ssaidi@eecs.umich.edu            // updateBusCache(dest_port_id, dest_port);
2584986Ssaidi@eecs.umich.edu            }
2594986Ssaidi@eecs.umich.edu        }
2604986Ssaidi@eecs.umich.edu        dest_port = (dest_port_id == defaultId) ?
2614432Ssaidi@eecs.umich.edu            defaultPort : interfaces[dest_port_id];
2622643Sstever@eecs.umich.edu    }
2632643Sstever@eecs.umich.edu
2642643Sstever@eecs.umich.edu    if (dest_port_id == src) {
2652643Sstever@eecs.umich.edu        // Must be forwarded snoop up from below...
2662657Ssaidi@eecs.umich.edu        assert(dest == Packet::Broadcast);
2672657Ssaidi@eecs.umich.edu    } else {
2684433Ssaidi@eecs.umich.edu        // send to actual target
2692657Ssaidi@eecs.umich.edu        if (!dest_port->sendTiming(pkt))  {
2702657Ssaidi@eecs.umich.edu            // Packet not successfully sent. Leave or put it on the retry list.
2712657Ssaidi@eecs.umich.edu            // illegal to block responses... can lead to deadlock
2722657Ssaidi@eecs.umich.edu            assert(!pkt->isResponse());
2732657Ssaidi@eecs.umich.edu            // It's also illegal to force a transaction to retry after
2742657Ssaidi@eecs.umich.edu            // someone else has committed to respond.
2752657Ssaidi@eecs.umich.edu            assert(!pkt->memInhibitAsserted());
2762657Ssaidi@eecs.umich.edu            DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
2774986Ssaidi@eecs.umich.edu                    src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
2784986Ssaidi@eecs.umich.edu            addToRetryList(src_port);
2794986Ssaidi@eecs.umich.edu            occupyBus(headerFinishTime);
2804986Ssaidi@eecs.umich.edu            return false;
2814433Ssaidi@eecs.umich.edu        }
2822657Ssaidi@eecs.umich.edu        // send OK, fall through... pkt may have been deleted by
2832657Ssaidi@eecs.umich.edu        // target at this point, so it should *not* be referenced
2842657Ssaidi@eecs.umich.edu        // again.  We'll set it to NULL here just to be safe.
2854433Ssaidi@eecs.umich.edu        pkt = NULL;
2865606Snate@binkert.org    }
2872657Ssaidi@eecs.umich.edu
2882643Sstever@eecs.umich.edu    occupyBus(packetFinishTime);
2892643Sstever@eecs.umich.edu
2904986Ssaidi@eecs.umich.edu    // Packet was successfully sent.
2914435Ssaidi@eecs.umich.edu    // Also take care of retries
2922643Sstever@eecs.umich.edu    if (inRetry) {
2934986Ssaidi@eecs.umich.edu        DPRINTF(Bus, "Remove retry from list %d\n", src);
2944433Ssaidi@eecs.umich.edu        retryList.front()->onRetryList(false);
2954433Ssaidi@eecs.umich.edu        retryList.pop_front();
2962568SN/A        inRetry = false;
2972568SN/A    }
2982568SN/A    return true;
2992657Ssaidi@eecs.umich.edu}
3002568SN/A
3012568SN/Avoid
3024435Ssaidi@eecs.umich.eduBus::recvRetry(int id)
3034435Ssaidi@eecs.umich.edu{
3044435Ssaidi@eecs.umich.edu    // If there's anything waiting, and the bus isn't busy...
3054435Ssaidi@eecs.umich.edu    if (retryList.size() && curTick() >= tickNextIdle) {
3064435Ssaidi@eecs.umich.edu        //retryingPort = retryList.front();
3075606Snate@binkert.org        inRetry = true;
3082568SN/A        DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());
3092568SN/A        retryList.front()->sendRetry();
3102643Sstever@eecs.umich.edu        // If inRetry is still true, sendTiming wasn't called
3112568SN/A        if (inRetry)
3122568SN/A        {
3133349Sbinkertn@umich.edu            retryList.front()->onRetryList(false);
3142568SN/A            retryList.pop_front();
3154454Ssaidi@eecs.umich.edu            inRetry = false;
3162568SN/A
3172568SN/A            //Bring tickNextIdle up to the present
3182643Sstever@eecs.umich.edu            while (tickNextIdle < curTick())
3192568SN/A                tickNextIdle += clock;
3202568SN/A
3213349Sbinkertn@umich.edu            //Burn a cycle for the missed grant.
3222568SN/A            tickNextIdle += clock;
3232643Sstever@eecs.umich.edu
3242568SN/A            reschedule(busIdle, tickNextIdle, true);
3255314Sstever@gmail.com        }
3265314Sstever@gmail.com    }
3272643Sstever@eecs.umich.edu    //If we weren't able to drain before, we might be able to now.
3287668Ssteve.reinhardt@amd.com    if (drainEvent && retryList.size() == 0 && curTick() >= tickNextIdle) {
3297668Ssteve.reinhardt@amd.com        drainEvent->process();
3304626Sstever@eecs.umich.edu        // Clear the drain event once we're done with it.
3317668Ssteve.reinhardt@amd.com        drainEvent = NULL;
3322568SN/A    }
3332568SN/A}
3345314Sstever@gmail.com
3355314Sstever@gmail.comint
3364626Sstever@eecs.umich.eduBus::findPort(Addr addr)
3374626Sstever@eecs.umich.edu{
3382568SN/A    /* An interval tree would be a better way to do this. --ali. */
3392568SN/A    int dest_id;
3402643Sstever@eecs.umich.edu
3412568SN/A    dest_id = checkPortCache(addr);
3422643Sstever@eecs.umich.edu    if (dest_id != -1)
3432568SN/A        return dest_id;
3442643Sstever@eecs.umich.edu
3452568SN/A    // Check normal port ranges
3462568SN/A    PortIter i = portMap.find(RangeSize(addr,1));
3472568SN/A    if (i != portMap.end()) {
3482643Sstever@eecs.umich.edu        dest_id = i->second;
3494475Sstever@eecs.umich.edu        updatePortCache(dest_id, i->first.start, i->first.end);
3502568SN/A        return dest_id;
3512643Sstever@eecs.umich.edu    }
3524965Ssaidi@eecs.umich.edu
3534877Sstever@eecs.umich.edu    // Check if this matches the default range
3544877Sstever@eecs.umich.edu    if (useDefaultRange) {
3552568SN/A        AddrRangeIter a_end = defaultRange.end();
3562568SN/A        for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
3574762Snate@binkert.org            if (*i == addr) {
3584762Snate@binkert.org                DPRINTF(Bus, "  found addr %#llx on default\n", addr);
3592568SN/A                return defaultId;
3604762Snate@binkert.org            }
3612568SN/A        }
362
363        panic("Unable to find destination for addr %#llx\n", addr);
364    }
365
366    DPRINTF(Bus, "Unable to find destination for addr %#llx, "
367            "will use default port\n", addr);
368    return defaultId;
369}
370
371
372/** Function called by the port when the bus is receiving a Atomic
373 * transaction.*/
374Tick
375Bus::recvAtomic(PacketPtr pkt)
376{
377    DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
378            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
379    assert(pkt->getDest() == Packet::Broadcast);
380    assert(pkt->isRequest());
381
382    // Variables for recording original command and snoop response (if
383    // any)... if a snooper respondes, we will need to restore
384    // original command so that additional snoops can take place
385    // properly
386    MemCmd orig_cmd = pkt->cmd;
387    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
388    Tick snoop_response_latency = 0;
389    int orig_src = pkt->getSrc();
390
391    int target_port_id = findPort(pkt->getAddr());
392    BusPort *target_port;
393    if (target_port_id == defaultId)
394        target_port = defaultPort;
395    else {
396      target_port = checkBusCache(target_port_id);
397      if (target_port == NULL) {
398          target_port = interfaces[target_port_id];
399          updateBusCache(target_port_id, target_port);
400      }
401    }
402
403    SnoopIter s_end = snoopPorts.end();
404    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
405        BusPort *p = *s_iter;
406        // same port should not have both target addresses and snooping
407        assert(p != target_port);
408        if (p->getId() != pkt->getSrc()) {
409            Tick latency = p->sendAtomic(pkt);
410            if (pkt->isResponse()) {
411                // response from snoop agent
412                assert(pkt->cmd != orig_cmd);
413                assert(pkt->memInhibitAsserted());
414                // should only happen once
415                assert(snoop_response_cmd == MemCmd::InvalidCmd);
416                // save response state
417                snoop_response_cmd = pkt->cmd;
418                snoop_response_latency = latency;
419                // restore original packet state for remaining snoopers
420                pkt->cmd = orig_cmd;
421                pkt->setSrc(orig_src);
422                pkt->setDest(Packet::Broadcast);
423            }
424        }
425    }
426
427    Tick response_latency = 0;
428
429    // we can get requests sent up from the memory side of the bus for
430    // snooping... don't send them back down!
431    if (target_port_id != pkt->getSrc()) {
432        response_latency = target_port->sendAtomic(pkt);
433    }
434
435    // if we got a response from a snooper, restore it here
436    if (snoop_response_cmd != MemCmd::InvalidCmd) {
437        // no one else should have responded
438        assert(!pkt->isResponse());
439        assert(pkt->cmd == orig_cmd);
440        pkt->cmd = snoop_response_cmd;
441        response_latency = snoop_response_latency;
442    }
443
444    // why do we have this packet field and the return value both???
445    pkt->finishTime = curTick() + response_latency;
446    return response_latency;
447}
448
449/** Function called by the port when the bus is receiving a Functional
450 * transaction.*/
451void
452Bus::recvFunctional(PacketPtr pkt)
453{
454    assert(pkt->getDest() == Packet::Broadcast);
455
456    int port_id = findPort(pkt->getAddr());
457    Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id];
458    // The packet may be changed by another bus on snoops, restore the
459    // id after each
460    int src_id = pkt->getSrc();
461
462    if (!pkt->isPrint()) {
463        // don't do DPRINTFs on PrintReq as it clutters up the output
464        DPRINTF(Bus,
465                "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
466                src_id, port_id, pkt->getAddr(),
467                pkt->cmdString());
468    }
469
470    assert(pkt->isRequest()); // hasn't already been satisfied
471
472    SnoopIter s_end = snoopPorts.end();
473    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
474        BusPort *p = *s_iter;
475        if (p != port && p->getId() != src_id) {
476            p->sendFunctional(pkt);
477        }
478        if (pkt->isResponse()) {
479            break;
480        }
481        pkt->setSrc(src_id);
482    }
483
484    // If the snooping hasn't found what we were looking for, keep going.
485    if (!pkt->isResponse() && port_id != pkt->getSrc()) {
486        port->sendFunctional(pkt);
487    }
488}
489
490/** Function called by the port when the bus is receiving a range change.*/
491void
492Bus::recvRangeChange(int id)
493{
494    AddrRangeList ranges;
495    AddrRangeIter iter;
496
497    if (inRecvRangeChange.count(id))
498        return;
499    inRecvRangeChange.insert(id);
500
501    DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
502
503    clearPortCache();
504    if (id == defaultId) {
505        defaultRange.clear();
506        // Only try to update these ranges if the user set a default responder.
507        if (useDefaultRange) {
508            AddrRangeList ranges = defaultPort->getPeer()->getAddrRanges();
509            for(iter = ranges.begin(); iter != ranges.end(); iter++) {
510                defaultRange.push_back(*iter);
511                DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
512                        iter->start, iter->end);
513            }
514        }
515    } else {
516
517        assert((id < maxId && id >= 0) || id == defaultId);
518        BusPort *port = interfaces[id];
519
520        // Clean out any previously existent ids
521        for (PortIter portIter = portMap.begin();
522             portIter != portMap.end(); ) {
523            if (portIter->second == id)
524                portMap.erase(portIter++);
525            else
526                portIter++;
527        }
528
529        ranges = port->getPeer()->getAddrRanges();
530
531        for (iter = ranges.begin(); iter != ranges.end(); iter++) {
532            DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
533                    iter->start, iter->end, id);
534            if (portMap.insert(*iter, id) == portMap.end()) {
535                int conflict_id = portMap.find(*iter)->second;
536                fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
537                      name(), interfaces[id]->getPeer()->name(),
538                      interfaces[conflict_id]->getPeer()->name());
539            }
540        }
541    }
542    DPRINTF(MMU, "port list has %d entries\n", portMap.size());
543
544    // tell all our peers that our address range has changed.
545    // Don't tell the device that caused this change, it already knows
546    m5::hash_map<short,BusPort*>::iterator intIter;
547
548    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
549        if (intIter->first != id && intIter->first != funcPortId)
550            intIter->second->sendRangeChange();
551
552    if (id != defaultId && defaultPort)
553        defaultPort->sendRangeChange();
554    inRecvRangeChange.erase(id);
555}
556
557AddrRangeList
558Bus::getAddrRanges(int id)
559{
560    AddrRangeList ranges;
561
562    DPRINTF(BusAddrRanges, "received address range request, returning:\n");
563
564    for (AddrRangeIter dflt_iter = defaultRange.begin();
565         dflt_iter != defaultRange.end(); dflt_iter++) {
566        ranges.push_back(*dflt_iter);
567        DPRINTF(BusAddrRanges, "  -- Dflt: %#llx : %#llx\n",dflt_iter->start,
568                dflt_iter->end);
569    }
570    for (PortIter portIter = portMap.begin();
571         portIter != portMap.end(); portIter++) {
572        bool subset = false;
573        for (AddrRangeIter dflt_iter = defaultRange.begin();
574             dflt_iter != defaultRange.end(); dflt_iter++) {
575            if ((portIter->first.start < dflt_iter->start &&
576                portIter->first.end >= dflt_iter->start) ||
577               (portIter->first.start < dflt_iter->end &&
578                portIter->first.end >= dflt_iter->end))
579                fatal("Devices can not set ranges that itersect the default set\
580                        but are not a subset of the default set.\n");
581            if (portIter->first.start >= dflt_iter->start &&
582                portIter->first.end <= dflt_iter->end) {
583                subset = true;
584                DPRINTF(BusAddrRanges, "  -- %#llx : %#llx is a SUBSET\n",
585                    portIter->first.start, portIter->first.end);
586            }
587        }
588        if (portIter->second != id && !subset) {
589            ranges.push_back(portIter->first);
590            DPRINTF(BusAddrRanges, "  -- %#llx : %#llx\n",
591                    portIter->first.start, portIter->first.end);
592        }
593    }
594
595    return ranges;
596}
597
598bool
599Bus::isSnooping(int id)
600{
601    // in essence, answer the question if there are other snooping
602    // ports rather than the port that is asking
603    bool snoop = false;
604    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end();
605         s_iter++) {
606        if ((*s_iter)->getId() != id) {
607            snoop = true;
608            break;
609        }
610    }
611    return snoop;
612}
613
614unsigned
615Bus::findBlockSize(int id)
616{
617    if (cachedBlockSizeValid)
618        return cachedBlockSize;
619
620    unsigned max_bs = 0;
621
622    PortIter p_end = portMap.end();
623    for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
624        unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize();
625        if (tmp_bs > max_bs)
626            max_bs = tmp_bs;
627    }
628    SnoopIter s_end = snoopPorts.end();
629    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
630        unsigned tmp_bs = (*s_iter)->peerBlockSize();
631        if (tmp_bs > max_bs)
632            max_bs = tmp_bs;
633    }
634    if (max_bs == 0)
635        max_bs = defaultBlockSize;
636
637    if (max_bs != 64)
638        warn_once("Blocksize found to not be 64... hmm... probably not.\n");
639    cachedBlockSize = max_bs;
640    cachedBlockSizeValid = true;
641    return max_bs;
642}
643
644
645unsigned int
646Bus::drain(Event * de)
647{
648    //We should check that we're not "doing" anything, and that noone is
649    //waiting. We might be idle but have someone waiting if the device we
650    //contacted for a retry didn't actually retry.
651    if (retryList.size() || (curTick() < tickNextIdle && busIdle.scheduled())) {
652        drainEvent = de;
653        return 1;
654    }
655    return 0;
656}
657
658void
659Bus::startup()
660{
661    if (tickNextIdle < curTick())
662        tickNextIdle = (curTick() / clock) * clock + clock;
663}
664
665Bus *
666BusParams::create()
667{
668    return new Bus(this);
669}
670