X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fbus.cc;h=829d694de3bfdfff1cb41c5c5b2e688f2f9d1526;hb=7122b83d8f92d77bccae432b4e90ba12f1babad5;hp=1fad13c5a2b78ea793c0ab27907e2a6e883e7683;hpb=58250b8e5fd8aba9ed99b7aff6ce67b05b379fa0;p=gem5.git diff --git a/src/mem/bus.cc b/src/mem/bus.cc index 1fad13c5a..829d694de 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011-2012 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2006 The Regents of The University of Michigan * All rights reserved. * @@ -26,6 +38,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Ali Saidi + * Andreas Hansson + * William Wang */ /** @@ -33,415 +47,332 @@ * Definition of a bus object. */ -#include -#include - #include "base/misc.hh" #include "base/trace.hh" +#include "debug/Bus.hh" +#include "debug/BusAddrRanges.hh" +#include "debug/Drain.hh" #include "mem/bus.hh" -#include "sim/builder.hh" -Port * -Bus::getPort(const std::string &if_name, int idx) +BaseBus::BaseBus(const BaseBusParams *p) + : MemObject(p), + headerCycles(p->header_cycles), width(p->width), + defaultPortID(InvalidPortID), + useDefaultRange(p->use_default_range), + defaultBlockSize(p->block_size), + cachedBlockSize(0), cachedBlockSizeValid(false) { - if (if_name == "default") { - if (defaultPort == NULL) { - defaultPort = new BusPort(csprintf("%s-default",name()), this, - defaultId); - cachedBlockSizeValid = false; - return defaultPort; - } else - fatal("Default port already set\n"); - } - int id; - if (if_name == "functional") { - if (!funcPort) { - id = maxId++; - funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); - funcPortId = id; - interfaces[id] = funcPort; - } - return funcPort; - } - - // if_name ignored? forced to be empty? - id = maxId++; - assert(maxId < std::numeric_limits::max()); - BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); - interfaces[id] = bp; - cachedBlockSizeValid = false; - return bp; + //width, clock period, and header cycles must be positive + if (width <= 0) + fatal("Bus width must be positive\n"); + if (clock <= 0) + fatal("Bus clock period must be positive\n"); + if (headerCycles <= 0) + fatal("Number of header cycles must be positive\n"); } -void -Bus::deletePortRefs(Port *p) +BaseBus::~BaseBus() { + for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); + ++m) { + delete *m; + } - BusPort *bp = dynamic_cast(p); - if (bp == NULL) - panic("Couldn't convert Port* to BusPort*\n"); - // If this is our one functional port - if (funcPort == bp) - return; - interfaces.erase(bp->getId()); - delete bp; + for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); + ++s) { + delete *s; + } } -/** Get the ranges of anyone other buses that we are connected to. */ -void -Bus::init() +MasterPort & +BaseBus::getMasterPort(const std::string &if_name, int idx) { - m5::hash_map::iterator intIter; - - for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) - intIter->second->sendStatusChange(Port::RangeChange); + if (if_name == "master" && idx < masterPorts.size()) { + // the master port index translates directly to the vector position + return *masterPorts[idx]; + } else if (if_name == "default") { + return *masterPorts[defaultPortID]; + } else { + return MemObject::getMasterPort(if_name, idx); + } } -Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) -{} - -void Bus::BusFreeEvent::process() +SlavePort & +BaseBus::getSlavePort(const std::string &if_name, int idx) { - bus->recvRetry(-1); + if (if_name == "slave" && idx < slavePorts.size()) { + // the slave port index translates directly to the vector position + return *slavePorts[idx]; + } else { + return MemObject::getSlavePort(if_name, idx); + } } -const char * Bus::BusFreeEvent::description() +Tick +BaseBus::calcPacketTiming(PacketPtr pkt) { - return "bus became available"; -} + // determine the current time rounded to the closest following + // clock edge + Tick now = nextCycle(); -void Bus::occupyBus(PacketPtr pkt) -{ - //Bring tickNextIdle up to the present tick - //There is some potential ambiguity where a cycle starts, which might make - //a difference when devices are acting right around a cycle boundary. Using - //a < allows things which happen exactly on a cycle boundary to take up - //only the following cycle. Anything that happens later will have to "wait" - //for the end of that cycle, and then start using the bus after that. - if (tickNextIdle < curTick) { - tickNextIdle = curTick; - if (tickNextIdle % clock != 0) - tickNextIdle = curTick - (curTick % clock) + clock; - } + Tick headerTime = now + headerCycles * clock; // The packet will be sent. Figure out how long it occupies the bus, and // how much of that time is for the first "word", aka bus width. int numCycles = 0; - // Requests need one cycle to send an address - if (pkt->isRequest()) - numCycles++; - else if (pkt->isResponse() || pkt->hasData()) { + if (pkt->hasData()) { // If a packet has data, it needs ceil(size/width) cycles to send it - // We're using the "adding instead of dividing" trick again here - if (pkt->hasData()) { - int dataSize = pkt->getSize(); - numCycles += dataSize/width; - if (dataSize % width) - numCycles++; - } else { - // If the packet didn't have data, it must have been a response. - // Those use the bus for one cycle to send their data. + int dataSize = pkt->getSize(); + numCycles += dataSize/width; + if (dataSize % width) numCycles++; - } } // The first word will be delivered after the current tick, the delivery // of the address if any, and one bus cycle to deliver the data - pkt->firstWordTime = - tickNextIdle + - pkt->isRequest() ? clock : 0 + - clock; - - //Advance it numCycles bus cycles. - //XXX Should this use the repeated addition trick as well? - tickNextIdle += (numCycles * clock); - if (!busIdle.scheduled()) { - busIdle.schedule(tickNextIdle); - } else { - busIdle.reschedule(tickNextIdle); - } - DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", - curTick, tickNextIdle); + pkt->firstWordTime = headerTime + clock; + + pkt->finishTime = headerTime + numCycles * clock; + + return headerTime; +} + +template +BaseBus::Layer::Layer(BaseBus& _bus, const std::string& _name, + Tick _clock) : + bus(_bus), _name(_name), state(IDLE), clock(_clock), drainEvent(NULL), + releaseEvent(this) +{ +} - // The bus will become idle once the current packet is delivered. - pkt->finishTime = tickNextIdle; +template +void BaseBus::Layer::occupyLayer(Tick until) +{ + // ensure the state is busy or in retry and never idle at this + // point, as the bus should transition from idle as soon as it has + // decided to forward the packet to prevent any follow-on calls to + // sendTiming seeing an unoccupied bus + assert(state != IDLE); + + // note that we do not change the bus state here, if we are going + // from idle to busy it is handled by tryTiming, and if we + // are in retry we should remain in retry such that + // succeededTiming still sees the accurate state + + // until should never be 0 as express snoops never occupy the bus + assert(until != 0); + bus.schedule(releaseEvent, until); + + DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", + curTick(), until); } -/** Function called by the port when the bus is receiving a Timing - * transaction.*/ +template bool -Bus::recvTiming(PacketPtr pkt) +BaseBus::Layer::tryTiming(PortClass* port) { - short src = pkt->getSrc(); - DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", - src, pkt->getDest(), pkt->getAddr(), pkt->cmdString()); - - BusPort *src_port = (src == defaultId) ? defaultPort : interfaces[src]; - - // If the bus is busy, or other devices are in line ahead of the current - // one, put this device on the retry list. - if (!(pkt->isResponse() || pkt->isExpressSnoop()) && - (tickNextIdle > curTick || - (retryList.size() && (!inRetry || src_port != retryList.front())))) - { - addToRetryList(src_port); - DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n"); + // first we see if the bus is busy, next we check if we are in a + // retry with a port other than the current one + if (state == BUSY || (state == RETRY && port != retryList.front())) { + // put the port at the end of the retry list + retryList.push_back(port); return false; } - occupyBus(pkt); - - short dest = pkt->getDest(); - int dest_port_id; - Port *dest_port; - - if (dest == Packet::Broadcast) { - dest_port_id = findPort(pkt->getAddr()); - dest_port = (dest_port_id == defaultId) ? - defaultPort : interfaces[dest_port_id]; - for (SnoopIter s_iter = snoopPorts.begin(); - s_iter != snoopPorts.end(); - s_iter++) { - BusPort *p = *s_iter; - if (p != dest_port && p != src_port) { -#ifndef NDEBUG - // cache is not allowed to refuse snoop - bool success = p->sendTiming(pkt); - assert(success); -#else - // avoid unused variable warning - p->sendTiming(pkt); -#endif - } - } - } else { - assert(dest >= 0 && dest < maxId); - assert(dest != src); // catch infinite loops - dest_port_id = dest; - dest_port = (dest_port_id == defaultId) ? - defaultPort : interfaces[dest_port_id]; - } + // update the state which is shared for request, response and + // snoop responses, if we were idle we are now busy, if we are in + // a retry, then do not change + if (state == IDLE) + state = BUSY; - if (dest_port_id == src) { - // Must be forwarded snoop up from below... - assert(dest == Packet::Broadcast); - } else { - // send to actual target - if (!dest_port->sendTiming(pkt)) { - // Packet not successfully sent. Leave or put it on the retry list. - // illegal to block responses... can lead to deadlock - assert(!pkt->isResponse()); - DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n", src); - addToRetryList(src_port); - return false; - } - // send OK, fall through - } + return true; +} - // Packet was successfully sent. - // Also take care of retries - if (inRetry) { - DPRINTF(Bus, "Remove retry from list %d\n", src); - retryList.front()->onRetryList(false); +template +void +BaseBus::Layer::succeededTiming(Tick busy_time) +{ + // if a retrying port succeeded, also take it off the retry list + if (state == RETRY) { + DPRINTF(BaseBus, "Remove retry from list %s\n", + retryList.front()->name()); retryList.pop_front(); - inRetry = false; + state = BUSY; } - return true; + + // we should either have gone from idle to busy in the + // tryTiming test, or just gone from a retry to busy + assert(state == BUSY); + + // occupy the bus accordingly + occupyLayer(busy_time); } +template void -Bus::recvRetry(int id) +BaseBus::Layer::failedTiming(PortClass* port, Tick busy_time) { - // If there's anything waiting, and the bus isn't busy... - if (retryList.size() && curTick >= tickNextIdle) { - //retryingPort = retryList.front(); - inRetry = true; - DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); - retryList.front()->sendRetry(); - // If inRetry is still true, sendTiming wasn't called - if (inRetry) - { - retryList.front()->onRetryList(false); - retryList.pop_front(); - inRetry = false; - - //Bring tickNextIdle up to the present - while (tickNextIdle < curTick) - tickNextIdle += clock; - - //Burn a cycle for the missed grant. - tickNextIdle += clock; - - busIdle.reschedule(tickNextIdle, true); - } + // if we are not in a retry, i.e. busy (but never idle), or we are + // in a retry but not for the current port, then add the port at + // the end of the retry list + if (state != RETRY || port != retryList.front()) { + retryList.push_back(port); } - //If we weren't able to drain before, we might be able to now. - if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) { + + // even if we retried the current one and did not succeed, + // we are no longer retrying but instead busy + state = BUSY; + + // occupy the bus accordingly + occupyLayer(busy_time); +} + +template +void +BaseBus::Layer::releaseLayer() +{ + // releasing the bus means we should now be idle + assert(state == BUSY); + assert(!releaseEvent.scheduled()); + + // update the state + state = IDLE; + + // bus is now idle, so if someone is waiting we can retry + if (!retryList.empty()) { + // note that we block (return false on recvTiming) both + // because the bus is busy and because the destination is + // busy, and in the latter case the bus may be released before + // we see a retry from the destination + retryWaiting(); + } else if (drainEvent) { + DPRINTF(Drain, "Bus done draining, processing drain event\n"); + //If we weren't able to drain before, do it now. drainEvent->process(); // Clear the drain event once we're done with it. drainEvent = NULL; } } -int -Bus::findPort(Addr addr) +template +void +BaseBus::Layer::retryWaiting() { - /* An interval tree would be a better way to do this. --ali. */ - int dest_id = -1; + // this should never be called with an empty retry list + assert(!retryList.empty()); - PortIter i = portMap.find(RangeSize(addr,1)); - if (i != portMap.end()) - dest_id = i->second; + // we always go to retrying from idle + assert(state == IDLE); - // Check if this matches the default range - if (dest_id == -1) { - for (AddrRangeIter iter = defaultRange.begin(); - iter != defaultRange.end(); iter++) { - if (*iter == addr) { - DPRINTF(Bus, " found addr %#llx on default\n", addr); - return defaultId; - } - } + // update the state which is shared for request, response and + // snoop responses + state = RETRY; - if (responderSet) { - panic("Unable to find destination for addr (user set default " - "responder): %#llx", addr); - } else { - DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use " - "default port", addr); + // note that we might have blocked on the receiving port being + // busy (rather than the bus itself) and now call retry before the + // destination called retry on the bus + retryList.front()->sendRetry(); - return defaultId; - } - } + // If the bus is still in the retry state, sendTiming wasn't + // called in zero time (e.g. the cache does this) + if (state == RETRY) { + retryList.pop_front(); - return dest_id; -} + //Burn a cycle for the missed grant. + // update the state which is shared for request, response and + // snoop responses + state = BUSY; -/** Function called by the port when the bus is receiving a Atomic - * transaction.*/ -Tick -Bus::recvAtomic(PacketPtr pkt) -{ - DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", - pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); - assert(pkt->getDest() == Packet::Broadcast); - assert(pkt->isRequest()); - - // Variables for recording original command and snoop response (if - // any)... if a snooper respondes, we will need to restore - // original command so that additional snoops can take place - // properly - MemCmd orig_cmd = pkt->cmd; - MemCmd snoop_response_cmd = MemCmd::InvalidCmd; - Tick snoop_response_latency = 0; - int orig_src = pkt->getSrc(); - - int target_port_id = findPort(pkt->getAddr()); - Port *target_port = (target_port_id == defaultId) ? - defaultPort : interfaces[target_port_id]; - - SnoopIter s_end = snoopPorts.end(); - for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { - BusPort *p = *s_iter; - // same port should not have both target addresses and snooping - assert(p != target_port); - if (p->getId() != pkt->getSrc()) { - Tick latency = p->sendAtomic(pkt); - if (pkt->isResponse()) { - // response from snoop agent - assert(pkt->cmd != orig_cmd); - assert(pkt->memInhibitAsserted()); - // should only happen once - assert(snoop_response_cmd == MemCmd::InvalidCmd); - // save response state - snoop_response_cmd = pkt->cmd; - snoop_response_latency = latency; - // restore original packet state for remaining snoopers - pkt->cmd = orig_cmd; - pkt->setSrc(orig_src); - pkt->setDest(Packet::Broadcast); - } - } - } + // determine the current time rounded to the closest following + // clock edge + Tick now = bus.nextCycle(); - Tick response_latency = 0; - - // we can get requests sent up from the memory side of the bus for - // snooping... don't send them back down! - if (target_port_id != pkt->getSrc()) { - response_latency = target_port->sendAtomic(pkt); + occupyLayer(now + clock); } +} - // if we got a response from a snooper, restore it here - if (snoop_response_cmd != MemCmd::InvalidCmd) { - // no one else should have responded - assert(!pkt->isResponse()); - assert(pkt->cmd == orig_cmd); - pkt->cmd = snoop_response_cmd; - response_latency = snoop_response_latency; - } +template +void +BaseBus::Layer::recvRetry() +{ + // we got a retry from a peer that we tried to send something to + // and failed, but we sent it on the account of someone else, and + // that source port should be on our retry list, however if the + // bus layer is released before this happens and the retry (from + // the bus point of view) is successful then this no longer holds + // and we could in fact have an empty retry list + if (retryList.empty()) + return; - // why do we have this packet field and the return value both??? - pkt->finishTime = curTick + response_latency; - return response_latency; + // if the bus layer is idle + if (state == IDLE) { + // note that we do not care who told us to retry at the moment, we + // merely let the first one on the retry list go + retryWaiting(); + } } -/** Function called by the port when the bus is receiving a Functional - * transaction.*/ -void -Bus::recvFunctional(PacketPtr pkt) +PortID +BaseBus::findPort(Addr addr) { - DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", - pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); - assert(pkt->getDest() == Packet::Broadcast); - - int port_id = findPort(pkt->getAddr()); - Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id]; - // The packet may be changed by another bus on snoops, restore the - // id after each - int src_id = pkt->getSrc(); - - assert(pkt->isRequest()); // hasn't already been satisfied - - for (SnoopIter s_iter = snoopPorts.begin(); - s_iter != snoopPorts.end(); - s_iter++) { - BusPort *p = *s_iter; - if (p != port && p->getId() != src_id) { - p->sendFunctional(pkt); - } - if (pkt->isResponse()) { - break; - } - pkt->setSrc(src_id); + /* An interval tree would be a better way to do this. --ali. */ + PortID dest_id = checkPortCache(addr); + if (dest_id != InvalidPortID) + return dest_id; + + // Check normal port ranges + PortMapConstIter i = portMap.find(RangeSize(addr,1)); + if (i != portMap.end()) { + dest_id = i->second; + updatePortCache(dest_id, i->first.start, i->first.end); + return dest_id; } - // If the snooping hasn't found what we were looking for, keep going. - if (!pkt->isResponse() && port_id != pkt->getSrc()) { - port->sendFunctional(pkt); + // Check if this matches the default range + if (useDefaultRange) { + AddrRangeConstIter a_end = defaultRange.end(); + for (AddrRangeConstIter i = defaultRange.begin(); i != a_end; i++) { + if (*i == addr) { + DPRINTF(BusAddrRanges, " found addr %#llx on default\n", + addr); + return defaultPortID; + } + } + } else if (defaultPortID != InvalidPortID) { + DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " + "will use default port\n", addr); + return defaultPortID; } + + // we should use the range for the default port and it did not + // match, or the default port is not set + fatal("Unable to find destination for addr %#llx on bus %s\n", addr, + name()); } -/** Function called by the port when the bus is receiving a status change.*/ +/** Function called by the port when the bus is receiving a range change.*/ void -Bus::recvStatusChange(Port::Status status, int id) +BaseBus::recvRangeChange(PortID master_port_id) { AddrRangeList ranges; - bool snoops; AddrRangeIter iter; - assert(status == Port::RangeChange && - "The other statuses need to be implemented."); + if (inRecvRangeChange.count(master_port_id)) + return; + inRecvRangeChange.insert(master_port_id); - DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); + DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", + master_port_id); - if (id == defaultId) { + clearPortCache(); + if (master_port_id == defaultPortID) { defaultRange.clear(); // Only try to update these ranges if the user set a default responder. - if (responderSet) { - defaultPort->getPeerAddressRanges(ranges, snoops); - assert(snoops == false); + if (useDefaultRange) { + // get the address ranges of the connected slave port + AddrRangeList ranges = + masterPorts[master_port_id]->getAddrRanges(); for(iter = ranges.begin(); iter != ranges.end(); iter++) { defaultRange.push_back(*iter); DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", @@ -450,73 +381,61 @@ Bus::recvStatusChange(Port::Status status, int id) } } else { - assert((id < maxId && id >= 0) || id == defaultId); - BusPort *port = interfaces[id]; + assert(master_port_id < masterPorts.size() && master_port_id >= 0); + MasterPort *port = masterPorts[master_port_id]; // Clean out any previously existent ids - for (PortIter portIter = portMap.begin(); + for (PortMapIter portIter = portMap.begin(); portIter != portMap.end(); ) { - if (portIter->second == id) + if (portIter->second == master_port_id) portMap.erase(portIter++); else portIter++; } - for (SnoopIter s_iter = snoopPorts.begin(); - s_iter != snoopPorts.end(); ) { - if ((*s_iter)->getId() == id) - s_iter = snoopPorts.erase(s_iter); - else - s_iter++; - } - - port->getPeerAddressRanges(ranges, snoops); - - if (snoops) { - DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id); - snoopPorts.push_back(port); - } + // get the address ranges of the connected slave port + ranges = port->getAddrRanges(); for (iter = ranges.begin(); iter != ranges.end(); iter++) { DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", - iter->start, iter->end, id); - if (portMap.insert(*iter, id) == portMap.end()) - panic("Two devices with same range\n"); - + iter->start, iter->end, master_port_id); + if (portMap.insert(*iter, master_port_id) == portMap.end()) { + PortID conflict_id = portMap.find(*iter)->second; + fatal("%s has two ports with same range:\n\t%s\n\t%s\n", + name(), + masterPorts[master_port_id]->getSlavePort().name(), + masterPorts[conflict_id]->getSlavePort().name()); + } } } - DPRINTF(MMU, "port list has %d entries\n", portMap.size()); - - // tell all our peers that our address range has changed. - // Don't tell the device that caused this change, it already knows - m5::hash_map::iterator intIter; + DPRINTF(BusAddrRanges, "port list has %d entries\n", portMap.size()); - for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) - if (intIter->first != id && intIter->first != funcPortId) - intIter->second->sendStatusChange(Port::RangeChange); + // tell all our neighbouring master ports that our address range + // has changed + for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); + ++p) + (*p)->sendRangeChange(); - if (id != defaultId && defaultPort) - defaultPort->sendStatusChange(Port::RangeChange); + inRecvRangeChange.erase(master_port_id); } -void -Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) +AddrRangeList +BaseBus::getAddrRanges() const { - resp.clear(); - snoop = false; + AddrRangeList ranges; DPRINTF(BusAddrRanges, "received address range request, returning:\n"); - for (AddrRangeIter dflt_iter = defaultRange.begin(); + for (AddrRangeConstIter dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); dflt_iter++) { - resp.push_back(*dflt_iter); + ranges.push_back(*dflt_iter); DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, dflt_iter->end); } - for (PortIter portIter = portMap.begin(); + for (PortMapConstIter portIter = portMap.begin(); portIter != portMap.end(); portIter++) { bool subset = false; - for (AddrRangeIter dflt_iter = defaultRange.begin(); + for (AddrRangeConstIter dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); dflt_iter++) { if ((portIter->first.start < dflt_iter->start && portIter->first.end >= dflt_iter->start) || @@ -531,43 +450,38 @@ Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) portIter->first.start, portIter->first.end); } } - if (portIter->second != id && !subset) { - resp.push_back(portIter->first); + if (!subset) { + ranges.push_back(portIter->first); DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", portIter->first.start, portIter->first.end); } } - for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); - s_iter++) { - if ((*s_iter)->getId() != id) { - snoop = true; - break; - } - } + return ranges; } -int -Bus::findBlockSize(int id) +unsigned +BaseBus::findBlockSize() { if (cachedBlockSizeValid) return cachedBlockSize; - int max_bs = -1; + unsigned max_bs = 0; - for (PortIter portIter = portMap.begin(); - portIter != portMap.end(); portIter++) { - int tmp_bs = interfaces[portIter->second]->peerBlockSize(); + for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); + ++m) { + unsigned tmp_bs = (*m)->peerBlockSize(); if (tmp_bs > max_bs) max_bs = tmp_bs; } - for (SnoopIter s_iter = snoopPorts.begin(); - s_iter != snoopPorts.end(); s_iter++) { - int tmp_bs = (*s_iter)->peerBlockSize(); + + for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); + ++s) { + unsigned tmp_bs = (*s)->peerBlockSize(); if (tmp_bs > max_bs) max_bs = tmp_bs; } - if (max_bs <= 0) + if (max_bs == 0) max_bs = defaultBlockSize; if (max_bs != 64) @@ -577,50 +491,25 @@ Bus::findBlockSize(int id) return max_bs; } - +template unsigned int -Bus::drain(Event * de) +BaseBus::Layer::drain(Event * de) { //We should check that we're not "doing" anything, and that noone is //waiting. We might be idle but have someone waiting if the device we //contacted for a retry didn't actually retry. - if (curTick >= tickNextIdle && retryList.size() == 0) { - return 0; - } else { + if (!retryList.empty() || state != IDLE) { + DPRINTF(Drain, "Bus not drained\n"); drainEvent = de; return 1; } + return 0; } -void -Bus::startup() -{ - if (tickNextIdle < curTick) - tickNextIdle = (curTick / clock) * clock + clock; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) - - Param bus_id; - Param clock; - Param width; - Param responder_set; - Param block_size; - -END_DECLARE_SIM_OBJECT_PARAMS(Bus) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) - INIT_PARAM(bus_id, "a globally unique bus id"), - INIT_PARAM(clock, "bus clock speed"), - INIT_PARAM(width, "width of the bus (bits)"), - INIT_PARAM(responder_set, "Is a default responder set by the user"), - INIT_PARAM(block_size, "Default blocksize if no device has one") -END_INIT_SIM_OBJECT_PARAMS(Bus) - -CREATE_SIM_OBJECT(Bus) -{ - return new Bus(getInstanceName(), bus_id, clock, width, responder_set, - block_size); -} - -REGISTER_SIM_OBJECT("Bus", Bus) +/** + * Bus layer template instantiations. Could be removed with _impl.hh + * file, but since there are only two given options (MasterPort and + * SlavePort) it seems a bit excessive at this point. + */ +template class BaseBus::Layer; +template class BaseBus::Layer;