xbar.cc revision 3074
111731Sjason@lowepower.com/*
211731Sjason@lowepower.com * Copyright (c) 2006 The Regents of The University of Michigan
311731Sjason@lowepower.com * All rights reserved.
411731Sjason@lowepower.com *
511731Sjason@lowepower.com * Redistribution and use in source and binary forms, with or without
611731Sjason@lowepower.com * modification, are permitted provided that the following conditions are
711731Sjason@lowepower.com * met: redistributions of source code must retain the above copyright
811731Sjason@lowepower.com * notice, this list of conditions and the following disclaimer;
911731Sjason@lowepower.com * redistributions in binary form must reproduce the above copyright
1011731Sjason@lowepower.com * notice, this list of conditions and the following disclaimer in the
1111731Sjason@lowepower.com * documentation and/or other materials provided with the distribution;
1211731Sjason@lowepower.com * neither the name of the copyright holders nor the names of its
1311731Sjason@lowepower.com * contributors may be used to endorse or promote products derived from
1411731Sjason@lowepower.com * this software without specific prior written permission.
1511731Sjason@lowepower.com *
1611731Sjason@lowepower.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1711731Sjason@lowepower.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1811731Sjason@lowepower.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1911731Sjason@lowepower.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2011731Sjason@lowepower.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2111731Sjason@lowepower.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2211731Sjason@lowepower.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2311731Sjason@lowepower.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2411731Sjason@lowepower.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2511731Sjason@lowepower.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2611731Sjason@lowepower.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2711731Sjason@lowepower.com *
2811731Sjason@lowepower.com * Authors: Ali Saidi
2911731Sjason@lowepower.com */
3011731Sjason@lowepower.com
3111731Sjason@lowepower.com/**
3211731Sjason@lowepower.com * @file
3311731Sjason@lowepower.com * Definition of a bus object.
3411731Sjason@lowepower.com */
3511731Sjason@lowepower.com
3611731Sjason@lowepower.com
3711731Sjason@lowepower.com#include "base/misc.hh"
3811731Sjason@lowepower.com#include "base/trace.hh"
3911731Sjason@lowepower.com#include "mem/bus.hh"
4011731Sjason@lowepower.com#include "sim/builder.hh"
4111731Sjason@lowepower.com
4211731Sjason@lowepower.comPort *
4311731Sjason@lowepower.comBus::getPort(const std::string &if_name, int idx)
4411731Sjason@lowepower.com{
4511731Sjason@lowepower.com    if (if_name == "default")
4611731Sjason@lowepower.com        if (defaultPort == NULL) {
4711731Sjason@lowepower.com            defaultPort = new BusPort(csprintf("%s-default",name()), this,
4811731Sjason@lowepower.com                    defaultId);
4911731Sjason@lowepower.com            return defaultPort;
5011731Sjason@lowepower.com        } else
5111731Sjason@lowepower.com            fatal("Default port already set\n");
5211731Sjason@lowepower.com
5311731Sjason@lowepower.com    // if_name ignored?  forced to be empty?
5411731Sjason@lowepower.com    int id = interfaces.size();
5511731Sjason@lowepower.com    BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
5611731Sjason@lowepower.com    interfaces.push_back(bp);
5711731Sjason@lowepower.com    return bp;
5811731Sjason@lowepower.com}
5911731Sjason@lowepower.com
6011731Sjason@lowepower.com/** Get the ranges of anyone other buses that we are connected to. */
6111731Sjason@lowepower.comvoid
6211731Sjason@lowepower.comBus::init()
6311731Sjason@lowepower.com{
6411731Sjason@lowepower.com    std::vector<Port*>::iterator intIter;
6511731Sjason@lowepower.com
6611731Sjason@lowepower.com    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
6711731Sjason@lowepower.com        (*intIter)->sendStatusChange(Port::RangeChange);
6811731Sjason@lowepower.com}
6911731Sjason@lowepower.com
7011731Sjason@lowepower.com
7111731Sjason@lowepower.com/** Function called by the port when the bus is receiving a Timing
7211731Sjason@lowepower.com * transaction.*/
7311731Sjason@lowepower.combool
7411731Sjason@lowepower.comBus::recvTiming(Packet *pkt)
7511731Sjason@lowepower.com{
7611731Sjason@lowepower.com    Port *port;
7711731Sjason@lowepower.com    DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
7811731Sjason@lowepower.com            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
7911731Sjason@lowepower.com
8011731Sjason@lowepower.com    short dest = pkt->getDest();
8111731Sjason@lowepower.com    if (dest == Packet::Broadcast) {
8211731Sjason@lowepower.com        if ( timingSnoopPhase1(pkt) )
8311731Sjason@lowepower.com        {
8411731Sjason@lowepower.com            timingSnoopPhase2(pkt);
8511731Sjason@lowepower.com            port = findPort(pkt->getAddr(), pkt->getSrc());
8611731Sjason@lowepower.com        }
8711731Sjason@lowepower.com        else
8811731Sjason@lowepower.com        {
8911731Sjason@lowepower.com            //Snoop didn't succeed
9011731Sjason@lowepower.com            retryList.push_back(interfaces[pkt->getSrc()]);
9111731Sjason@lowepower.com            return false;
9211731Sjason@lowepower.com        }
9311731Sjason@lowepower.com    } else {
9411731Sjason@lowepower.com        assert(dest >= 0 && dest < interfaces.size());
9511731Sjason@lowepower.com        assert(dest != pkt->getSrc()); // catch infinite loops
9611731Sjason@lowepower.com        port = interfaces[dest];
9711731Sjason@lowepower.com    }
9811731Sjason@lowepower.com    if (port->sendTiming(pkt))  {
9911731Sjason@lowepower.com        // packet was successfully sent, just return true.
10011731Sjason@lowepower.com        return true;
10111731Sjason@lowepower.com    }
10211731Sjason@lowepower.com
10311731Sjason@lowepower.com    // packet not successfully sent
10411731Sjason@lowepower.com    retryList.push_back(interfaces[pkt->getSrc()]);
10511731Sjason@lowepower.com    return false;
10611731Sjason@lowepower.com}
10711731Sjason@lowepower.com
10811731Sjason@lowepower.comvoid
10911731Sjason@lowepower.comBus::recvRetry(int id)
11011731Sjason@lowepower.com{
11111731Sjason@lowepower.com    // Go through all the elements on the list calling sendRetry on each
11211731Sjason@lowepower.com    // This is not very efficient at all but it works. Ultimately we should end
11311731Sjason@lowepower.com    // up with something that is more intelligent.
11411731Sjason@lowepower.com    int initialSize = retryList.size();
11511731Sjason@lowepower.com    int i;
11611731Sjason@lowepower.com    Port *p;
11711731Sjason@lowepower.com
11811731Sjason@lowepower.com    for (i = 0; i < initialSize; i++) {
11911731Sjason@lowepower.com        assert(retryList.size() > 0);
12011731Sjason@lowepower.com        p = retryList.front();
12111731Sjason@lowepower.com        retryList.pop_front();
12211731Sjason@lowepower.com        p->sendRetry();
12311731Sjason@lowepower.com    }
12411731Sjason@lowepower.com}
12511731Sjason@lowepower.com
12611731Sjason@lowepower.com
12711731Sjason@lowepower.comPort *
12811731Sjason@lowepower.comBus::findPort(Addr addr, int id)
12911731Sjason@lowepower.com{
13011731Sjason@lowepower.com    /* An interval tree would be a better way to do this. --ali. */
13111731Sjason@lowepower.com    int dest_id = -1;
13211731Sjason@lowepower.com    int i = 0;
13311731Sjason@lowepower.com    bool found = false;
13411731Sjason@lowepower.com    AddrRangeIter iter;
13511731Sjason@lowepower.com
13611731Sjason@lowepower.com    while (i < portList.size() && !found)
13711731Sjason@lowepower.com    {
13811731Sjason@lowepower.com        if (portList[i].range == addr) {
13911731Sjason@lowepower.com            dest_id = portList[i].portId;
14011731Sjason@lowepower.com            found = true;
14111731Sjason@lowepower.com            DPRINTF(Bus, "  found addr 0x%llx on device %d\n", addr, dest_id);
14211731Sjason@lowepower.com        }
14311731Sjason@lowepower.com        i++;
14411731Sjason@lowepower.com    }
14511731Sjason@lowepower.com
14611731Sjason@lowepower.com    // Check if this matches the default range
14711731Sjason@lowepower.com    if (dest_id == -1) {
14811731Sjason@lowepower.com        for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) {
14911731Sjason@lowepower.com            if (*iter == addr) {
15011731Sjason@lowepower.com                DPRINTF(Bus, "  found addr 0x%llx on default\n", addr);
15111731Sjason@lowepower.com                return defaultPort;
15211731Sjason@lowepower.com            }
15311731Sjason@lowepower.com        }
15411731Sjason@lowepower.com        panic("Unable to find destination for addr: %llx", addr);
15511731Sjason@lowepower.com    }
15611731Sjason@lowepower.com
15711731Sjason@lowepower.com
15811731Sjason@lowepower.com    // we shouldn't be sending this back to where it came from
15911731Sjason@lowepower.com    assert(dest_id != id);
16011731Sjason@lowepower.com
16111731Sjason@lowepower.com    return interfaces[dest_id];
16211731Sjason@lowepower.com}
16311731Sjason@lowepower.com
16411731Sjason@lowepower.comstd::vector<int>
16511731Sjason@lowepower.comBus::findSnoopPorts(Addr addr, int id)
16611731Sjason@lowepower.com{
16711731Sjason@lowepower.com    int i = 0;
16811731Sjason@lowepower.com    AddrRangeIter iter;
16911731Sjason@lowepower.com    std::vector<int> ports;
17011731Sjason@lowepower.com
17111731Sjason@lowepower.com    while (i < portSnoopList.size())
17211731Sjason@lowepower.com    {
17311731Sjason@lowepower.com        if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) {
17411731Sjason@lowepower.com            //Careful  to not overlap ranges
17511731Sjason@lowepower.com            //or snoop will be called more than once on the port
17611731Sjason@lowepower.com            ports.push_back(portSnoopList[i].portId);
17711731Sjason@lowepower.com            DPRINTF(Bus, "  found snoop addr 0x%llx on device%d\n", addr,
17811731Sjason@lowepower.com                    portSnoopList[i].portId);
17911731Sjason@lowepower.com        }
18011731Sjason@lowepower.com        i++;
18111731Sjason@lowepower.com    }
18211731Sjason@lowepower.com    return ports;
18311731Sjason@lowepower.com}
18411731Sjason@lowepower.com
18511731Sjason@lowepower.comvoid
18611731Sjason@lowepower.comBus::atomicSnoop(Packet *pkt)
18711731Sjason@lowepower.com{
18811731Sjason@lowepower.com    std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
18911731Sjason@lowepower.com
19011731Sjason@lowepower.com    while (!ports.empty())
19111731Sjason@lowepower.com    {
19211731Sjason@lowepower.com        interfaces[ports.back()]->sendAtomic(pkt);
19311731Sjason@lowepower.com        ports.pop_back();
19411731Sjason@lowepower.com    }
19512062Sar4jc@virginia.edu}
19611731Sjason@lowepower.com
19711731Sjason@lowepower.combool
19811731Sjason@lowepower.comBus::timingSnoopPhase1(Packet *pkt)
19911731Sjason@lowepower.com{
20011731Sjason@lowepower.com    std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
20111731Sjason@lowepower.com    bool success = true;
20211731Sjason@lowepower.com
20311731Sjason@lowepower.com    while (!ports.empty() && success)
20411731Sjason@lowepower.com    {
20511731Sjason@lowepower.com        snoopCallbacks.push_back(ports.back());
20611731Sjason@lowepower.com        success = interfaces[ports.back()]->sendTiming(pkt);
20711731Sjason@lowepower.com        ports.pop_back();
20811731Sjason@lowepower.com    }
20911731Sjason@lowepower.com    if (!success)
21011731Sjason@lowepower.com    {
21111731Sjason@lowepower.com        while (!snoopCallbacks.empty())
21211731Sjason@lowepower.com        {
21311731Sjason@lowepower.com            interfaces[snoopCallbacks.back()]->sendStatusChange(Port::SnoopSquash);
21411731Sjason@lowepower.com            snoopCallbacks.pop_back();
21511731Sjason@lowepower.com        }
21611731Sjason@lowepower.com        return false;
21711731Sjason@lowepower.com    }
21811731Sjason@lowepower.com    return true;
21911731Sjason@lowepower.com}
22012062Sar4jc@virginia.edu
22112062Sar4jc@virginia.eduvoid
22211731Sjason@lowepower.comBus::timingSnoopPhase2(Packet *pkt)
22311731Sjason@lowepower.com{
22411731Sjason@lowepower.com    bool success;
22511731Sjason@lowepower.com    pkt->flags |= SNOOP_COMMIT;
22611731Sjason@lowepower.com    while (!snoopCallbacks.empty())
22712062Sar4jc@virginia.edu    {
22812062Sar4jc@virginia.edu        success = interfaces[snoopCallbacks.back()]->sendTiming(pkt);
22912062Sar4jc@virginia.edu        //We should not fail on snoop callbacks
23011731Sjason@lowepower.com        assert(success);
23112062Sar4jc@virginia.edu        snoopCallbacks.pop_back();
23211731Sjason@lowepower.com    }
23311731Sjason@lowepower.com}
23412062Sar4jc@virginia.edu
23511731Sjason@lowepower.com/** Function called by the port when the bus is receiving a Atomic
23611731Sjason@lowepower.com * transaction.*/
23711731Sjason@lowepower.comTick
23811731Sjason@lowepower.comBus::recvAtomic(Packet *pkt)
23911731Sjason@lowepower.com{
24011731Sjason@lowepower.com    DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
24111731Sjason@lowepower.com            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
24211731Sjason@lowepower.com    assert(pkt->getDest() == Packet::Broadcast);
24311731Sjason@lowepower.com    atomicSnoop(pkt);
24411731Sjason@lowepower.com    return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt);
24511731Sjason@lowepower.com}
24611731Sjason@lowepower.com
24712137Sar4jc@virginia.edu/** Function called by the port when the bus is receiving a Functional
24811731Sjason@lowepower.com * transaction.*/
24911731Sjason@lowepower.comvoid
25011731Sjason@lowepower.comBus::recvFunctional(Packet *pkt)
25111731Sjason@lowepower.com{
25211731Sjason@lowepower.com    DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
25311731Sjason@lowepower.com            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
25411731Sjason@lowepower.com    assert(pkt->getDest() == Packet::Broadcast);
25511731Sjason@lowepower.com    findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt);
25611731Sjason@lowepower.com}
25711731Sjason@lowepower.com
25811731Sjason@lowepower.com/** Function called by the port when the bus is receiving a status change.*/
25911731Sjason@lowepower.comvoid
26011731Sjason@lowepower.comBus::recvStatusChange(Port::Status status, int id)
26111731Sjason@lowepower.com{
26211731Sjason@lowepower.com    AddrRangeList ranges;
26311731Sjason@lowepower.com    AddrRangeList snoops;
26411731Sjason@lowepower.com    int x;
26511731Sjason@lowepower.com    AddrRangeIter iter;
26611731Sjason@lowepower.com
26711731Sjason@lowepower.com    assert(status == Port::RangeChange &&
26811731Sjason@lowepower.com           "The other statuses need to be implemented.");
26911731Sjason@lowepower.com
27011731Sjason@lowepower.com    DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
27111731Sjason@lowepower.com
27211731Sjason@lowepower.com    if (id == defaultId) {
27311731Sjason@lowepower.com        defaultRange.clear();
27411731Sjason@lowepower.com        defaultPort->getPeerAddressRanges(ranges, snoops);
27511731Sjason@lowepower.com        assert(snoops.size() == 0);
27611731Sjason@lowepower.com        for(iter = ranges.begin(); iter != ranges.end(); iter++) {
27711731Sjason@lowepower.com            defaultRange.push_back(*iter);
27811731Sjason@lowepower.com            DPRINTF(BusAddrRanges, "Adding range %llx - %llx for default range\n",
27911731Sjason@lowepower.com                    iter->start, iter->end);
28011731Sjason@lowepower.com        }
28111731Sjason@lowepower.com    } else {
28211731Sjason@lowepower.com
28311731Sjason@lowepower.com        assert((id < interfaces.size() && id >= 0) || id == -1);
28411731Sjason@lowepower.com        Port *port = interfaces[id];
28511731Sjason@lowepower.com        std::vector<DevMap>::iterator portIter;
28611731Sjason@lowepower.com        std::vector<DevMap>::iterator snoopIter;
28711731Sjason@lowepower.com
28811731Sjason@lowepower.com        // Clean out any previously existent ids
28911731Sjason@lowepower.com        for (portIter = portList.begin(); portIter != portList.end(); ) {
29011731Sjason@lowepower.com            if (portIter->portId == id)
29111731Sjason@lowepower.com                portIter = portList.erase(portIter);
29211731Sjason@lowepower.com            else
293                portIter++;
294        }
295
296        for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) {
297            if (snoopIter->portId == id)
298                snoopIter = portSnoopList.erase(snoopIter);
299            else
300                snoopIter++;
301        }
302
303        port->getPeerAddressRanges(ranges, snoops);
304
305        for(iter = snoops.begin(); iter != snoops.end(); iter++) {
306            DevMap dm;
307            dm.portId = id;
308            dm.range = *iter;
309
310            DPRINTF(BusAddrRanges, "Adding snoop range %llx - %llx for id %d\n",
311                    dm.range.start, dm.range.end, id);
312            portSnoopList.push_back(dm);
313        }
314
315        for(iter = ranges.begin(); iter != ranges.end(); iter++) {
316            DevMap dm;
317            dm.portId = id;
318            dm.range = *iter;
319
320            DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n",
321                    dm.range.start, dm.range.end, id);
322            portList.push_back(dm);
323        }
324    }
325    DPRINTF(MMU, "port list has %d entries\n", portList.size());
326
327    // tell all our peers that our address range has changed.
328    // Don't tell the device that caused this change, it already knows
329    for (x = 0; x < interfaces.size(); x++)
330        if (x != id)
331            interfaces[x]->sendStatusChange(Port::RangeChange);
332
333    if (id != defaultId && defaultPort)
334        defaultPort->sendStatusChange(Port::RangeChange);
335}
336
337void
338Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
339{
340    std::vector<DevMap>::iterator portIter;
341    AddrRangeIter dflt_iter;
342    bool subset;
343
344    resp.clear();
345    snoop.clear();
346
347    DPRINTF(BusAddrRanges, "received address range request, returning:\n");
348
349    for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
350            dflt_iter++) {
351        resp.push_back(*dflt_iter);
352        DPRINTF(BusAddrRanges, "  -- %#llX : %#llX\n",dflt_iter->start,
353                dflt_iter->end);
354    }
355    for (portIter = portList.begin(); portIter != portList.end(); portIter++) {
356        subset = false;
357        for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
358                dflt_iter++) {
359            if ((portIter->range.start < dflt_iter->start &&
360                portIter->range.end >= dflt_iter->start) ||
361               (portIter->range.start < dflt_iter->end &&
362                portIter->range.end >= dflt_iter->end))
363                fatal("Devices can not set ranges that itersect the default set\
364                        but are not a subset of the default set.\n");
365            if (portIter->range.start >= dflt_iter->start &&
366                portIter->range.end <= dflt_iter->end) {
367                subset = true;
368                DPRINTF(BusAddrRanges, "  -- %#llX : %#llX is a SUBSET\n",
369                    portIter->range.start, portIter->range.end);
370            }
371        }
372        if (portIter->portId != id && !subset) {
373            resp.push_back(portIter->range);
374            DPRINTF(BusAddrRanges, "  -- %#llX : %#llX\n",
375                    portIter->range.start, portIter->range.end);
376        }
377    }
378}
379
380BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
381
382    Param<int> bus_id;
383
384END_DECLARE_SIM_OBJECT_PARAMS(Bus)
385
386BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
387    INIT_PARAM(bus_id, "a globally unique bus id")
388END_INIT_SIM_OBJECT_PARAMS(Bus)
389
390CREATE_SIM_OBJECT(Bus)
391{
392    return new Bus(getInstanceName(), bus_id);
393}
394
395REGISTER_SIM_OBJECT("Bus", Bus)
396