Bus: Split the bus into a non-coherent and coherent bus
authorAndreas Hansson <andreas.hansson@arm.com>
Thu, 31 May 2012 17:30:04 +0000 (13:30 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Thu, 31 May 2012 17:30:04 +0000 (13:30 -0400)
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

45 files changed:
configs/common/CacheConfig.py
configs/common/FSConfig.py
configs/example/memtest.py
configs/example/se.py
configs/splash2/cluster.py
configs/splash2/run.py
src/cpu/BaseCPU.py
src/mem/Bus.py
src/mem/SConscript
src/mem/bus.cc
src/mem/bus.hh
src/mem/coherent_bus.cc [new file with mode: 0644]
src/mem/coherent_bus.hh [new file with mode: 0644]
src/mem/noncoherent_bus.cc [new file with mode: 0644]
src/mem/noncoherent_bus.hh [new file with mode: 0644]
tests/configs/inorder-timing.py
tests/configs/memtest.py
tests/configs/o3-timing-checker.py
tests/configs/o3-timing-mp-ruby.py
tests/configs/o3-timing-mp.py
tests/configs/o3-timing-ruby.py
tests/configs/o3-timing.py
tests/configs/pc-o3-timing.py
tests/configs/pc-simple-atomic.py
tests/configs/pc-simple-timing.py
tests/configs/realview-o3-checker.py
tests/configs/realview-o3-dual.py
tests/configs/realview-o3.py
tests/configs/realview-simple-atomic-dual.py
tests/configs/realview-simple-atomic.py
tests/configs/realview-simple-timing-dual.py
tests/configs/realview-simple-timing.py
tests/configs/simple-atomic-dummychecker.py
tests/configs/simple-atomic-mp-ruby.py
tests/configs/simple-atomic-mp.py
tests/configs/simple-atomic.py
tests/configs/simple-timing-mp.py
tests/configs/simple-timing.py
tests/configs/tsunami-inorder.py
tests/configs/tsunami-o3-dual.py
tests/configs/tsunami-o3.py
tests/configs/tsunami-simple-atomic-dual.py
tests/configs/tsunami-simple-atomic.py
tests/configs/tsunami-simple-timing-dual.py
tests/configs/tsunami-simple-timing.py

index 009cb1bf6b02222a778a6816c1c80f91a75f2583..bc724f65fa74391e9a2a5249b0ccc15ce16dcad0 100644 (file)
@@ -43,7 +43,7 @@ def config_cache(options, system):
             system.l2 = L2Cache(size = options.l2_size, assoc = options.l2_assoc,
                                 block_size=options.cacheline_size)
 
-        system.tol2bus = Bus()
+        system.tol2bus = CoherentBus()
         system.l2.cpu_side = system.tol2bus.master
         system.l2.mem_side = system.membus.slave
 
index 8e4be313748e2e3416d07afa4b72cb7de936589f..c9e28a5f6379758533721895fc51acaa36e9cb90 100644 (file)
@@ -50,7 +50,7 @@ class CowIdeDisk(IdeDisk):
     def childImage(self, ci):
         self.image.child.image_file = ci
 
-class MemBus(Bus):
+class MemBus(CoherentBus):
     badaddr_responder = BadAddr()
     default = Self.badaddr_responder.pio
 
@@ -67,8 +67,8 @@ def makeLinuxAlphaSystem(mem_mode, mdesc = None):
         # generic system
         mdesc = SysConfig()
     self.readfile = mdesc.script()
-    self.iobus = Bus(bus_id=0)
-    self.membus = MemBus(bus_id=1)
+    self.iobus = NoncoherentBus()
+    self.membus = MemBus()
     # By default the bridge responds to all addresses above the I/O
     # base address (including the PCI config space)
     self.bridge = Bridge(delay='50ns', nack_delay='4ns',
@@ -117,7 +117,7 @@ def makeLinuxAlphaRubySystem(mem_mode, mdesc = None):
     self.readfile = mdesc.script()
 
     # Create pio bus to connect all device pio ports to rubymem's pio port
-    self.piobus = Bus(bus_id=0)
+    self.piobus = NoncoherentBus()
 
     #
     # Pio functional accesses from devices need direct access to memory
@@ -172,8 +172,8 @@ def makeSparcSystem(mem_mode, mdesc = None):
         # generic system
         mdesc = SysConfig()
     self.readfile = mdesc.script()
-    self.iobus = Bus(bus_id=0)
-    self.membus = MemBus(bus_id=1)
+    self.iobus = NoncoherentBus()
+    self.membus = MemBus()
     self.bridge = Bridge(delay='50ns', nack_delay='4ns')
     self.t1000 = T1000()
     self.t1000.attachOnChipIO(self.membus)
@@ -237,8 +237,8 @@ def makeArmSystem(mem_mode, machine_type, mdesc = None, bare_metal=False):
         mdesc = SysConfig()
 
     self.readfile = mdesc.script()
-    self.iobus = Bus(bus_id=0)
-    self.membus = MemBus(bus_id=1)
+    self.iobus = NoncoherentBus()
+    self.membus = MemBus()
     self.membus.badaddr_responder.warn_access = "warn"
     self.bridge = Bridge(delay='50ns', nack_delay='4ns')
     self.bridge.master = self.iobus.slave
@@ -320,8 +320,8 @@ def makeLinuxMipsSystem(mem_mode, mdesc = None):
         # generic system
         mdesc = SysConfig()
     self.readfile = mdesc.script()
-    self.iobus = Bus(bus_id=0)
-    self.membus = MemBus(bus_id=1)
+    self.iobus = NoncoherentBus()
+    self.membus = MemBus()
     self.bridge = Bridge(delay='50ns', nack_delay='4ns')
     self.physmem = SimpleMemory(range = AddrRange('1GB'))
     self.bridge.master = self.iobus.slave
@@ -363,11 +363,11 @@ def connectX86ClassicSystem(x86_sys, numCPUs):
     interrupts_address_space_base = 0xa000000000000000
     APIC_range_size = 1 << 12;
 
-    x86_sys.membus = MemBus(bus_id=1)
+    x86_sys.membus = MemBus()
     x86_sys.physmem.port = x86_sys.membus.master
 
     # North Bridge
-    x86_sys.iobus = Bus(bus_id=0)
+    x86_sys.iobus = NoncoherentBus()
     x86_sys.bridge = Bridge(delay='50ns', nack_delay='4ns')
     x86_sys.bridge.master = x86_sys.iobus.slave
     x86_sys.bridge.slave = x86_sys.membus.master
@@ -402,7 +402,7 @@ def connectX86ClassicSystem(x86_sys, numCPUs):
 
 def connectX86RubySystem(x86_sys):
     # North Bridge
-    x86_sys.piobus = Bus(bus_id=0)
+    x86_sys.piobus = NoncoherentBus()
 
     #
     # Pio functional accesses from devices need direct access to memory
index 2dcccbba6841bba2fc777594f7f30483ca453da8..5903789203092a7c8d6cf290ebbe007a26ab4a79 100644 (file)
@@ -148,7 +148,7 @@ def make_level(spec, prototypes, attach_obj, attach_port):
      parent = attach_obj # use attach obj as config parent too
      if len(spec) > 1 and (fanout > 1 or options.force_bus):
           port = getattr(attach_obj, attach_port)
-          new_bus = Bus(clock="500MHz", width=16)
+          new_bus = CoherentBus(clock="500MHz", width=16)
           if (port.role == 'MASTER'):
                new_bus.slave = port
                attach_port = "master"
index 8324bea4efd852171542da991e1e9f2f66e997a6..83abbd2f38ea292a42b9a5469f840c12ea08226c 100644 (file)
@@ -153,7 +153,7 @@ np = options.num_cpus
 
 system = System(cpu = [CPUClass(cpu_id=i) for i in xrange(np)],
                 physmem = SimpleMemory(range=AddrRange("512MB")),
-                membus = Bus(), mem_mode = test_mem_mode)
+                membus = CoherentBus(), mem_mode = test_mem_mode)
 
 # Sanity check
 if options.fastmem and (options.caches or options.l2cache):
index dd8ab784ac61f7856c583d4f5ce7caa0c4e98507..d7e32a41460513a4f858f0021f1a61ce1a5c91b7 100644 (file)
@@ -173,7 +173,7 @@ if options.timing:
     for j in xrange(options.numclusters):
         clusters[j].id = j
     for cluster in clusters:
-        cluster.clusterbus = Bus(clock=busFrequency)
+        cluster.clusterbus = CoherentBus(clock=busFrequency)
         all_l1buses += [cluster.clusterbus]
         cluster.cpus = [TimingSimpleCPU(cpu_id = i + cluster.id,
                                         clock=options.frequency)
@@ -186,7 +186,7 @@ elif options.detailed:
     for j in xrange(options.numclusters):
         clusters[j].id = j
     for cluster in clusters:
-        cluster.clusterbus = Bus(clock=busFrequency)
+        cluster.clusterbus = CoherentBus(clock=busFrequency)
         all_l1buses += [cluster.clusterbus]
         cluster.cpus = [DerivO3CPU(cpu_id = i + cluster.id,
                                    clock=options.frequency)
@@ -199,7 +199,7 @@ else:
     for j in xrange(options.numclusters):
         clusters[j].id = j
     for cluster in clusters:
-        cluster.clusterbus = Bus(clock=busFrequency)
+        cluster.clusterbus = CoherentBus(clock=busFrequency)
         all_l1buses += [cluster.clusterbus]
         cluster.cpus = [AtomicSimpleCPU(cpu_id = i + cluster.id,
                                         clock=options.frequency)
@@ -212,9 +212,10 @@ else:
 # Create a system, and add system wide objects
 # ----------------------
 system = System(cpu = all_cpus, l1_ = all_l1s, l1bus_ = all_l1buses,
-                physmem = SimpleMemory(), membus = Bus(clock = busFrequency))
+                physmem = SimpleMemory(),
+                membus = CoherentBus(clock = busFrequency))
 
-system.toL2bus = Bus(clock = busFrequency)
+system.toL2bus = CoherentBus(clock = busFrequency)
 system.l2 = L2(size = options.l2size, assoc = 8)
 
 # ----------------------
index 40dafceff2fad263938508ce7af69e71500e126a..48e255c52ea78c52785aa16cfbdae7650be5ad92 100644 (file)
@@ -198,9 +198,9 @@ else:
 # Create a system, and add system wide objects
 # ----------------------
 system = System(cpu = cpus, physmem = SimpleMemory(),
-                membus = Bus(clock = busFrequency))
+                membus = CoherentBus(clock = busFrequency))
 
-system.toL2bus = Bus(clock = busFrequency)
+system.toL2bus = CoherentBus(clock = busFrequency)
 system.l2 = L2(size = options.l2size, assoc = 8)
 
 # ----------------------
index 60d06b20916a3b8165a31e0408e2d45923ea954a..9ed2cb78995e6be5b006a74cb854b2667b5dfccd 100644 (file)
@@ -47,7 +47,7 @@ from m5.defines import buildEnv
 from m5.params import *
 from m5.proxy import *
 
-from Bus import Bus
+from Bus import CoherentBus
 from InstTracer import InstTracer
 from ExeTracer import ExeTracer
 from MemObject import MemObject
@@ -223,7 +223,7 @@ class BaseCPU(MemObject):
 
     def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None):
         self.addPrivateSplitL1Caches(ic, dc, iwc, dwc)
-        self.toL2Bus = Bus()
+        self.toL2Bus = CoherentBus()
         self.connectCachedPorts(self.toL2Bus)
         self.l2cache = l2c
         self.toL2Bus.master = self.l2cache.cpu_side
index 91043da80c158b6ede5d353e487e86199b883ab0..05033d38247ac327a53355e1dd9113c39ce00119 100644 (file)
@@ -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.
 #
 # 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'
index 3ffb3503aba77fd10d3d4077d78243a1ee4a3986..1961204f7222e955b00a827404c08efd799fbd04 100644 (file)
@@ -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')
index a22b0e7fdf846bcc6c9ef658a96071f7b30f77e9..8040118d2e25c0e7b0cb34c3c2ba662ce20af491 100644 (file)
@@ -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);
-}
index c35b46cc261c508abdcf0c60fc8252af33531b17..4f0e44b1c6bae5c259915128662573fa0dea758c 100644 (file)
@@ -45,7 +45,7 @@
 
 /**
  * @file
- * Declaration of a bus object.
+ * Declaration of an abstract bus base class.
  */
 
 #ifndef __MEM_BUS_HH__
 
 #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 (file)
