summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
authorAndreas Hansson <andreas.hansson@arm.com>2012-05-31 13:30:04 -0400
committerAndreas Hansson <andreas.hansson@arm.com>2012-05-31 13:30:04 -0400
commit0d329407116921cd9aed6f02da551cc5a8ec5131 (patch)
tree6cc534a94543ed1e40c65d502cd428338eabb94d /src/mem
parentfb9bfb9cfcb6ef5db6881b769c7011ff4907f219 (diff)
downloadgem5-0d329407116921cd9aed6f02da551cc5a8ec5131.tar.xz
Bus: Split the bus into a non-coherent and coherent bus
This patch introduces a class hierarchy of buses, a non-coherent one, and a coherent one, splitting the existing bus functionality. By doing so it also enables further specialisation of the two types of buses. A non-coherent bus connects a number of non-snooping masters and slaves, and routes the request and response packets based on the address. The request packets issued by the master connected to a non-coherent bus could still snoop in caches attached to a coherent bus, as is the case with the I/O bus and memory bus in most system configurations. No snoops will, however, reach any master on the non-coherent bus itself. The non-coherent bus can be used as a template for modelling PCI, PCIe, and non-coherent AMBA and OCP buses, and is typically used for the I/O buses. A coherent bus connects a number of (potentially) snooping masters and slaves, and routes the request and response packets based on the address, and also forwards all requests to the snoopers and deals with the snoop responses. The coherent bus can be used as a template for modelling QPI, HyperTransport, ACE and coherent OCP buses, and is typically used for the L1-to-L2 buses and as the main system interconnect. The configuration scripts are updated to use a NoncoherentBus for all peripheral and I/O buses. A bit of minor tidying up has also been done. --HG-- rename : src/mem/bus.cc => src/mem/coherent_bus.cc rename : src/mem/bus.hh => src/mem/coherent_bus.hh rename : src/mem/bus.cc => src/mem/noncoherent_bus.cc rename : src/mem/bus.hh => src/mem/noncoherent_bus.hh
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/Bus.py48
-rw-r--r--src/mem/SConscript9
-rw-r--r--src/mem/bus.cc492
-rw-r--r--src/mem/bus.hh247
-rw-r--r--src/mem/coherent_bus.cc493
-rw-r--r--src/mem/coherent_bus.hh290
-rw-r--r--src/mem/noncoherent_bus.cc209
-rw-r--r--src/mem/noncoherent_bus.hh201
8 files changed, 1293 insertions, 696 deletions
diff --git a/src/mem/Bus.py b/src/mem/Bus.py
index 91043da80..05033d382 100644
--- a/src/mem/Bus.py
+++ b/src/mem/Bus.py
@@ -1,3 +1,15 @@
+# Copyright (c) 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) 2005-2008 The Regents of The University of Michigan
# All rights reserved.
#
@@ -25,22 +37,36 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
+# Andreas Hansson
-from m5.defines import buildEnv
-from m5.params import *
-from m5.proxy import *
from MemObject import MemObject
+from m5.params import *
-class Bus(MemObject):
- type = 'Bus'
+class BaseBus(MemObject):
+ type = 'BaseBus'
+ abstract = True
slave = VectorSlavePort("vector port for connecting masters")
master = VectorMasterPort("vector port for connecting slaves")
- bus_id = Param.Int(0, "blah")
clock = Param.Clock("1GHz", "bus clock speed")
header_cycles = Param.Int(1, "cycles of overhead per transaction")
width = Param.Int(64, "bus width (bytes)")
- block_size = Param.Int(64, "The default block size if one isn't set by a device attached to the bus.")
- default = MasterPort("Default port for requests that aren't handled " \
- "by a device.")
- use_default_range = \
- Param.Bool(False, "Query default port device for legal range.")
+ block_size = Param.Int(64, "The default block size if not set by " \
+ "any connected module")
+
+ # The default port can be left unconnected, or be used to connect
+ # a default slave port
+ default = MasterPort("Port for connecting an optional default slave")
+
+ # The default port can be used unconditionally, or based on
+ # address range, in which case it may overlap with other
+ # ports. The default range is always checked first, thus creating
+ # a two-level hierarchical lookup. This is useful e.g. for the PCI
+ # bus configuration.
+ use_default_range = Param.Bool(False, "Perform address mapping for " \
+ "the default port")
+
+class NoncoherentBus(BaseBus):
+ type = 'NoncoherentBus'
+
+class CoherentBus(BaseBus):
+ type = 'CoherentBus'
diff --git a/src/mem/SConscript b/src/mem/SConscript
index 3ffb3503a..1961204f7 100644
--- a/src/mem/SConscript
+++ b/src/mem/SConscript
@@ -37,9 +37,11 @@ SimObject('MemObject.py')
Source('bridge.cc')
Source('bus.cc')
+Source('coherent_bus.cc')
Source('comm_monitor.cc')
Source('mem_object.cc')
Source('mport.cc')
+Source('noncoherent_bus.cc')
Source('packet.cc')
Source('port.cc')
Source('packet_queue.cc')
@@ -56,8 +58,13 @@ if env['TARGET_ISA'] != 'no':
Source('page_table.cc')
Source('physical.cc')
-DebugFlag('Bus')
+DebugFlag('BaseBus')
DebugFlag('BusAddrRanges')
+DebugFlag('CoherentBus')
+DebugFlag('NoncoherentBus')
+CompoundFlag('Bus', ['BaseBus', 'BusAddrRanges', 'CoherentBus',
+ 'NoncoherentBus'])
+
DebugFlag('BusBridge')
DebugFlag('CommMonitor')
DebugFlag('LLSC')
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index a22b0e7fd..8040118d2 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -53,7 +53,7 @@
#include "debug/BusAddrRanges.hh"
#include "mem/bus.hh"
-Bus::Bus(const BusParams *p)
+BaseBus::BaseBus(const BaseBusParams *p)
: MemObject(p), clock(p->clock),
headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
drainEvent(NULL), busIdleEvent(this), inRetry(false),
@@ -69,37 +69,23 @@ Bus::Bus(const BusParams *p)
fatal("Bus clock period must be positive\n");
if (headerCycles <= 0)
fatal("Number of header cycles must be positive\n");
+}
- // create the ports based on the size of the master and slave
- // vector ports, and the presence of the default port, the ports
- // are enumerated starting from zero
- for (int i = 0; i < p->port_master_connection_count; ++i) {
- std::string portName = csprintf("%s-p%d", name(), i);
- MasterPort* bp = new BusMasterPort(portName, this, i);
- masterPorts.push_back(bp);
- }
-
- // see if we have a default slave device connected and if so add
- // our corresponding master port
- if (p->port_default_connection_count) {
- defaultPortID = masterPorts.size();
- std::string portName = csprintf("%s-default", name());
- MasterPort* bp = new BusMasterPort(portName, this, defaultPortID);
- masterPorts.push_back(bp);
+BaseBus::~BaseBus()
+{
+ for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end();
+ ++m) {
+ delete *m;
}
- // create the slave ports, once again starting at zero
- for (int i = 0; i < p->port_slave_connection_count; ++i) {
- std::string portName = csprintf("%s-p%d", name(), i);
- SlavePort* bp = new BusSlavePort(portName, this, i);
- slavePorts.push_back(bp);
+ for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end();
+ ++s) {
+ delete *s;
}
-
- clearPortCache();
}
MasterPort &
-Bus::getMasterPort(const std::string &if_name, int idx)
+BaseBus::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "master" && idx < masterPorts.size()) {
// the master port index translates directly to the vector position
@@ -112,7 +98,7 @@ Bus::getMasterPort(const std::string &if_name, int idx)
}
SlavePort &
-Bus::getSlavePort(const std::string &if_name, int idx)
+BaseBus::getSlavePort(const std::string &if_name, int idx)
{
if (if_name == "slave" && idx < slavePorts.size()) {
// the slave port index translates directly to the vector position
@@ -122,23 +108,8 @@ Bus::getSlavePort(const std::string &if_name, int idx)
}
}
-void
-Bus::init()
-{
- // iterate over our slave ports and determine which of our
- // neighbouring master ports are snooping and add them as snoopers
- for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end();
- ++p) {
- if ((*p)->getMasterPort().isSnooping()) {
- DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
- (*p)->getMasterPort().name());
- snoopPorts.push_back(*p);
- }
- }
-}
-
Tick
-Bus::calcPacketTiming(PacketPtr pkt)
+BaseBus::calcPacketTiming(PacketPtr pkt)
{
// determine the current time rounded to the closest following
// clock edge
@@ -169,7 +140,7 @@ Bus::calcPacketTiming(PacketPtr pkt)
return headerTime;
}
-void Bus::occupyBus(Tick until)
+void BaseBus::occupyBus(Tick until)
{
if (until == 0) {
// shortcut for express snoop packets
@@ -179,12 +150,12 @@ void Bus::occupyBus(Tick until)
tickNextIdle = until;
reschedule(busIdleEvent, tickNextIdle, true);
- DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
+ DPRINTF(BaseBus, "The bus is now occupied from tick %d to %d\n",
curTick(), tickNextIdle);
}
bool
-Bus::isOccupied(Port* port)
+BaseBus::isOccupied(Port* port)
{
// first we see if the next idle tick is in the future, next the
// bus is considered occupied if there are ports on the retry list
@@ -197,220 +168,15 @@ Bus::isOccupied(Port* port)
return false;
}
-bool
-Bus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
-{
- // determine the source port based on the id
- SlavePort *src_port = slavePorts[slave_port_id];
-
- // test if the bus should be considered occupied for the current
- // port, and exclude express snoops from the check
- if (!pkt->isExpressSnoop() && isOccupied(src_port)) {
- DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x BUSY\n",
- src_port->name(), pkt->cmdString(), pkt->getAddr());
- return false;
- }
-
- DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x\n",
- src_port->name(), pkt->cmdString(), pkt->getAddr());
-
- // set the source port for routing of the response
- pkt->setSrc(slave_port_id);
-
- Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
- Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
-
- // uncacheable requests need never be snooped
- if (!pkt->req->isUncacheable()) {
- // the packet is a memory-mapped request and should be
- // broadcasted to our snoopers but the source
- forwardTiming(pkt, slave_port_id);
- }
-
- // remember if we add an outstanding req so we can undo it if
- // necessary, if the packet needs a response, we should add it
- // as outstanding and express snoops never fail so there is
- // not need to worry about them
- bool add_outstanding = !pkt->isExpressSnoop() && pkt->needsResponse();
-
- // keep track that we have an outstanding request packet
- // matching this request, this is used by the coherency
- // mechanism in determining what to do with snoop responses
- // (in recvTimingSnoop)
- if (add_outstanding) {
- // we should never have an exsiting request outstanding
- assert(outstandingReq.find(pkt->req) == outstandingReq.end());
- outstandingReq.insert(pkt->req);
- }
-
- // since it is a normal request, determine the destination
- // based on the address and attempt to send the packet
- bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt);
-
- if (!success) {
- // inhibited packets should never be forced to retry
- assert(!pkt->memInhibitAsserted());
-
- // if it was added as outstanding and the send failed, then
- // erase it again
- if (add_outstanding)
- outstandingReq.erase(pkt->req);
-
- DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x RETRY\n",
- src_port->name(), pkt->cmdString(), pkt->getAddr());
-
- addToRetryList(src_port);
- occupyBus(headerFinishTime);
-
- return false;
- }
-
- succeededTiming(packetFinishTime);
-
- return true;
-}
-
-bool
-Bus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
-{
- // determine the source port based on the id
- MasterPort *src_port = masterPorts[master_port_id];
-
- // test if the bus should be considered occupied for the current
- // port
- if (isOccupied(src_port)) {
- DPRINTF(Bus, "recvTimingResp: src %s %s 0x%x BUSY\n",
- src_port->name(), pkt->cmdString(), pkt->getAddr());
- return false;
- }
-
- DPRINTF(Bus, "recvTimingResp: src %s %s 0x%x\n",
- src_port->name(), pkt->cmdString(), pkt->getAddr());
-
- calcPacketTiming(pkt);
- Tick packetFinishTime = pkt->finishTime;
-
- // the packet is a normal response to a request that we should
- // have seen passing through the bus
- assert(outstandingReq.find(pkt->req) != outstandingReq.end());
-
- // remove it as outstanding
- outstandingReq.erase(pkt->req);
-
- // send the packet to the destination through one of our slave
- // ports, as determined by the destination field
- bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt);
-
- // currently it is illegal to block responses... can lead to
- // deadlock
- assert(success);
-
- succeededTiming(packetFinishTime);
-
- return true;
-}
-
void
-Bus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id)
-{
- DPRINTF(Bus, "recvTimingSnoopReq: src %s %s 0x%x\n",
- masterPorts[master_port_id]->name(), pkt->cmdString(),
- pkt->getAddr());
-
- // we should only see express snoops from caches
- assert(pkt->isExpressSnoop());
-
- // set the source port for routing of the response
- pkt->setSrc(master_port_id);
-
- // forward to all snoopers
- forwardTiming(pkt, InvalidPortID);
-
- // a snoop request came from a connected slave device (one of
- // our master ports), and if it is not coming from the slave
- // device responsible for the address range something is
- // wrong, hence there is nothing further to do as the packet
- // would be going back to where it came from
- assert(master_port_id == findPort(pkt->getAddr()));
-
- // this is an express snoop and is never forced to retry
- assert(!inRetry);
-}
-
-bool
-Bus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
-{
- // determine the source port based on the id
- SlavePort* src_port = slavePorts[slave_port_id];
-
- // test if the bus should be considered occupied for the current
- // port
- if (isOccupied(src_port)) {
- DPRINTF(Bus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
- src_port->name(), pkt->cmdString(), pkt->getAddr());
- return false;
- }
-
- DPRINTF(Bus, "recvTimingSnoop: src %s %s 0x%x\n",
- src_port->name(), pkt->cmdString(), pkt->getAddr());
-
- // get the destination from the packet
- PortID dest = pkt->getDest();
-
- // responses are never express snoops
- assert(!pkt->isExpressSnoop());
-
- calcPacketTiming(pkt);
- Tick packetFinishTime = pkt->finishTime;
-
- // determine if the response is from a snoop request we
- // created as the result of a normal request (in which case it
- // should be in the outstandingReq), or if we merely forwarded
- // someone else's snoop request
- if (outstandingReq.find(pkt->req) == outstandingReq.end()) {
- // this is a snoop response to a snoop request we
- // forwarded, e.g. coming from the L1 and going to the L2
- // this should be forwarded as a snoop response
- bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt);
- assert(success);
- } else {
- // we got a snoop response on one of our slave ports,
- // i.e. from a coherent master connected to the bus, and
- // since we created the snoop request as part of
- // recvTiming, this should now be a normal response again
- outstandingReq.erase(pkt->req);
-
- // this is a snoop response from a coherent master, with a
- // destination field set on its way through the bus as
- // request, hence it should never go back to where the
- // snoop response came from, but instead to where the
- // original request came from
- assert(slave_port_id != dest);
-
- // as a normal response, it should go back to a master
- // through one of our slave ports
- bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt);
-
- // currently it is illegal to block responses... can lead
- // to deadlock
- assert(success);
- }
-
- succeededTiming(packetFinishTime);
-
- return true;
-}
-
-
-void
-Bus::succeededTiming(Tick busy_time)
+BaseBus::succeededTiming(Tick busy_time)
{
// occupy the bus accordingly
occupyBus(busy_time);
// if a retrying port succeeded, also take it off the retry list
if (inRetry) {
- DPRINTF(Bus, "Remove retry from list %s\n",
+ DPRINTF(BaseBus, "Remove retry from list %s\n",
retryList.front()->name());
retryList.pop_front();
inRetry = false;
@@ -418,24 +184,7 @@ Bus::succeededTiming(Tick busy_time)
}
void
-Bus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
-{
- for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
- SlavePort *p = *s;
- // we could have gotten this request from a snooping master
- // (corresponding to our own slave port that is also in
- // snoopPorts) and should not send it back to where it came
- // from
- if (exclude_slave_port_id == InvalidPortID ||
- p->getId() != exclude_slave_port_id) {
- // cache is not allowed to refuse snoop
- p->sendTimingSnoopReq(pkt);
- }
- }
-}
-
-void
-Bus::releaseBus()
+BaseBus::releaseBus()
{
// releasing the bus means we should now be idle
assert(curTick() >= tickNextIdle);
@@ -458,7 +207,7 @@ Bus::releaseBus()
}
void
-Bus::retryWaiting()
+BaseBus::retryWaiting()
{
// this should never be called with an empty retry list
assert(!retryList.empty());
@@ -489,7 +238,7 @@ Bus::retryWaiting()
}
void
-Bus::recvRetry()
+BaseBus::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
@@ -509,7 +258,7 @@ Bus::recvRetry()
}
PortID
-Bus::findPort(Addr addr)
+BaseBus::findPort(Addr addr)
{
/* An interval tree would be a better way to do this. --ali. */
PortID dest_id = checkPortCache(addr);
@@ -529,12 +278,13 @@ Bus::findPort(Addr addr)
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);
+ DPRINTF(BusAddrRanges, " found addr %#llx on default\n",
+ addr);
return defaultPortID;
}
}
} else if (defaultPortID != InvalidPortID) {
- DPRINTF(Bus, "Unable to find destination for addr %#llx, "
+ DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, "
"will use default port\n", addr);
return defaultPortID;
}
@@ -545,170 +295,9 @@ Bus::findPort(Addr addr)
name());
}
-Tick
-Bus::recvAtomic(PacketPtr pkt, PortID slave_port_id)
-{
- DPRINTF(Bus, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
- slavePorts[slave_port_id]->name(), pkt->getAddr(),
- pkt->cmdString());
-
- MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
- Tick snoop_response_latency = 0;
-
- // uncacheable requests need never be snooped
- if (!pkt->req->isUncacheable()) {
- // forward to all snoopers but the source
- std::pair<MemCmd, Tick> snoop_result =
- forwardAtomic(pkt, slave_port_id);
- snoop_response_cmd = snoop_result.first;
- snoop_response_latency = snoop_result.second;
- }
-
- // even if we had a snoop response, we must continue and also
- // perform the actual request at the destination
- PortID dest_id = findPort(pkt->getAddr());
-
- // forward the request to the appropriate destination
- Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
-
- // 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());
- pkt->cmd = snoop_response_cmd;
- response_latency = snoop_response_latency;
- }
-
- pkt->finishTime = curTick() + response_latency;
- return response_latency;
-}
-
-Tick
-Bus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id)
-{
- DPRINTF(Bus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n",
- masterPorts[master_port_id]->name(), pkt->getAddr(),
- pkt->cmdString());
-
- // forward to all snoopers
- std::pair<MemCmd, Tick> snoop_result =
- forwardAtomic(pkt, InvalidPortID);
- MemCmd snoop_response_cmd = snoop_result.first;
- Tick snoop_response_latency = snoop_result.second;
-
- if (snoop_response_cmd != MemCmd::InvalidCmd)
- pkt->cmd = snoop_response_cmd;
-
- pkt->finishTime = curTick() + snoop_response_latency;
- return snoop_response_latency;
-}
-
-std::pair<MemCmd, Tick>
-Bus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
-{
- // the packet may be changed on snoops, record the original
- // command to enable us to restore it between snoops so that
- // additional snoops can take place properly
- MemCmd orig_cmd = pkt->cmd;
- MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
- Tick snoop_response_latency = 0;
-
- for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
- SlavePort *p = *s;
- // we could have gotten this request from a snooping master
- // (corresponding to our own slave port that is also in
- // snoopPorts) and should not send it back to where it came
- // from
- if (exclude_slave_port_id == InvalidPortID ||
- p->getId() != exclude_slave_port_id) {
- Tick latency = p->sendAtomicSnoop(pkt);
- // in contrast to a functional access, we have to keep on
- // going as all snoopers must be updated even if we get a
- // response
- 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;
- }
- }
- }
-
- // the packet is restored as part of the loop and any potential
- // snoop response is part of the returned pair
- return std::make_pair(snoop_response_cmd, snoop_response_latency);
-}
-
-void
-Bus::recvFunctional(PacketPtr pkt, PortID slave_port_id)
-{
- if (!pkt->isPrint()) {
- // don't do DPRINTFs on PrintReq as it clutters up the output
- DPRINTF(Bus,
- "recvFunctional: packet src %s addr 0x%x cmd %s\n",
- slavePorts[slave_port_id]->name(), pkt->getAddr(),
- pkt->cmdString());
- }
-
- // uncacheable requests need never be snooped
- if (!pkt->req->isUncacheable()) {
- // forward to all snoopers but the source
- forwardFunctional(pkt, slave_port_id);
- }
-
- // there is no need to continue if the snooping has found what we
- // were looking for and the packet is already a response
- if (!pkt->isResponse()) {
- PortID dest_id = findPort(pkt->getAddr());
-
- masterPorts[dest_id]->sendFunctional(pkt);
- }
-}
-
-void
-Bus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id)
-{
- if (!pkt->isPrint()) {
- // don't do DPRINTFs on PrintReq as it clutters up the output
- DPRINTF(Bus,
- "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n",
- masterPorts[master_port_id]->name(), pkt->getAddr(),
- pkt->cmdString());
- }
-
- // forward to all snoopers
- forwardFunctional(pkt, InvalidPortID);
-}
-
-void
-Bus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
-{
- for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
- SlavePort *p = *s;
- // we could have gotten this request from a snooping master
- // (corresponding to our own slave port that is also in
- // snoopPorts) and should not send it back to where it came
- // from
- if (exclude_slave_port_id == InvalidPortID ||
- p->getId() != exclude_slave_port_id)
- p->sendFunctionalSnoop(pkt);
-
- // if we get a response we are done
- if (pkt->isResponse()) {
- break;
- }
- }
-}
-
/** Function called by the port when the bus is receiving a range change.*/
void
-Bus::recvRangeChange(PortID master_port_id)
+BaseBus::recvRangeChange(PortID master_port_id)
{
AddrRangeList ranges;
AddrRangeIter iter;
@@ -773,7 +362,7 @@ Bus::recvRangeChange(PortID master_port_id)
}
AddrRangeList
-Bus::getAddrRanges()
+BaseBus::getAddrRanges()
{
AddrRangeList ranges;
@@ -813,29 +402,22 @@ Bus::getAddrRanges()
return ranges;
}
-bool
-Bus::isSnooping() const
-{
- // in essence, answer the question if there are snooping ports
- return !snoopPorts.empty();
-}
-
unsigned
-Bus::findBlockSize()
+BaseBus::findBlockSize()
{
if (cachedBlockSizeValid)
return cachedBlockSize;
unsigned max_bs = 0;
- PortIter p_end = portMap.end();
- for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
- unsigned tmp_bs = masterPorts[p_iter->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 (SlavePortConstIter s = snoopPorts.begin(); s != snoopPorts.end();
+ for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end();
++s) {
unsigned tmp_bs = (*s)->peerBlockSize();
if (tmp_bs > max_bs)
@@ -853,7 +435,7 @@ Bus::findBlockSize()
unsigned int
-Bus::drain(Event * de)
+BaseBus::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
@@ -867,14 +449,8 @@ Bus::drain(Event * de)
}
void
-Bus::startup()
+BaseBus::startup()
{
if (tickNextIdle < curTick())
tickNextIdle = (curTick() / clock) * clock + clock;
}
-
-Bus *
-BusParams::create()
-{
- return new Bus(this);
-}
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
index c35b46cc2..4f0e44b1c 100644
--- a/src/mem/bus.hh
+++ b/src/mem/bus.hh
@@ -45,7 +45,7 @@
/**
* @file
- * Declaration of a bus object.
+ * Declaration of an abstract bus base class.
*/
#ifndef __MEM_BUS_HH__
@@ -53,155 +53,26 @@
#include <list>
#include <set>
-#include <string>
#include "base/range.hh"
#include "base/range_map.hh"
#include "base/types.hh"
#include "mem/mem_object.hh"
-#include "mem/packet.hh"
-#include "mem/port.hh"
-#include "params/Bus.hh"
-#include "sim/eventq.hh"
+#include "params/BaseBus.hh"
-class Bus : public MemObject
+/**
+ * The base bus contains the common elements of the non-coherent and
+ * coherent bus. It is an abstract class that does not have any of the
+ * functionality relating to the actual reception and transmission of
+ * packets, as this is left for the subclasses.
+ *
+ * The BaseBus is responsible for the basic flow control (busy or
+ * not), the administration of retries, and the address decoding.
+ */
+class BaseBus : public MemObject
{
- /**
- * Declaration of the bus slave port type, one will be
- * instantiated for each of the master interfaces connecting to
- * the bus.
- */
- class BusSlavePort : public SlavePort
- {
- private:
- /** A pointer to the bus to which this port belongs. */
- Bus *bus;
-
- public:
-
- /** Constructor for the BusSlavePort.*/
- BusSlavePort(const std::string &_name, Bus *_bus, PortID _id)
- : SlavePort(_name, _bus, _id), bus(_bus)
- { }
-
- protected:
-
- /**
- * When receiving a timing request, pass it to the bus.
- */
- virtual bool recvTimingReq(PacketPtr pkt)
- { return bus->recvTimingReq(pkt, id); }
-
- /**
- * When receiving a timing snoop response, pass it to the bus.
- */
- virtual bool recvTimingSnoopResp(PacketPtr pkt)
- { return bus->recvTimingSnoopResp(pkt, id); }
-
- /**
- * When receiving an atomic request, pass it to the bus.
- */
- virtual Tick recvAtomic(PacketPtr pkt)
- { return bus->recvAtomic(pkt, id); }
-
- /**
- * When receiving a functional request, pass it to the bus.
- */
- virtual void recvFunctional(PacketPtr pkt)
- { bus->recvFunctional(pkt, id); }
-
- /**
- * When receiving a retry, pass it to the bus.
- */
- virtual void recvRetry()
- { panic("Bus slave ports always succeed and should never retry.\n"); }
-
- // This should return all the 'owned' addresses that are
- // downstream from this bus, yes? That is, the union of all
- // the 'owned' address ranges of all the other interfaces on
- // this bus...
- virtual AddrRangeList getAddrRanges()
- { return bus->getAddrRanges(); }
-
- // Ask the bus to ask everyone on the bus what their block size is and
- // take the max of it. This might need to be changed a bit if we ever
- // support multiple block sizes.
- virtual unsigned deviceBlockSize() const
- { return bus->findBlockSize(); }
-
- };
-
- /**
- * Declaration of the bus master port type, one will be
- * instantiated for each of the slave interfaces connecting to the
- * bus.
- */
- class BusMasterPort : public MasterPort
- {
- private:
- /** A pointer to the bus to which this port belongs. */
- Bus *bus;
-
- public:
-
- /** Constructor for the BusMasterPort.*/
- BusMasterPort(const std::string &_name, Bus *_bus, PortID _id)
- : MasterPort(_name, _bus, _id), bus(_bus)
- { }
-
- /**
- * Determine if this port should be considered a snooper. This
- * is determined by the bus.
- *
- * @return a boolean that is true if this port is snooping
- */
- virtual bool isSnooping() const
- { return bus->isSnooping(); }
-
- protected:
-
- /**
- * When receiving a timing response, pass it to the bus.
- */
- virtual bool recvTimingResp(PacketPtr pkt)
- { return bus->recvTimingResp(pkt, id); }
-
- /**
- * When receiving a timing snoop request, pass it to the bus.
- */
- virtual void recvTimingSnoopReq(PacketPtr pkt)
- { return bus->recvTimingSnoopReq(pkt, id); }
-
- /**
- * When receiving an atomic snoop request, pass it to the bus.
- */
- virtual Tick recvAtomicSnoop(PacketPtr pkt)
- { return bus->recvAtomicSnoop(pkt, id); }
-
- /**
- * When receiving a functional snoop request, pass it to the bus.
- */
- virtual void recvFunctionalSnoop(PacketPtr pkt)
- { bus->recvFunctionalSnoop(pkt, id); }
-
- /** When reciving a range change from the peer port (at id),
- pass it to the bus. */
- virtual void recvRangeChange()
- { bus->recvRangeChange(id); }
-
- /** When reciving a retry from the peer port (at id),
- pass it to the bus. */
- virtual void recvRetry()
- { bus->recvRetry(); }
-
- // Ask the bus to ask everyone on the bus what their block size is and
- // take the max of it. This might need to be changed a bit if we ever
- // support multiple block sizes.
- virtual unsigned deviceBlockSize() const
- { return bus->findBlockSize(); }
-
- };
+ protected:
/** the clock speed for the bus */
int clock;
@@ -219,41 +90,6 @@ class Bus : public MemObject
AddrRangeList defaultRange;
- std::vector<SlavePort*> snoopPorts;
-
- /**
- * Store the outstanding requests so we can determine which ones
- * we generated and which ones were merely forwarded. This is used
- * in the coherent bus when coherency responses come back.
- */
- std::set<RequestPtr> outstandingReq;
-
- /** Function called by the port when the bus is recieving a Timing
- request packet.*/
- bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
-
- /** Function called by the port when the bus is recieving a Timing
- response packet.*/
- bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
-
- /** Function called by the port when the bus is recieving a timing
- snoop request.*/
- void recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id);
-
- /** Function called by the port when the bus is recieving a timing
- snoop response.*/
- bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id);
-
- /**
- * Forward a timing packet to our snoopers, potentially excluding
- * one of the connected coherent masters to avoid sending a packet
- * back to where it came from.
- *
- * @param pkt Packet to forward
- * @param exclude_slave_port_id Id of slave port to exclude
- */
- void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id);
-
/**
* Determine if the bus is to be considered occupied when being
* presented with a packet from a specific port. If so, the port
@@ -274,45 +110,6 @@ class Bus : public MemObject
*/
void succeededTiming(Tick busy_time);
- /** Function called by the port when the bus is recieving a Atomic
- transaction.*/
- Tick recvAtomic(PacketPtr pkt, PortID slave_port_id);
-
- /** Function called by the port when the bus is recieving an
- atomic snoop transaction.*/
- Tick recvAtomicSnoop(PacketPtr pkt, PortID master_port_id);
-
- /**
- * Forward an atomic packet to our snoopers, potentially excluding
- * one of the connected coherent masters to avoid sending a packet
- * back to where it came from.
- *
- * @param pkt Packet to forward
- * @param exclude_slave_port_id Id of slave port to exclude
- *
- * @return a pair containing the snoop response and snoop latency
- */
- std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
- PortID exclude_slave_port_id);
-
- /** Function called by the port when the bus is recieving a Functional
- transaction.*/
- void recvFunctional(PacketPtr pkt, PortID slave_port_id);
-
- /** Function called by the port when the bus is recieving a functional
- snoop transaction.*/
- void recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id);
-
- /**
- * Forward a functional packet to our snoopers, potentially
- * excluding one of the connected coherent masters to avoid
- * sending a packet back to where it came from.
- *
- * @param pkt Packet to forward
- * @param exclude_slave_port_id Id of slave port to exclude
- */
- void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id);
-
/** Timing function called by port when it is once again able to process
* requests. */
void recvRetry();
@@ -392,13 +189,6 @@ class Bus : public MemObject
*/
AddrRangeList getAddrRanges();
- /**
- * Determine if the bus port is snooping or not.
- *
- * @return a boolean indicating if this port is snooping or not
- */
- bool isSnooping() const;
-
/** Calculate the timing parameters for the packet. Updates the
* firstWordTime and finishTime fields of the packet object.
* Returns the tick at which the packet header is completed (which
@@ -430,7 +220,7 @@ class Bus : public MemObject
unsigned findBlockSize();
// event used to schedule a release of the bus
- EventWrapper<Bus, &Bus::releaseBus> busIdleEvent;
+ EventWrapper<BaseBus, &BaseBus::releaseBus> busIdleEvent;
bool inRetry;
std::set<PortID> inRecvRangeChange;
@@ -439,8 +229,11 @@ class Bus : public MemObject
std::vector<SlavePort*> slavePorts;
std::vector<MasterPort*> masterPorts;
+ /** Convenience typedefs. */
typedef std::vector<SlavePort*>::iterator SlavePortIter;
+ typedef std::vector<MasterPort*>::iterator MasterPortIter;
typedef std::vector<SlavePort*>::const_iterator SlavePortConstIter;
+ typedef std::vector<MasterPort*>::const_iterator MasterPortConstIter;
/** An array of pointers to ports that retry should be called on because the
* original send failed for whatever reason.*/
@@ -478,18 +271,20 @@ class Bus : public MemObject
unsigned cachedBlockSize;
bool cachedBlockSizeValid;
+ BaseBus(const BaseBusParams *p);
+
+ virtual ~BaseBus();
+
public:
/** A function used to return the port associated with this bus object. */
virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1);
virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1);
- virtual void init();
virtual void startup();
unsigned int drain(Event *de);
- Bus(const BusParams *p);
};
#endif //__MEM_BUS_HH__
diff --git a/src/mem/coherent_bus.cc b/src/mem/coherent_bus.cc
new file mode 100644
index 000000000..b40e84762
--- /dev/null
+++ b/src/mem/coherent_bus.cc
@@ -0,0 +1,493 @@
+/*
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ * Andreas Hansson
+ * William Wang
+ */
+
+/**
+ * @file
+ * Definition of a bus object.
+ */
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "debug/BusAddrRanges.hh"
+#include "debug/CoherentBus.hh"
+#include "mem/coherent_bus.hh"
+
+CoherentBus::CoherentBus(const CoherentBusParams *p)
+ : BaseBus(p)
+{
+ // create the ports based on the size of the master and slave
+ // vector ports, and the presence of the default port, the ports
+ // are enumerated starting from zero
+ for (int i = 0; i < p->port_master_connection_count; ++i) {
+ std::string portName = csprintf("%s-p%d", name(), i);
+ MasterPort* bp = new CoherentBusMasterPort(portName, *this, i);
+ masterPorts.push_back(bp);
+ }
+
+ // see if we have a default slave device connected and if so add
+ // our corresponding master port
+ if (p->port_default_connection_count) {
+ defaultPortID = masterPorts.size();
+ std::string portName = csprintf("%s-default", name());
+ MasterPort* bp = new CoherentBusMasterPort(portName, *this,
+ defaultPortID);
+ masterPorts.push_back(bp);
+ }
+
+ // create the slave ports, once again starting at zero
+ for (int i = 0; i < p->port_slave_connection_count; ++i) {
+ std::string portName = csprintf("%s-p%d", name(), i);
+ SlavePort* bp = new CoherentBusSlavePort(portName, *this, i);
+ slavePorts.push_back(bp);
+ }
+
+ clearPortCache();
+}
+
+void
+CoherentBus::init()
+{
+ // iterate over our slave ports and determine which of our
+ // neighbouring master ports are snooping and add them as snoopers
+ for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end();
+ ++p) {
+ if ((*p)->getMasterPort().isSnooping()) {
+ DPRINTF(BusAddrRanges, "Adding snooping master %s\n",
+ (*p)->getMasterPort().name());
+ snoopPorts.push_back(*p);
+ }
+ }
+
+ if (snoopPorts.empty())
+ warn("CoherentBus %s has no snooping ports attached!\n", name());
+}
+
+bool
+CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
+{
+ // determine the source port based on the id
+ SlavePort *src_port = slavePorts[slave_port_id];
+
+ // test if the bus should be considered occupied for the current
+ // port, and exclude express snoops from the check
+ if (!pkt->isExpressSnoop() && isOccupied(src_port)) {
+ DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+ return false;
+ }
+
+ DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+ // set the source port for routing of the response
+ pkt->setSrc(slave_port_id);
+
+ Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
+ Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
+
+ // uncacheable requests need never be snooped
+ if (!pkt->req->isUncacheable()) {
+ // the packet is a memory-mapped request and should be
+ // broadcasted to our snoopers but the source
+ forwardTiming(pkt, slave_port_id);
+ }
+
+ // remember if we add an outstanding req so we can undo it if
+ // necessary, if the packet needs a response, we should add it
+ // as outstanding and express snoops never fail so there is
+ // not need to worry about them
+ bool add_outstanding = !pkt->isExpressSnoop() && pkt->needsResponse();
+
+ // keep track that we have an outstanding request packet
+ // matching this request, this is used by the coherency
+ // mechanism in determining what to do with snoop responses
+ // (in recvTimingSnoop)
+ if (add_outstanding) {
+ // we should never have an exsiting request outstanding
+ assert(outstandingReq.find(pkt->req) == outstandingReq.end());
+ outstandingReq.insert(pkt->req);
+ }
+
+ // since it is a normal request, determine the destination
+ // based on the address and attempt to send the packet
+ bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt);
+
+ if (!success) {
+ // inhibited packets should never be forced to retry
+ assert(!pkt->memInhibitAsserted());
+
+ // if it was added as outstanding and the send failed, then
+ // erase it again
+ if (add_outstanding)
+ outstandingReq.erase(pkt->req);
+
+ DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+ addToRetryList(src_port);
+ occupyBus(headerFinishTime);
+
+ return false;
+ }
+
+ succeededTiming(packetFinishTime);
+
+ return true;
+}
+
+bool
+CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
+{
+ // determine the source port based on the id
+ MasterPort *src_port = masterPorts[master_port_id];
+
+ // test if the bus should be considered occupied for the current
+ // port
+ if (isOccupied(src_port)) {
+ DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+ return false;
+ }
+
+ DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+ calcPacketTiming(pkt);
+ Tick packetFinishTime = pkt->finishTime;
+
+ // the packet is a normal response to a request that we should
+ // have seen passing through the bus
+ assert(outstandingReq.find(pkt->req) != outstandingReq.end());
+
+ // remove it as outstanding
+ outstandingReq.erase(pkt->req);
+
+ // send the packet to the destination through one of our slave
+ // ports, as determined by the destination field
+ bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt);
+
+ // currently it is illegal to block responses... can lead to
+ // deadlock
+ assert(success);
+
+ succeededTiming(packetFinishTime);
+
+ return true;
+}
+
+void
+CoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id)
+{
+ DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n",
+ masterPorts[master_port_id]->name(), pkt->cmdString(),
+ pkt->getAddr());
+
+ // we should only see express snoops from caches
+ assert(pkt->isExpressSnoop());
+
+ // set the source port for routing of the response
+ pkt->setSrc(master_port_id);
+
+ // forward to all snoopers
+ forwardTiming(pkt, InvalidPortID);
+
+ // a snoop request came from a connected slave device (one of
+ // our master ports), and if it is not coming from the slave
+ // device responsible for the address range something is
+ // wrong, hence there is nothing further to do as the packet
+ // would be going back to where it came from
+ assert(master_port_id == findPort(pkt->getAddr()));
+
+ // this is an express snoop and is never forced to retry
+ assert(!inRetry);
+}
+
+bool
+CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
+{
+ // determine the source port based on the id
+ SlavePort* src_port = slavePorts[slave_port_id];
+
+ // test if the bus should be considered occupied for the current
+ // port
+ if (isOccupied(src_port)) {
+ DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+ return false;
+ }
+
+ DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+ // get the destination from the packet
+ PortID dest = pkt->getDest();
+
+ // responses are never express snoops
+ assert(!pkt->isExpressSnoop());
+
+ calcPacketTiming(pkt);
+ Tick packetFinishTime = pkt->finishTime;
+
+ // determine if the response is from a snoop request we
+ // created as the result of a normal request (in which case it
+ // should be in the outstandingReq), or if we merely forwarded
+ // someone else's snoop request
+ if (outstandingReq.find(pkt->req) == outstandingReq.end()) {
+ // this is a snoop response to a snoop request we
+ // forwarded, e.g. coming from the L1 and going to the L2
+ // this should be forwarded as a snoop response
+ bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt);
+ assert(success);
+ } else {
+ // we got a snoop response on one of our slave ports,
+ // i.e. from a coherent master connected to the bus, and
+ // since we created the snoop request as part of
+ // recvTiming, this should now be a normal response again
+ outstandingReq.erase(pkt->req);
+
+ // this is a snoop response from a coherent master, with a
+ // destination field set on its way through the bus as
+ // request, hence it should never go back to where the
+ // snoop response came from, but instead to where the
+ // original request came from
+ assert(slave_port_id != dest);
+
+ // as a normal response, it should go back to a master
+ // through one of our slave ports
+ bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt);
+
+ // currently it is illegal to block responses... can lead
+ // to deadlock
+ assert(success);
+ }
+
+ succeededTiming(packetFinishTime);
+
+ return true;
+}
+
+
+void
+CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
+{
+ for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
+ SlavePort *p = *s;
+ // we could have gotten this request from a snooping master
+ // (corresponding to our own slave port that is also in
+ // snoopPorts) and should not send it back to where it came
+ // from
+ if (exclude_slave_port_id == InvalidPortID ||
+ p->getId() != exclude_slave_port_id) {
+ // cache is not allowed to refuse snoop
+ p->sendTimingSnoopReq(pkt);
+ }
+ }
+}
+
+Tick
+CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id)
+{
+ DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
+ slavePorts[slave_port_id]->name(), pkt->getAddr(),
+ pkt->cmdString());
+
+ MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
+ Tick snoop_response_latency = 0;
+
+ // uncacheable requests need never be snooped
+ if (!pkt->req->isUncacheable()) {
+ // forward to all snoopers but the source
+ std::pair<MemCmd, Tick> snoop_result =
+ forwardAtomic(pkt, slave_port_id);
+ snoop_response_cmd = snoop_result.first;
+ snoop_response_latency = snoop_result.second;
+ }
+
+ // even if we had a snoop response, we must continue and also
+ // perform the actual request at the destination
+ PortID dest_id = findPort(pkt->getAddr());
+
+ // forward the request to the appropriate destination
+ Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
+
+ // 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());
+ pkt->cmd = snoop_response_cmd;
+ response_latency = snoop_response_latency;
+ }
+
+ pkt->finishTime = curTick() + response_latency;
+ return response_latency;
+}
+
+Tick
+CoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id)
+{
+ DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n",
+ masterPorts[master_port_id]->name(), pkt->getAddr(),
+ pkt->cmdString());
+
+ // forward to all snoopers
+ std::pair<MemCmd, Tick> snoop_result =
+ forwardAtomic(pkt, InvalidPortID);
+ MemCmd snoop_response_cmd = snoop_result.first;
+ Tick snoop_response_latency = snoop_result.second;
+
+ if (snoop_response_cmd != MemCmd::InvalidCmd)
+ pkt->cmd = snoop_response_cmd;
+
+ pkt->finishTime = curTick() + snoop_response_latency;
+ return snoop_response_latency;
+}
+
+std::pair<MemCmd, Tick>
+CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
+{
+ // the packet may be changed on snoops, record the original
+ // command to enable us to restore it between snoops so that
+ // additional snoops can take place properly
+ MemCmd orig_cmd = pkt->cmd;
+ MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
+ Tick snoop_response_latency = 0;
+
+ for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
+ SlavePort *p = *s;
+ // we could have gotten this request from a snooping master
+ // (corresponding to our own slave port that is also in
+ // snoopPorts) and should not send it back to where it came
+ // from
+ if (exclude_slave_port_id == InvalidPortID ||
+ p->getId() != exclude_slave_port_id) {
+ Tick latency = p->sendAtomicSnoop(pkt);
+ // in contrast to a functional access, we have to keep on
+ // going as all snoopers must be updated even if we get a
+ // response
+ 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;
+ }
+ }
+ }
+
+ // the packet is restored as part of the loop and any potential
+ // snoop response is part of the returned pair
+ return std::make_pair(snoop_response_cmd, snoop_response_latency);
+}
+
+void
+CoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id)
+{
+ if (!pkt->isPrint()) {
+ // don't do DPRINTFs on PrintReq as it clutters up the output
+ DPRINTF(CoherentBus,
+ "recvFunctional: packet src %s addr 0x%x cmd %s\n",
+ slavePorts[slave_port_id]->name(), pkt->getAddr(),
+ pkt->cmdString());
+ }
+
+ // uncacheable requests need never be snooped
+ if (!pkt->req->isUncacheable()) {
+ // forward to all snoopers but the source
+ forwardFunctional(pkt, slave_port_id);
+ }
+
+ // there is no need to continue if the snooping has found what we
+ // were looking for and the packet is already a response
+ if (!pkt->isResponse()) {
+ PortID dest_id = findPort(pkt->getAddr());
+
+ masterPorts[dest_id]->sendFunctional(pkt);
+ }
+}
+
+void
+CoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id)
+{
+ if (!pkt->isPrint()) {
+ // don't do DPRINTFs on PrintReq as it clutters up the output
+ DPRINTF(CoherentBus,
+ "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n",
+ masterPorts[master_port_id]->name(), pkt->getAddr(),
+ pkt->cmdString());
+ }
+
+ // forward to all snoopers
+ forwardFunctional(pkt, InvalidPortID);
+}
+
+void
+CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
+{
+ for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
+ SlavePort *p = *s;
+ // we could have gotten this request from a snooping master
+ // (corresponding to our own slave port that is also in
+ // snoopPorts) and should not send it back to where it came
+ // from
+ if (exclude_slave_port_id == InvalidPortID ||
+ p->getId() != exclude_slave_port_id)
+ p->sendFunctionalSnoop(pkt);
+
+ // if we get a response we are done
+ if (pkt->isResponse()) {
+ break;
+ }
+ }
+}
+
+CoherentBus *
+CoherentBusParams::create()
+{
+ return new CoherentBus(this);
+}
diff --git a/src/mem/coherent_bus.hh b/src/mem/coherent_bus.hh
new file mode 100644
index 000000000..760ff8add
--- /dev/null
+++ b/src/mem/coherent_bus.hh
@@ -0,0 +1,290 @@
+/*
+ * 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) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Ali Saidi
+ * Andreas Hansson
+ * William Wang
+ */
+
+/**
+ * @file
+ * Declaration of a coherent bus.
+ */
+
+#ifndef __MEM_COHERENT_BUS_HH__
+#define __MEM_COHERENT_BUS_HH__
+
+#include "mem/bus.hh"
+#include "params/CoherentBus.hh"
+
+/**
+ * A coherent bus connects a number of (potentially) snooping masters
+ * and slaves, and routes the request and response packets based on
+ * the address, and also forwards all requests to the snoopers and
+ * deals with the snoop responses.
+ *
+ * The coherent bus can be used as a template for modelling QPI,
+* HyperTransport, ACE and coherent OCP buses, and is typically used
+ * for the L1-to-L2 buses and as the main system interconnect.
+ */
+class CoherentBus : public BaseBus
+{
+
+ protected:
+
+ /**
+ * Declaration of the coherent bus slave port type, one will be
+ * instantiated for each of the master ports connecting to the
+ * bus.
+ */
+ class CoherentBusSlavePort : public SlavePort
+ {
+
+ private:
+
+ /** A reference to the bus to which this port belongs. */
+ CoherentBus &bus;
+
+ public:
+
+ CoherentBusSlavePort(const std::string &_name,
+ CoherentBus &_bus, PortID _id)
+ : SlavePort(_name, &_bus, _id), bus(_bus)
+ { }
+
+ protected:
+
+ /**
+ * When receiving a timing request, pass it to the bus.
+ */
+ virtual bool recvTimingReq(PacketPtr pkt)
+ { return bus.recvTimingReq(pkt, id); }
+
+ /**
+ * When receiving a timing snoop response, pass it to the bus.
+ */
+ virtual bool recvTimingSnoopResp(PacketPtr pkt)
+ { return bus.recvTimingSnoopResp(pkt, id); }
+
+ /**
+ * When receiving an atomic request, pass it to the bus.
+ */
+ virtual Tick recvAtomic(PacketPtr pkt)
+ { return bus.recvAtomic(pkt, id); }
+
+ /**
+ * When receiving a functional request, pass it to the bus.
+ */
+ virtual void recvFunctional(PacketPtr pkt)
+ { bus.recvFunctional(pkt, id); }
+
+ /**
+ * When receiving a retry, pass it to the bus.
+ */
+ virtual void recvRetry()
+ { panic("Bus slave ports always succeed and should never retry.\n"); }
+
+ /**
+ * Return the union of all adress ranges seen by this bus.
+ */
+ virtual AddrRangeList getAddrRanges()
+ { return bus.getAddrRanges(); }
+
+ /**
+ * Get the maximum block size as seen by the bus.
+ */
+ virtual unsigned deviceBlockSize() const
+ { return bus.findBlockSize(); }
+
+ };
+
+ /**
+ * Declaration of the coherent bus master port type, one will be
+ * instantiated for each of the slave interfaces connecting to the
+ * bus.
+ */
+ class CoherentBusMasterPort : public MasterPort
+ {
+ private:
+ /** A reference to the bus to which this port belongs. */
+ CoherentBus &bus;
+
+ public:
+
+ CoherentBusMasterPort(const std::string &_name,
+ CoherentBus &_bus, PortID _id)
+ : MasterPort(_name, &_bus, _id), bus(_bus)
+ { }
+
+ protected:
+
+ /**
+ * Determine if this port should be considered a snooper. For
+ * a coherent bus master port this is always true.
+ *
+ * @return a boolean that is true if this port is snooping
+ */
+ virtual bool isSnooping() const
+ { return true; }
+
+ /**
+ * When receiving a timing response, pass it to the bus.
+ */
+ virtual bool recvTimingResp(PacketPtr pkt)
+ { return bus.recvTimingResp(pkt, id); }
+
+ /**
+ * When receiving a timing snoop request, pass it to the bus.
+ */
+ virtual void recvTimingSnoopReq(PacketPtr pkt)
+ { return bus.recvTimingSnoopReq(pkt, id); }
+
+ /**
+ * When receiving an atomic snoop request, pass it to the bus.
+ */
+ virtual Tick recvAtomicSnoop(PacketPtr pkt)
+ { return bus.recvAtomicSnoop(pkt, id); }
+
+ /**
+ * When receiving a functional snoop request, pass it to the bus.
+ */
+ virtual void recvFunctionalSnoop(PacketPtr pkt)
+ { bus.recvFunctionalSnoop(pkt, id); }
+
+ /** When reciving a range change from the peer port (at id),
+ pass it to the bus. */
+ virtual void recvRangeChange()
+ { bus.recvRangeChange(id); }
+
+ /** When reciving a retry from the peer port (at id),
+ pass it to the bus. */
+ virtual void recvRetry()
+ { bus.recvRetry(); }
+
+ // Ask the bus to ask everyone on the bus what their block size is and
+ // take the max of it. This might need to be changed a bit if we ever
+ // support multiple block sizes.
+ virtual unsigned deviceBlockSize() const
+ { return bus.findBlockSize(); }
+
+ };
+
+ std::vector<SlavePort*> snoopPorts;
+
+ /**
+ * Store the outstanding requests so we can determine which ones
+ * we generated and which ones were merely forwarded. This is used
+ * in the coherent bus when coherency responses come back.
+ */
+ std::set<RequestPtr> outstandingReq;
+
+ /** Function called by the port when the bus is recieving a Timing
+ request packet.*/
+ bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
+
+ /** Function called by the port when the bus is recieving a Timing
+ response packet.*/
+ bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
+
+ /** Function called by the port when the bus is recieving a timing
+ snoop request.*/
+ void recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id);
+
+ /** Function called by the port when the bus is recieving a timing
+ snoop response.*/
+ bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id);
+
+ /**
+ * Forward a timing packet to our snoopers, potentially excluding
+ * one of the connected coherent masters to avoid sending a packet
+ * back to where it came from.
+ *
+ * @param pkt Packet to forward
+ * @param exclude_slave_port_id Id of slave port to exclude
+ */
+ void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id);
+
+ /** Function called by the port when the bus is recieving a Atomic
+ transaction.*/
+ Tick recvAtomic(PacketPtr pkt, PortID slave_port_id);
+
+ /** Function called by the port when the bus is recieving an
+ atomic snoop transaction.*/
+ Tick recvAtomicSnoop(PacketPtr pkt, PortID master_port_id);
+
+ /**
+ * Forward an atomic packet to our snoopers, potentially excluding
+ * one of the connected coherent masters to avoid sending a packet
+ * back to where it came from.
+ *
+ * @param pkt Packet to forward
+ * @param exclude_slave_port_id Id of slave port to exclude
+ *
+ * @return a pair containing the snoop response and snoop latency
+ */
+ std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
+ PortID exclude_slave_port_id);
+
+ /** Function called by the port when the bus is recieving a Functional
+ transaction.*/
+ void recvFunctional(PacketPtr pkt, PortID slave_port_id);
+
+ /** Function called by the port when the bus is recieving a functional
+ snoop transaction.*/
+ void recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id);
+
+ /**
+ * Forward a functional packet to our snoopers, potentially
+ * excluding one of the connected coherent masters to avoid
+ * sending a packet back to where it came from.
+ *
+ * @param pkt Packet to forward
+ * @param exclude_slave_port_id Id of slave port to exclude
+ */
+ void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id);
+
+ public:
+
+ virtual void init();
+
+ CoherentBus(const CoherentBusParams *p);
+};
+
+#endif //__MEM_COHERENT_BUS_HH__
diff --git a/src/mem/noncoherent_bus.cc b/src/mem/noncoherent_bus.cc
new file mode 100644
index 000000000..4faad757a
--- /dev/null
+++ b/src/mem/noncoherent_bus.cc
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ * Andreas Hansson
+ * William Wang
+ */
+
+/**
+ * @file
+ * Definition of a bus object.
+ */
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "debug/Bus.hh"
+#include "debug/BusAddrRanges.hh"
+#include "debug/NoncoherentBus.hh"
+#include "mem/noncoherent_bus.hh"
+
+NoncoherentBus::NoncoherentBus(const NoncoherentBusParams *p)
+ : BaseBus(p)
+{
+ // create the ports based on the size of the master and slave
+ // vector ports, and the presence of the default port, the ports
+ // are enumerated starting from zero
+ for (int i = 0; i < p->port_master_connection_count; ++i) {
+ std::string portName = csprintf("%s-p%d", name(), i);
+ MasterPort* bp = new NoncoherentBusMasterPort(portName, *this, i);
+ masterPorts.push_back(bp);
+ }
+
+ // see if we have a default slave device connected and if so add
+ // our corresponding master port
+ if (p->port_default_connection_count) {
+ defaultPortID = masterPorts.size();
+ std::string portName = csprintf("%s-default", name());
+ MasterPort* bp = new NoncoherentBusMasterPort(portName, *this,
+ defaultPortID);
+ masterPorts.push_back(bp);
+ }
+
+ // create the slave ports, once again starting at zero
+ for (int i = 0; i < p->port_slave_connection_count; ++i) {
+ std::string portName = csprintf("%s-p%d", name(), i);
+ SlavePort* bp = new NoncoherentBusSlavePort(portName, *this, i);
+ slavePorts.push_back(bp);
+ }
+
+ clearPortCache();
+}
+
+bool
+NoncoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
+{
+ // determine the source port based on the id
+ SlavePort *src_port = slavePorts[slave_port_id];
+
+ // we should never see express snoops on a non-coherent bus
+ assert(!pkt->isExpressSnoop());
+
+ // test if the bus should be considered occupied for the current
+ // port
+ if (isOccupied(src_port)) {
+ DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+ return false;
+ }
+
+ DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+ // set the source port for routing of the response
+ pkt->setSrc(slave_port_id);
+
+ Tick headerFinishTime = calcPacketTiming(pkt);
+ Tick packetFinishTime = pkt->finishTime;
+
+ // since it is a normal request, determine the destination
+ // based on the address and attempt to send the packet
+ bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt);
+
+ if (!success) {
+ // inhibited packets should never be forced to retry
+ assert(!pkt->memInhibitAsserted());
+
+ DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+ addToRetryList(src_port);
+ occupyBus(headerFinishTime);
+
+ return false;
+ }
+
+ succeededTiming(packetFinishTime);
+
+ return true;
+}
+
+bool
+NoncoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
+{
+ // determine the source port based on the id
+ MasterPort *src_port = masterPorts[master_port_id];
+
+ // test if the bus should be considered occupied for the current
+ // port
+ if (isOccupied(src_port)) {
+ DPRINTF(NoncoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+ return false;
+ }
+
+ DPRINTF(NoncoherentBus, "recvTimingResp: src %s %s 0x%x\n",
+ src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+ calcPacketTiming(pkt);
+ Tick packetFinishTime = pkt->finishTime;
+
+ // send the packet to the destination through one of our slave
+ // ports, as determined by the destination field
+ bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt);
+
+ // currently it is illegal to block responses... can lead to
+ // deadlock
+ assert(success);
+
+ succeededTiming(packetFinishTime);
+
+ return true;
+}
+
+Tick
+NoncoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id)
+{
+ DPRINTF(NoncoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
+ slavePorts[slave_port_id]->name(), pkt->getAddr(),
+ pkt->cmdString());
+
+ // determine the destination port
+ PortID dest_id = findPort(pkt->getAddr());
+
+ // forward the request to the appropriate destination
+ Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
+
+ pkt->finishTime = curTick() + response_latency;
+ return response_latency;
+}
+
+void
+NoncoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id)
+{
+ if (!pkt->isPrint()) {
+ // don't do DPRINTFs on PrintReq as it clutters up the output
+ DPRINTF(NoncoherentBus,
+ "recvFunctional: packet src %s addr 0x%x cmd %s\n",
+ slavePorts[slave_port_id]->name(), pkt->getAddr(),
+ pkt->cmdString());
+ }
+
+ // determine the destination port
+ PortID dest_id = findPort(pkt->getAddr());
+
+ // forward the request to the appropriate destination
+ masterPorts[dest_id]->sendFunctional(pkt);
+}
+
+NoncoherentBus*
+NoncoherentBusParams::create()
+{
+ return new NoncoherentBus(this);
+}
diff --git a/src/mem/noncoherent_bus.hh b/src/mem/noncoherent_bus.hh
new file mode 100644
index 000000000..8bd6c0e74
--- /dev/null
+++ b/src/mem/noncoherent_bus.hh
@@ -0,0 +1,201 @@
+/*
+ * 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) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Ali Saidi
+ * Andreas Hansson
+ * William Wang
+ */
+
+/**
+ * @file
+ * Declaration of a non-coherent bus.
+ */
+
+#ifndef __MEM_NONCOHERENT_BUS_HH__
+#define __MEM_NONCOHERENT_BUS_HH__
+
+#include "mem/bus.hh"
+#include "params/NoncoherentBus.hh"
+
+/**
+ * A non-coherent bus connects a number of non-snooping masters and
+ * slaves, and routes the request and response packets based on the
+ * address. The request packets issued by the master connected to a
+ * non-coherent bus could still snoop in caches attached to a coherent
+ * bus, as is the case with the I/O bus and memory bus in most system
+ * configurations. No snoops will, however, reach any master on the
+ * non-coherent bus itself.
+ *
+ * The non-coherent bus can be used as a template for modelling PCI,
+ * PCIe, and non-coherent AMBA and OCP buses, and is typically used
+ * for the I/O buses.
+ */
+class NoncoherentBus : public BaseBus
+{
+
+ protected:
+
+ /**
+ * Declaration of the non-coherent bus slave port type, one will
+ * be instantiated for each of the master ports connecting to the
+ * bus.
+ */
+ class NoncoherentBusSlavePort : public SlavePort
+ {
+ private:
+
+ /** A reference to the bus to which this port belongs. */
+ NoncoherentBus &bus;
+
+ public:
+
+ NoncoherentBusSlavePort(const std::string &_name,
+ NoncoherentBus &_bus, PortID _id)
+ : SlavePort(_name, &_bus, _id), bus(_bus)
+ { }
+
+ protected:
+
+ /**
+ * When receiving a timing request, pass it to the bus.
+ */
+ virtual bool recvTimingReq(PacketPtr pkt)
+ { return bus.recvTimingReq(pkt, id); }
+
+ /**
+ * When receiving an atomic request, pass it to the bus.
+ */
+ virtual Tick recvAtomic(PacketPtr pkt)
+ { return bus.recvAtomic(pkt, id); }
+
+ /**
+ * When receiving a functional request, pass it to the bus.
+ */
+ virtual void recvFunctional(PacketPtr pkt)
+ { bus.recvFunctional(pkt, id); }
+
+ /**
+ * When receiving a retry, pass it to the bus.
+ */
+ virtual void recvRetry()
+ { panic("Bus slave ports always succeed and should never retry.\n"); }
+
+ /**
+ * Return the union of all adress ranges seen by this bus.
+ */
+ virtual AddrRangeList getAddrRanges()
+ { return bus.getAddrRanges(); }
+
+ /**
+ * Get the maximum block size as seen by the bus.
+ */
+ virtual unsigned deviceBlockSize() const
+ { return bus.findBlockSize(); }
+
+ };
+
+ /**
+ * Declaration of the bus master port type, one will be
+ * instantiated for each of the slave ports connecting to the
+ * bus.
+ */
+ class NoncoherentBusMasterPort : public MasterPort
+ {
+ private:
+
+ /** A reference to the bus to which this port belongs. */
+ NoncoherentBus &bus;
+
+ public:
+
+ NoncoherentBusMasterPort(const std::string &_name,
+ NoncoherentBus &_bus, PortID _id)
+ : MasterPort(_name, &_bus, _id), bus(_bus)
+ { }
+
+ protected:
+
+ /**
+ * When receiving a timing response, pass it to the bus.
+ */
+ virtual bool recvTimingResp(PacketPtr pkt)
+ { return bus.recvTimingResp(pkt, id); }
+
+ /** When reciving a range change from the peer port (at id),
+ pass it to the bus. */
+ virtual void recvRangeChange()
+ { bus.recvRangeChange(id); }
+
+ /** When reciving a retry from the peer port (at id),
+ pass it to the bus. */
+ virtual void recvRetry()
+ { bus.recvRetry(); }
+
+ /**
+ * Get the maximum block size as seen by the bus.
+ */
+ virtual unsigned deviceBlockSize() const
+ { return bus.findBlockSize(); }
+
+ };
+
+ /** Function called by the port when the bus is recieving a Timing
+ request packet.*/
+ bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
+
+ /** Function called by the port when the bus is recieving a Timing
+ response packet.*/
+ bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
+
+ /** Function called by the port when the bus is recieving a Atomic
+ transaction.*/
+ Tick recvAtomic(PacketPtr pkt, PortID slave_port_id);
+
+ /** Function called by the port when the bus is recieving a Functional
+ transaction.*/
+ void recvFunctional(PacketPtr pkt, PortID slave_port_id);
+
+ public:
+
+ NoncoherentBus(const NoncoherentBusParams *p);
+
+};
+
+#endif //__MEM_NONCOHERENT_BUS_HH__