* Definition of a bus object.
*/
-
+#include <algorithm>
#include <limits>
#include "base/misc.hh"
#include "base/trace.hh"
#include "mem/bus.hh"
-#include "sim/builder.hh"
+
+Bus::Bus(const BusParams *p)
+ : MemObject(p), busId(p->bus_id), clock(p->clock),
+ headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
+ drainEvent(NULL), busIdle(this), inRetry(false), maxId(0),
+ defaultPort(NULL), funcPort(NULL), funcPortId(-4),
+ useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size),
+ cachedBlockSize(0), cachedBlockSizeValid(false)
+{
+ //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");
+ clearBusCache();
+ clearPortCache();
+}
Port *
Bus::getPort(const std::string &if_name, int idx)
if (funcPort == bp)
return;
interfaces.erase(bp->getId());
+ clearBusCache();
delete bp;
}
intIter->second->sendStatusChange(Port::RangeChange);
}
-Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus)
+Bus::BusFreeEvent::BusFreeEvent(Bus *_bus)
+ : bus(_bus)
{}
-void Bus::BusFreeEvent::process()
+void
+Bus::BusFreeEvent::process()
{
bus->recvRetry(-1);
}
-const char * Bus::BusFreeEvent::description()
+const char *
+Bus::BusFreeEvent::description() const
{
return "bus became available";
}
-void Bus::occupyBus(PacketPtr pkt)
+Tick
+Bus::calcPacketTiming(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. Anthing that happens later will have to "wait" for
- //the end of that cycle, and then start using the bus after that.
- while (tickNextIdle < curTick)
- tickNextIdle += clock;
+ // 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 = tickNextIdle + 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();
- for (int transmitted = 0; transmitted < dataSize;
- transmitted += 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);
+ pkt->firstWordTime = headerTime + clock;
+
+ pkt->finishTime = headerTime + numCycles * clock;
+
+ return headerTime;
+}
+
+void Bus::occupyBus(Tick until)
+{
+ if (until == 0) {
+ // shortcut for express snoop packets
+ return;
}
- DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
- curTick, tickNextIdle);
- // The bus will become idle once the current packet is delivered.
- pkt->finishTime = tickNextIdle;
+ tickNextIdle = until;
+ reschedule(busIdle, tickNextIdle, true);
+
+ DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
+ curTick(), tickNextIdle);
}
/** Function called by the port when the bus is receiving a Timing
bool
Bus::recvTiming(PacketPtr pkt)
{
- Port *port;
- DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s result %d\n",
- pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString(),
- pkt->result);
+ short src = pkt->getSrc();
- BusPort *pktPort;
- if (pkt->getSrc() == defaultId)
- pktPort = defaultPort;
- else pktPort = interfaces[pkt->getSrc()];
+ BusPort *src_port;
+ if (src == defaultId)
+ src_port = defaultPort;
+ else {
+ src_port = checkBusCache(src);
+ if (src_port == NULL) {
+ src_port = interfaces[src];
+ updateBusCache(src, src_port);
+ }
+ }
// 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->flags & EXPRESS_SNOOP) &&
- tickNextIdle > curTick ||
- (retryList.size() && (!inRetry || pktPort != retryList.front())))
+ if (!pkt->isExpressSnoop() &&
+ (tickNextIdle > curTick() ||
+ (retryList.size() && (!inRetry || src_port != retryList.front()))))
{
- addToRetryList(pktPort);
- DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n");
+ addToRetryList(src_port);
+ DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",
+ src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
return false;
}
+ DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",
+ src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+
+ Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
+ Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
+
short dest = pkt->getDest();
+ int dest_port_id;
+ Port *dest_port;
- // Make sure to clear the snoop commit flag so it doesn't think an
- // access has been handled twice.
if (dest == Packet::Broadcast) {
- port = findPort(pkt->getAddr(), pkt->getSrc());
- timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
-
- if (pkt->flags & SATISFIED) {
- //Cache-Cache transfer occuring
- if (inRetry) {
- retryList.front()->onRetryList(false);
- retryList.pop_front();
- inRetry = false;
+ dest_port_id = findPort(pkt->getAddr());
+ dest_port = (dest_port_id == defaultId) ?
+ defaultPort : interfaces[dest_port_id];
+ SnoopIter s_end = snoopPorts.end();
+ for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
+ BusPort *p = *s_iter;
+ if (p != dest_port && p != src_port) {
+ // cache is not allowed to refuse snoop
+ bool success M5_VAR_USED = p->sendTiming(pkt);
+ assert(success);
}
- occupyBus(pkt);
- DPRINTF(Bus, "recvTiming: Packet sucessfully sent\n");
- return true;
}
} else {
- assert(dest >= 0 && dest < maxId);
- assert(dest != pkt->getSrc()); // catch infinite loops
- port = interfaces[dest];
- }
-
- occupyBus(pkt);
-
- if (port) {
- if (port->sendTiming(pkt)) {
- // Packet was successfully sent. Return true.
- // Also take care of retries
- if (inRetry) {
- DPRINTF(Bus, "Remove retry from list %d\n",
- retryList.front()->getId());
- retryList.front()->onRetryList(false);
- retryList.pop_front();
- inRetry = false;
+ assert(dest < maxId);
+ assert(dest != src); // catch infinite loops
+ dest_port_id = dest;
+ if (dest_port_id == defaultId)
+ dest_port = defaultPort;
+ else {
+ dest_port = checkBusCache(dest);
+ if (dest_port == NULL) {
+ dest_port = interfaces[dest_port_id];
+ // updateBusCache(dest_port_id, dest_port);
}
- return true;
}
+ dest_port = (dest_port_id == defaultId) ?
+ defaultPort : interfaces[dest_port_id];
+ }
- // Packet not successfully sent. Leave or put it on the retry list.
- DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n",
- pktPort->getId());
- addToRetryList(pktPort);
- return false;
+ 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());
+ // It's also illegal to force a transaction to retry after
+ // someone else has committed to respond.
+ assert(!pkt->memInhibitAsserted());
+ DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
+ src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+ addToRetryList(src_port);
+ occupyBus(headerFinishTime);
+ return false;
+ }
+ // send OK, fall through... pkt may have been deleted by
+ // target at this point, so it should *not* be referenced
+ // again. We'll set it to NULL here just to be safe.
+ pkt = NULL;
}
- else {
- //Forwarding up from responder, just return true;
- DPRINTF(Bus, "recvTiming: can we be here?\n");
- return true;
+
+ occupyBus(packetFinishTime);
+
+ // Packet was successfully sent.
+ // Also take care of retries
+ if (inRetry) {
+ DPRINTF(Bus, "Remove retry from list %d\n", src);
+ retryList.front()->onRetryList(false);
+ retryList.pop_front();
+ inRetry = false;
}
+ return true;
}
void
Bus::recvRetry(int id)
{
- DPRINTF(Bus, "Received a retry from %s\n", id == -1 ? "self" : interfaces[id]->getPeer()->name());
// If there's anything waiting, and the bus isn't busy...
- if (retryList.size() && curTick >= tickNextIdle) {
+ if (retryList.size() && curTick() >= tickNextIdle) {
//retryingPort = retryList.front();
inRetry = true;
DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());
inRetry = false;
//Bring tickNextIdle up to the present
- while (tickNextIdle < curTick)
+ while (tickNextIdle < curTick())
tickNextIdle += clock;
//Burn a cycle for the missed grant.
tickNextIdle += clock;
- busIdle.reschedule(tickNextIdle, true);
+ reschedule(busIdle, tickNextIdle, true);
}
}
//If we weren't able to drain before, we might be able to now.
- if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) {
+ if (drainEvent && retryList.size() == 0 && curTick() >= tickNextIdle) {
drainEvent->process();
// Clear the drain event once we're done with it.
drainEvent = NULL;
}
}
-Port *
-Bus::findPort(Addr addr, int id)
+int
+Bus::findPort(Addr addr)
{
/* An interval tree would be a better way to do this. --ali. */
- int dest_id = -1;
- AddrRangeIter iter;
- range_map<Addr,int>::iterator i;
+ int dest_id;
- i = portMap.find(RangeSize(addr,1));
- if (i != portMap.end())
+ dest_id = checkPortCache(addr);
+ if (dest_id != -1)
+ return dest_id;
+
+ // Check normal port ranges
+ PortIter 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;
+ }
// Check if this matches the default range
- if (dest_id == -1) {
- for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) {
- if (*iter == addr) {
+ if (useDefaultRange) {
+ AddrRangeIter a_end = defaultRange.end();
+ for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
+ if (*i == addr) {
DPRINTF(Bus, " found addr %#llx on default\n", addr);
- return defaultPort;
+ return defaultId;
}
}
- 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);
-
- return defaultPort;
- }
+ panic("Unable to find destination for addr %#llx\n", addr);
}
-
- // we shouldn't be sending this back to where it came from
- // do the snoop access and then we should terminate
- // the cyclical call.
- if (dest_id == id)
- return 0;
-
- return interfaces[dest_id];
+ DPRINTF(Bus, "Unable to find destination for addr %#llx, "
+ "will use default port\n", addr);
+ return defaultId;
}
-std::vector<int>
-Bus::findSnoopPorts(Addr addr, int id)
-{
- int i = 0;
- AddrRangeIter iter;
- std::vector<int> ports;
-
- while (i < portSnoopList.size())
- {
- if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) {
- //Careful to not overlap ranges
- //or snoop will be called more than once on the port
-
- //@todo Fix this hack because ranges are overlapping
- //need to make sure we dont't create overlapping ranges
- bool hack_overlap = false;
- int size = ports.size();
- for (int j=0; j < size; j++) {
- if (ports[j] == portSnoopList[i].portId)
- hack_overlap = true;
- }
-
- if (!hack_overlap)
- ports.push_back(portSnoopList[i].portId);
-// DPRINTF(Bus, " found snoop addr %#llx on device%d\n", addr,
-// portSnoopList[i].portId);
- }
- i++;
- }
- return ports;
-}
+/** Function called by the port when the bus is receiving a Atomic
+ * transaction.*/
Tick
-Bus::atomicSnoop(PacketPtr pkt, Port *responder)
+Bus::recvAtomic(PacketPtr pkt)
{
- std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
- Tick response_time = 0;
+ 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());
+ BusPort *target_port;
+ if (target_port_id == defaultId)
+ target_port = defaultPort;
+ else {
+ target_port = checkBusCache(target_port_id);
+ if (target_port == NULL) {
+ target_port = interfaces[target_port_id];
+ updateBusCache(target_port_id, target_port);
+ }
+ }
- while (!ports.empty())
- {
- if (interfaces[ports.back()] != responder) {
- Tick response = interfaces[ports.back()]->sendAtomic(pkt);
- if (response) {
- assert(!response_time); //Multiple responders
- response_time = response;
+ 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);
}
}
- ports.pop_back();
}
- return response_time;
-}
-void
-Bus::functionalSnoop(PacketPtr pkt, Port *responder)
-{
- std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
+ Tick response_latency = 0;
- //The packet may be changed by another bus on snoops, restore the id after each
- int id = pkt->getSrc();
- while (!ports.empty() && pkt->result != Packet::Success)
- {
- if (interfaces[ports.back()] != responder)
- interfaces[ports.back()]->sendFunctional(pkt);
- ports.pop_back();
- pkt->setSrc(id);
+ // 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);
}
-}
-bool
-Bus::timingSnoop(PacketPtr pkt, Port* responder)
-{
- std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
- bool success = true;
-
- while (!ports.empty() && success)
- {
- if (interfaces[ports.back()] != responder) //Don't call if responder also, once will do
- success = interfaces[ports.back()]->sendTiming(pkt);
- ports.pop_back();
+ // 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;
}
- return success;
-}
-
-
-/** 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);
-
- // Assume one bus cycle in order to get through. This may have
- // some clock skew issues yet again...
- pkt->finishTime = curTick + clock;
-
- Port *port = findPort(pkt->getAddr(), pkt->getSrc());
- Tick snoopTime = atomicSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
-
- if (snoopTime)
- return snoopTime; //Snoop satisfies it
- else if (port)
- return port->sendAtomic(pkt);
- else
- return 0;
+ // why do we have this packet field and the return value both???
+ pkt->finishTime = curTick() + response_latency;
+ return response_latency;
}
/** Function called by the port when the bus is receiving a Functional
void
Bus::recvFunctional(PacketPtr pkt)
{
- DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
- pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
+ if (!pkt->isPrint()) {
+ // don't do DPRINTFs on PrintReq as it clutters up the output
+ 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);
- Port* port = findPort(pkt->getAddr(), pkt->getSrc());
- functionalSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
+ 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
+
+ SnoopIter s_end = snoopPorts.end();
+ for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_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);
+ }
- // If the snooping found what we were looking for, we're done.
- if (pkt->result != Packet::Success && port) {
+ // If the snooping hasn't found what we were looking for, keep going.
+ if (!pkt->isResponse() && port_id != pkt->getSrc()) {
port->sendFunctional(pkt);
}
}
Bus::recvStatusChange(Port::Status status, int id)
{
AddrRangeList ranges;
- AddrRangeList snoops;
+ bool snoops;
AddrRangeIter iter;
+ if (inRecvStatusChange.count(id))
+ return;
+ inRecvStatusChange.insert(id);
+
assert(status == Port::RangeChange &&
"The other statuses need to be implemented.");
DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
+ clearPortCache();
if (id == defaultId) {
defaultRange.clear();
// Only try to update these ranges if the user set a default responder.
- if (responderSet) {
+ if (useDefaultRange) {
defaultPort->getPeerAddressRanges(ranges, snoops);
- assert(snoops.size() == 0);
+ assert(snoops == false);
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
defaultRange.push_back(*iter);
DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
} else {
assert((id < maxId && id >= 0) || id == defaultId);
- Port *port = interfaces[id];
- range_map<Addr,int>::iterator portIter;
- std::vector<DevMap>::iterator snoopIter;
+ BusPort *port = interfaces[id];
// Clean out any previously existent ids
- for (portIter = portMap.begin(); portIter != portMap.end(); ) {
+ for (PortIter portIter = portMap.begin();
+ portIter != portMap.end(); ) {
if (portIter->second == id)
portMap.erase(portIter++);
else
portIter++;
}
- for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) {
- if (snoopIter->portId == id)
- snoopIter = portSnoopList.erase(snoopIter);
+ for (SnoopIter s_iter = snoopPorts.begin();
+ s_iter != snoopPorts.end(); ) {
+ if ((*s_iter)->getId() == id)
+ s_iter = snoopPorts.erase(s_iter);
else
- snoopIter++;
+ s_iter++;
}
port->getPeerAddressRanges(ranges, snoops);
- for(iter = snoops.begin(); iter != snoops.end(); iter++) {
- DevMap dm;
- dm.portId = id;
- dm.range = *iter;
-
- //@todo, make sure we don't overlap ranges
- DPRINTF(BusAddrRanges, "Adding snoop range %#llx - %#llx for id %d\n",
- dm.range.start, dm.range.end, id);
- portSnoopList.push_back(dm);
+ if (snoops) {
+ DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id);
+ snoopPorts.push_back(port);
}
- for(iter = ranges.begin(); iter != ranges.end(); iter++) {
+ 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");
-
+ if (portMap.insert(*iter, id) == portMap.end()) {
+ int conflict_id = portMap.find(*iter)->second;
+ fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
+ name(), interfaces[id]->getPeer()->name(),
+ interfaces[conflict_id]->getPeer()->name());
+ }
}
}
DPRINTF(MMU, "port list has %d entries\n", portMap.size());
if (id != defaultId && defaultPort)
defaultPort->sendStatusChange(Port::RangeChange);
+ inRecvStatusChange.erase(id);
}
void
-Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
+Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id)
{
- std::vector<DevMap>::iterator snoopIter;
- range_map<Addr,int>::iterator portIter;
- AddrRangeIter dflt_iter;
- bool subset;
-
resp.clear();
- snoop.clear();
+ snoop = false;
DPRINTF(BusAddrRanges, "received address range request, returning:\n");
- for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
- dflt_iter++) {
+ for (AddrRangeIter dflt_iter = defaultRange.begin();
+ dflt_iter != defaultRange.end(); dflt_iter++) {
resp.push_back(*dflt_iter);
DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start,
dflt_iter->end);
}
- for (portIter = portMap.begin(); portIter != portMap.end(); portIter++) {
- subset = false;
- for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
- dflt_iter++) {
+ for (PortIter portIter = portMap.begin();
+ portIter != portMap.end(); portIter++) {
+ bool subset = false;
+ for (AddrRangeIter dflt_iter = defaultRange.begin();
+ dflt_iter != defaultRange.end(); dflt_iter++) {
if ((portIter->first.start < dflt_iter->start &&
portIter->first.end >= dflt_iter->start) ||
(portIter->first.start < dflt_iter->end &&
}
}
- for (snoopIter = portSnoopList.begin();
- snoopIter != portSnoopList.end(); snoopIter++)
- {
- if (snoopIter->portId != id) {
- snoop.push_back(snoopIter->range);
- DPRINTF(BusAddrRanges, " -- Snoop: %#llx : %#llx\n",
- snoopIter->range.start, snoopIter->range.end);
- //@todo We need to properly insert snoop ranges
- //not overlapping the ranges (multiple)
+ for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end();
+ s_iter++) {
+ if ((*s_iter)->getId() != id) {
+ snoop = true;
+ break;
}
}
}
-int
+unsigned
Bus::findBlockSize(int id)
{
if (cachedBlockSizeValid)
return cachedBlockSize;
- int max_bs = -1, tmp_bs;
- range_map<Addr,int>::iterator portIter;
- std::vector<DevMap>::iterator snoopIter;
- for (portIter = portMap.begin(); portIter != portMap.end(); portIter++) {
- tmp_bs = interfaces[portIter->second]->peerBlockSize();
+ unsigned max_bs = 0;
+
+ PortIter p_end = portMap.end();
+ for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
+ unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize();
if (tmp_bs > max_bs)
max_bs = tmp_bs;
}
- for (snoopIter = portSnoopList.begin();
- snoopIter != portSnoopList.end(); snoopIter++) {
- tmp_bs = interfaces[snoopIter->portId]->peerBlockSize();
+ SnoopIter s_end = snoopPorts.end();
+ for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
+ unsigned tmp_bs = (*s_iter)->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)
//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.size() || (curTick() < tickNextIdle && busIdle.scheduled())) {
drainEvent = de;
return 1;
}
+ return 0;
}
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
-
- Param<int> bus_id;
- Param<int> clock;
- Param<int> width;
- Param<bool> responder_set;
- Param<int> 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)
+void
+Bus::startup()
{
- return new Bus(getInstanceName(), bus_id, clock, width, responder_set,
- block_size);
+ if (tickNextIdle < curTick())
+ tickNextIdle = (curTick() / clock) * clock + clock;
}
-REGISTER_SIM_OBJECT("Bus", Bus)
+Bus *
+BusParams::create()
+{
+ return new Bus(this);
+}