index 0000000..b40e847
--- /dev/null
@@ -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 (file)
index 0000000..760ff8a
--- /dev/null
@@ -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 (file)
index 0000000..4faad75
--- /dev/null
@@ -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 (file)
index 0000000..8bd6c0e
--- /dev/null
@@ -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__
index ea9c37ef94dcdcb5e6c4ff70602105643256a91f..3e285af7772fd379851f459aea7677edf866f6e7 100644 (file)
@@ -49,7 +49,7 @@ cpu.clock = '2GHz'
 
 system = System(cpu = cpu,
                 physmem = SimpleMemory(),
-                membus = Bus())
+                membus = CoherentBus())
 system.system_port = system.membus.slave
 system.physmem.port = system.membus.master
 # create the interrupt controller
index 9876c07b9ad98da181917960c3af47a2d49ae753..0add2158fcb43c77cc2676d38d944916e7f0ec01 100644 (file)
@@ -58,10 +58,10 @@ cpus = [ MemTest() for i in xrange(nb_cores) ]
 # system simulated
 system = System(cpu = cpus, funcmem = SimpleMemory(in_addr_map = False),
                 physmem = SimpleMemory(),
-                membus = Bus(clock="500GHz", width=16))
+                membus = CoherentBus(clock="500GHz", width=16))
 
 # l2cache & bus
-system.toL2Bus = Bus(clock="500GHz", width=16)
+system.toL2Bus = CoherentBus(clock="500GHz", width=16)
 system.l2c = L2(size='64kB', assoc=8)
 system.l2c.cpu_side = system.toL2Bus.master
 
index 68429de04c8bd71b5defae1b234e037287c6ef5d..0bbe9b00aa195acf4c28120512dec58d24c10de1 100644 (file)
@@ -60,7 +60,7 @@ cpu.clock = '2GHz'
 
 system = System(cpu = cpu,
                 physmem = SimpleMemory(),
-                membus = Bus())
+                membus = CoherentBus())
 system.system_port = system.membus.slave
 system.physmem.port = system.membus.master
 cpu.connectAllPorts(system.membus)
index 0bc54f0f0b86374583829175234dce9fe9cd501b..a58bc50ec72c5165e5a4b443b2160a43e737b137 100644 (file)
@@ -37,7 +37,7 @@ import ruby_config
 ruby_memory = ruby_config.generate("TwoLevel_SplitL1UnifiedL2.rb", nb_cores)
 
 # system simulated
-system = System(cpu = cpus, physmem = ruby_memory, membus = Bus())
+system = System(cpu = cpus, physmem = ruby_memory, membus = CoherentBus())
 
 for cpu in cpus:
     # create the interrupt controller
index ee0f29570cc9283ca3c81f7eea1d6cc6cf987701..2aec2bb1d0319bd3ab4eade6c3dad86cada995c7 100644 (file)
@@ -56,10 +56,10 @@ nb_cores = 4
 cpus = [ DerivO3CPU(cpu_id=i) for i in xrange(nb_cores) ]
 
 # system simulated
-system = System(cpu = cpus, physmem = SimpleMemory(), membus = Bus())
+system = System(cpu = cpus, physmem = SimpleMemory(), membus = CoherentBus())
 
 # l2cache & bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.l2c = L2(size='4MB', assoc=8)
 system.l2c.cpu_side = system.toL2Bus.master
 
index 8debc7d3dbfd39dce690d8492bda1cff27bff973..db8ccdc7b1f048905943de5cb3cb012ceab825ee 100644 (file)
@@ -39,7 +39,7 @@ cpu.clock = '2GHz'
 
 system = System(cpu = cpu,
                 physmem = ruby_memory,
-                membus = Bus())
+                membus = CoherentBus())
 system.physmem.port = system.membus.master
 # create the interrupt controller
 cpu.createInterruptController()
index 732cd2d439c0e7e98099f659246f77ee770c861d..a10079ab8c39ee4d2b127a3961f7ca6814d438a6 100644 (file)
@@ -49,7 +49,7 @@ cpu.clock = '2GHz'
 
 system = System(cpu = cpu,
                 physmem = SimpleMemory(),
-                membus = Bus())
+                membus = CoherentBus())
 system.system_port = system.membus.slave
 system.physmem.port = system.membus.master
 # create the interrupt controller
index 0b8b9381faeaa31f75efe2b54de491a6bd82cd73..2d3019dafb415c232575b9d0f1254a4b1e08ee19 100644 (file)
@@ -92,7 +92,7 @@ system.iocache.mem_side = system.membus.slave
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 
 #connect up the l2 cache
 system.l2c = L2(size='4MB', assoc=8)
index 77cd1319fb2a9453193688514690cfddb8ff2056..f0d168c1aa8008a60ef0f658ec6f1aedc7289dc0 100644 (file)
@@ -94,7 +94,7 @@ system.iocache.mem_side = system.membus.slave
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 
 #connect up the l2 cache
 system.l2c = L2(size='4MB', assoc=8)
index fbe6b4c4ff6503d27c292d728b37e17e491cb7ef..4347b78d33c724b2049151e9c3e83025db033faf 100644 (file)
@@ -90,7 +90,7 @@ system.kernel = FSConfig.binary('x86_64-vmlinux-2.6.22.9')
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.master
 system.iocache.mem_side = system.membus.slave
index c07c2ca9eab7cc973b5715b654dcbeba62283199..b263adee0ec4c830065a720fba61dd3596a75496 100644 (file)
@@ -83,7 +83,7 @@ system = FSConfig.makeArmSystem('timing', "RealView_PBX", None, False)
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.master
 system.iocache.mem_side = system.membus.slave
index 71b4f06dd6303e2383ecb980b791dfede6d56fac..e6ca2d7bdadfddf873055609dfff32c048aae82b 100644 (file)
@@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave
 
 system.cpu = cpus
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 
 #connect up the l2 cache
 system.l2c = L2(size='4MB', assoc=8)
index db64ccc602c9b2f00070c5588ffd73b2b4c2a5b7..e231df9f2d5ea906fc9a656f94bf2202f75f46a4 100644 (file)
@@ -74,7 +74,7 @@ system = FSConfig.makeArmSystem('timing', "RealView_PBX", None, False)
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.master
 system.iocache.mem_side = system.membus.slave
index eef5e90c5d649fdf9bde399de37481e667b84c86..e3a73305c0987bf8861a4734feedab55ca641d6a 100644 (file)
@@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave
 
 system.cpu = cpus
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 
 #connect up the l2 cache
 system.l2c = L2(size='4MB', assoc=8)
index 0544c98b64227b73386a6809a3148f58bb1e444c..fdfac1cc68e88b985899d74b38d234fa5cecc3c1 100644 (file)
@@ -76,7 +76,7 @@ system.iocache.mem_side = system.membus.slave
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 
 #connect up the l2 cache
 system.l2c = L2(size='4MB', assoc=8)
index edc2b7a9579294364d6df241d9fbcd19b3f52f50..825b67d05657d15b6e23ca5f8667fa655eaaf2d4 100644 (file)
@@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave
 
 system.cpu = cpus
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 
 #connect up the l2 cache
 system.l2c = L2(size='4MB', assoc=8)
index 6e539624bbad152c4f5a352e8b64c28e232c200e..786b42e20c37b50129df124d9903582be63b5018 100644 (file)
@@ -74,7 +74,7 @@ system = FSConfig.makeArmSystem('timing', "RealView_PBX", None, False)
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.master
 system.iocache.mem_side = system.membus.slave
index 2e672924d67ed1f4c8c7ece1eed69cb6c144d650..5192afb1c3ec1e605f9b7b2681f7b5b0d0228048 100644 (file)
@@ -40,7 +40,7 @@ from m5.objects import *
 
 system = System(cpu = AtomicSimpleCPU(cpu_id=0),
                 physmem = SimpleMemory(),
-                membus = Bus())
+                membus = CoherentBus())
 system.system_port = system.membus.slave
 system.physmem.port = system.membus.master
 system.cpu.addCheckerCpu()
index a9ee3c4d045ffc202b50a6266a08386b6d780b49..50d3349dd02080ec4ef2e1bae0997c0d0dd0becc 100644 (file)
@@ -37,7 +37,7 @@ import ruby_config
 ruby_memory = ruby_config.generate("TwoLevel_SplitL1UnifiedL2.rb", nb_cores)
 
 # system simulated
-system = System(cpu = cpus, physmem = ruby_memory, membus = Bus())
+system = System(cpu = cpus, physmem = ruby_memory, membus = CoherentBus())
 
 # add L1 caches
 for cpu in cpus:
index af9f3bc09a1c821033bc484e27618d7cc8ab4a92..8161a93f247b5c936c0cfa83b0b81fc7163f5b17 100644 (file)
@@ -57,10 +57,10 @@ cpus = [ AtomicSimpleCPU(cpu_id=i) for i in xrange(nb_cores) ]
 # system simulated
 system = System(cpu = cpus,
                 physmem = SimpleMemory(range = AddrRange('1024MB')),
-                membus = Bus())
+                membus = CoherentBus())
 
 # l2cache & bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.l2c = L2(size='4MB', assoc=8)
 system.l2c.cpu_side = system.toL2Bus.master
 
index b1aa31d8024c9aeb0dbf453e98fee04caab14e58..3b81d97696669453849a4499b18c6c89eb402576 100644 (file)
@@ -31,7 +31,7 @@ from m5.objects import *
 
 system = System(cpu = AtomicSimpleCPU(cpu_id=0),
                 physmem = SimpleMemory(),
-                membus = Bus())
+                membus = CoherentBus())
 system.system_port = system.membus.slave
 system.physmem.port = system.membus.master
 # create the interrupt controller
index 5bb0194aa99513b6a6651a987af701d343644a93..2a4075624e14deac5d118a2ab20beaa378b5fdab 100644 (file)
@@ -55,10 +55,10 @@ nb_cores = 4
 cpus = [ TimingSimpleCPU(cpu_id=i) for i in xrange(nb_cores) ]
 
 # system simulated
-system = System(cpu = cpus, physmem = SimpleMemory(), membus = Bus())
+system = System(cpu = cpus, physmem = SimpleMemory(), membus = CoherentBus())
 
 # l2cache & bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.l2c = L2(size='4MB', assoc=8)
 system.l2c.cpu_side = system.toL2Bus.master
 
index 5269f41275284d332e08025c4eea8f875a34ddad..33d03f6cfae18d0943017b2befc07f415e541d40 100644 (file)
@@ -45,7 +45,7 @@ cpu.addTwoLevelCacheHierarchy(MyL1Cache(size = '128kB'),
                               MyCache(size = '2MB', latency='10ns'))
 system = System(cpu = cpu,
                 physmem = SimpleMemory(),
-                membus = Bus())
+                membus = CoherentBus())
 system.system_port = system.membus.slave
 system.physmem.port = system.membus.master
 # create the interrupt controller
index 41df45fab2b19ea97247e244e1f066c5997f3fd5..6435e5a7870114621b5769923810c59917abd31e 100644 (file)
@@ -78,7 +78,7 @@ system = FSConfig.makeLinuxAlphaSystem('timing')
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.master
 system.iocache.mem_side = system.membus.slave
index d50a45b070b877823f1ccdc922c1e6dc1317be14..c4e69266d4988b6ed5fee3361902d6b7037a6ca7 100644 (file)
@@ -75,7 +75,7 @@ system = FSConfig.makeLinuxAlphaSystem('timing')
 
 system.cpu = cpus
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.master
 system.iocache.mem_side = system.membus.slave
index c5a3236a58dc323031e2c53b9095fceca3c955f6..dba8f9dd3f00ed0c5b59776515bcf05de7455e8e 100644 (file)
@@ -75,7 +75,7 @@ system = FSConfig.makeLinuxAlphaSystem('timing')
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.master
 system.iocache.mem_side = system.membus.slave
index 57672b0e181b838e23adfe92dceee9655a3ce09d..90f6c7f0be709dc2b1a6698e7c078f076ffb2e27 100644 (file)
@@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave
 
 system.cpu = cpus
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 
 #connect up the l2 cache
 system.l2c = L2(size='4MB', assoc=8)
index 8a03760e33c43a93dc6d46e4dbcfcee449d22b7e..5065f3346afdc0f1239bddfacc6c8d8eab03399a 100644 (file)
@@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 
 #connect up the l2 cache
 system.l2c = L2(size='4MB', assoc=8)
index 1b905a8d05f69c628f4d7e40fd7ba0d013161e03..c9bcc59c79fe65786d7a359ba4fcdfa339b51202 100644 (file)
@@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave
 
 system.cpu = cpus
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 
 #connect up the l2 cache
 system.l2c = L2(size='4MB', assoc=8)
index e4920ddf42d352186a73d37e1cd3295e52932659..eb62b20d802dec596ccb948aa9be47d79ebfaddb 100644 (file)
@@ -75,7 +75,7 @@ system = FSConfig.makeLinuxAlphaSystem('timing')
 
 system.cpu = cpu
 #create the l1/l2 bus
-system.toL2Bus = Bus()
+system.toL2Bus = CoherentBus()
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.master
 system.iocache.mem_side = system.membus.slave