mem: Rename Bus to XBar to better reflect its behaviour
authorAndreas Hansson <andreas.hansson@arm.com>
Sat, 20 Sep 2014 21:18:32 +0000 (17:18 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Sat, 20 Sep 2014 21:18:32 +0000 (17:18 -0400)
This patch changes the name of the Bus classes to XBar to better
reflect the actual timing behaviour. The actual instances in the
config scripts are not renamed, and remain as e.g. iobus or membus.

As part of this renaming, the code has also been clean up slightly,
making use of range-based for loops and tidying up some comments. The
only changes outside the bus/crossbar code is due to the delay
variables in the packet.

--HG--
rename : src/mem/Bus.py => src/mem/XBar.py
rename : src/mem/coherent_bus.cc => src/mem/coherent_xbar.cc
rename : src/mem/coherent_bus.hh => src/mem/coherent_xbar.hh
rename : src/mem/noncoherent_bus.cc => src/mem/noncoherent_xbar.cc
rename : src/mem/noncoherent_bus.hh => src/mem/noncoherent_xbar.hh
rename : src/mem/bus.cc => src/mem/xbar.cc
rename : src/mem/bus.hh => src/mem/xbar.hh

47 files changed:
configs/common/CacheConfig.py
configs/common/FSConfig.py
configs/dram/sweep.py
configs/example/memtest.py
configs/example/ruby_mem_test.py
configs/example/se.py
configs/splash2/cluster.py
configs/splash2/run.py
src/arch/x86/pagetable_walker.cc
src/cpu/BaseCPU.py
src/dev/io_device.cc
src/dev/pcidev.cc
src/dev/x86/intdev.hh
src/mem/Bus.py [deleted file]
src/mem/SConscript
src/mem/XBar.py [new file with mode: 0644]
src/mem/bridge.cc
src/mem/bridge.hh
src/mem/bus.cc [deleted file]
src/mem/bus.hh [deleted file]
src/mem/cache/cache_impl.hh
src/mem/coherent_bus.cc [deleted file]
src/mem/coherent_bus.hh [deleted file]
src/mem/coherent_xbar.cc [new file with mode: 0644]
src/mem/coherent_xbar.hh [new file with mode: 0644]
src/mem/dram_ctrl.cc
src/mem/dramsim2.cc
src/mem/noncoherent_bus.cc [deleted file]
src/mem/noncoherent_bus.hh [deleted file]
src/mem/noncoherent_xbar.cc [new file with mode: 0644]
src/mem/noncoherent_xbar.hh [new file with mode: 0644]
src/mem/packet.hh
src/mem/physical.cc
src/mem/simple_mem.cc
src/mem/xbar.cc [new file with mode: 0644]
src/mem/xbar.hh [new file with mode: 0644]
src/python/m5/params.py
src/python/m5/util/dot_writer.py
tests/configs/base_config.py
tests/configs/memtest-filter.py
tests/configs/memtest-ruby.py
tests/configs/memtest.py
tests/configs/o3-timing-mp-ruby.py
tests/configs/o3-timing-ruby.py
tests/configs/simple-atomic-mp-ruby.py
tests/configs/tgen-dram-ctrl.py
tests/configs/tgen-simple-mem.py

index b467b16561a934330e0cbdfdb5aea2160e9bcf2c..c7a724b3438a85fddda5c6c3d36d5a5a6d20747f 100644 (file)
@@ -71,8 +71,8 @@ def config_cache(options, system):
                                    size=options.l2_size,
                                    assoc=options.l2_assoc)
 
-        system.tol2bus = CoherentBus(clk_domain = system.cpu_clk_domain,
-                                     width = 32)
+        system.tol2bus = CoherentXBar(clk_domain = system.cpu_clk_domain,
+                                      width = 32)
         system.l2.cpu_side = system.tol2bus.master
         system.l2.mem_side = system.membus.slave
 
index cc921229eb446e7aac3c50c2d930e32527702753..e93bd68f2b41177fd0296717a905ac486e1c6a7d 100644 (file)
@@ -50,7 +50,7 @@ class CowIdeDisk(IdeDisk):
     def childImage(self, ci):
         self.image.child.image_file = ci
 
-class MemBus(CoherentBus):
+class MemBus(CoherentXBar):
     badaddr_responder = BadAddr()
     default = Self.badaddr_responder.pio
 
@@ -71,7 +71,7 @@ def makeLinuxAlphaSystem(mem_mode, mdesc = None, ruby = False):
     self.tsunami = BaseTsunami()
 
     # Create the io bus to connect all device ports
-    self.iobus = NoncoherentBus()
+    self.iobus = NoncoherentXBar()
     self.tsunami.attachIO(self.iobus)
 
     self.tsunami.ide.pio = self.iobus.master
@@ -134,7 +134,7 @@ def makeSparcSystem(mem_mode, mdesc = None):
         # generic system
         mdesc = SysConfig()
     self.readfile = mdesc.script()
-    self.iobus = NoncoherentBus()
+    self.iobus = NoncoherentXBar()
     self.membus = MemBus()
     self.bridge = Bridge(delay='50ns')
     self.t1000 = T1000()
@@ -196,7 +196,7 @@ def makeArmSystem(mem_mode, machine_type, mdesc = None,
         mdesc = SysConfig()
 
     self.readfile = mdesc.script()
-    self.iobus = NoncoherentBus()
+    self.iobus = NoncoherentXBar()
     self.membus = MemBus()
     self.membus.badaddr_responder.warn_access = "warn"
     self.bridge = Bridge(delay='50ns')
@@ -299,7 +299,7 @@ def makeLinuxMipsSystem(mem_mode, mdesc = None):
         # generic system
         mdesc = SysConfig()
     self.readfile = mdesc.script()
-    self.iobus = NoncoherentBus()
+    self.iobus = NoncoherentXBar()
     self.membus = MemBus()
     self.bridge = Bridge(delay='50ns')
     self.mem_ranges = [AddrRange('1GB')]
@@ -344,7 +344,7 @@ def connectX86ClassicSystem(x86_sys, numCPUs):
     x86_sys.membus = MemBus()
 
     # North Bridge
-    x86_sys.iobus = NoncoherentBus()
+    x86_sys.iobus = NoncoherentXBar()
     x86_sys.bridge = Bridge(delay='50ns')
     x86_sys.bridge.master = x86_sys.iobus.slave
     x86_sys.bridge.slave = x86_sys.membus.master
@@ -379,7 +379,7 @@ def connectX86ClassicSystem(x86_sys, numCPUs):
 
 def connectX86RubySystem(x86_sys):
     # North Bridge
-    x86_sys.iobus = NoncoherentBus()
+    x86_sys.iobus = NoncoherentXBar()
 
     # add the ide to the list of dma devices that later need to attach to
     # dma controllers
index 631d82e072e948aa2439c9f2c9055670ab71e62d..18a58b2da4eb358e66018cf726b59c29f86d7968 100644 (file)
@@ -82,9 +82,9 @@ if args:
 # and address mapping
 
 # start with the system itself, using a multi-layer 1.5 GHz
-# bus/crossbar, delivering 64 bytes / 5 cycles (one header cycle)
+# crossbar, delivering 64 bytes / 5 cycles (one header cycle)
 # which amounts to 19.2 GByte/s per layer and thus per port
-system = System(membus = NoncoherentBus(width = 16))
+system = System(membus = NoncoherentXBar(width = 16))
 system.clk_domain = SrcClockDomain(clock = '1.5GHz',
                                    voltage_domain =
                                    VoltageDomain(voltage = '1V'))
index feeffa76401498b3612ae5b4fce1c7ab6eac09b0..eaf3a52bd445227b8e6c2439d4330cb746b79173 100644 (file)
@@ -147,7 +147,7 @@ for scale in treespec[:-2]:
 
 # system simulated
 system = System(funcmem = SimpleMemory(in_addr_map = False),
-                funcbus = NoncoherentBus(),
+                funcbus = NoncoherentXBar(),
                 physmem = SimpleMemory(latency = "100ns"),
                 cache_line_size = block_size)
 
@@ -162,7 +162,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 = CoherentBus(width=16)
+          new_bus = CoherentXBar(width=16)
           if (port.role == 'MASTER'):
                new_bus.slave = port
                attach_port = "master"
index 99f6f4a09b7e392b5984ddbad0f21042c49b2f5e..4e2cde79174de044465decb2efed25411287730b 100644 (file)
@@ -106,7 +106,7 @@ cpus = [ MemTest(atomic = False,
 
 system = System(cpu = cpus,
                 funcmem = SimpleMemory(in_addr_map = False),
-                funcbus = NoncoherentBus(),
+                funcbus = NoncoherentXBar(),
                 physmem = SimpleMemory(),
                 clk_domain = SrcClockDomain(clock = options.sys_clock),
                 mem_ranges = [AddrRange(options.mem_size)])
index 8ec90599b8b28326323945c7e8b2ac8c6ad47bd8..f5aef5c2f0f63a18e91d4b3d74e2f6e8b13d0a1c 100644 (file)
@@ -255,7 +255,7 @@ if options.ruby:
             system.cpu[i].dtb.walker.port = ruby_port.slave
 else:
     MemClass = Simulation.setMemClass(options)
-    system.membus = CoherentBus()
+    system.membus = CoherentXBar()
     system.system_port = system.membus.slave
     CacheConfig.config_cache(options, system)
     MemConfig.config_mem(options, system)
index 1ae9a6dd5cc2da31794105effae3e3d81fb55b25..b17c8877eeb76ef9060849e4295d03c0479bd0f6 100644 (file)
@@ -171,7 +171,7 @@ if options.timing:
     for j in xrange(options.numclusters):
         clusters[j].id = j
     for cluster in clusters:
-        cluster.clusterbus = CoherentBus(clock=busFrequency)
+        cluster.clusterbus = CoherentXBar(clock=busFrequency)
         all_l1buses += [cluster.clusterbus]
         cluster.cpus = [TimingSimpleCPU(cpu_id = i + cluster.id,
                                         clock=options.frequency)
@@ -184,7 +184,7 @@ elif options.detailed:
     for j in xrange(options.numclusters):
         clusters[j].id = j
     for cluster in clusters:
-        cluster.clusterbus = CoherentBus(clock=busFrequency)
+        cluster.clusterbus = CoherentXBar(clock=busFrequency)
         all_l1buses += [cluster.clusterbus]
         cluster.cpus = [DerivO3CPU(cpu_id = i + cluster.id,
                                    clock=options.frequency)
@@ -197,7 +197,7 @@ else:
     for j in xrange(options.numclusters):
         clusters[j].id = j
     for cluster in clusters:
-        cluster.clusterbus = CoherentBus(clock=busFrequency)
+        cluster.clusterbus = CoherentXBar(clock=busFrequency)
         all_l1buses += [cluster.clusterbus]
         cluster.cpus = [AtomicSimpleCPU(cpu_id = i + cluster.id,
                                         clock=options.frequency)
@@ -211,10 +211,10 @@ else:
 # ----------------------
 system = System(cpu = all_cpus, l1_ = all_l1s, l1bus_ = all_l1buses,
                 physmem = SimpleMemory(),
-                membus = CoherentBus(clock = busFrequency))
+                membus = CoherentXBar(clock = busFrequency))
 system.clock = '1GHz'
 
-system.toL2bus = CoherentBus(clock = busFrequency)
+system.toL2bus = CoherentXBar(clock = busFrequency)
 system.l2 = L2(size = options.l2size, assoc = 8)
 
 # ----------------------
index 10c9a7f61d16e63fd287b5ca84fe67e14f495506..d542a94370a68c8e3edfbd9d08d0436fd8e309dd 100644 (file)
@@ -196,10 +196,10 @@ else:
 # Create a system, and add system wide objects
 # ----------------------
 system = System(cpu = cpus, physmem = SimpleMemory(),
-                membus = CoherentBus(clock = busFrequency))
+                membus = CoherentXBar(clock = busFrequency))
 system.clock = '1GHz'
 
-system.toL2bus = CoherentBus(clock = busFrequency)
+system.toL2bus = CoherentXBar(clock = busFrequency)
 system.l2 = L2(size = options.l2size, assoc = 8)
 
 # ----------------------
index 3d8cc92927c2ec7a155a81c6d6fc9516d9636e38..db3b4b933512ea43ad55a26507480e99441dd076 100644 (file)
@@ -597,7 +597,7 @@ Walker::WalkerState::recvPacket(PacketPtr pkt)
         assert(!read);
 
         // @todo someone should pay for this
-        pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+        pkt->firstWordDelay = pkt->lastWordDelay = 0;
 
         state = nextState;
         nextState = Ready;
index b7f0b208909b22f690dede7bdaa5b734ae071fb8..8ba90209aacb470b583ed50c59acd5526ced1b96 100644 (file)
@@ -47,7 +47,7 @@ from m5.defines import buildEnv
 from m5.params import *
 from m5.proxy import *
 
-from Bus import CoherentBus
+from XBar import CoherentXBar
 from InstTracer import InstTracer
 from ExeTracer import ExeTracer
 from MemObject import MemObject
@@ -274,8 +274,8 @@ class BaseCPU(MemObject):
                 self.itb_walker_cache = iwc
                 self.dtb_walker_cache = dwc
                 if buildEnv['TARGET_ISA'] in ['arm']:
-                    self.itb_walker_cache_bus = CoherentBus()
-                    self.dtb_walker_cache_bus = CoherentBus()
+                    self.itb_walker_cache_bus = CoherentXBar()
+                    self.dtb_walker_cache_bus = CoherentXBar()
                     self.itb_walker_cache_bus.master = iwc.cpu_side
                     self.dtb_walker_cache_bus.master = dwc.cpu_side
                     self.itb.walker.port = self.itb_walker_cache_bus.slave
@@ -308,7 +308,7 @@ class BaseCPU(MemObject):
         # Set a width of 32 bytes (256-bits), which is four times that
         # of the default bus. The clock of the CPU is inherited by
         # default.
-        self.toL2Bus = CoherentBus(width = 32)
+        self.toL2Bus = CoherentXBar(width = 32)
         self.connectCachedPorts(self.toL2Bus)
         self.l2cache = l2c
         self.toL2Bus.master = self.l2cache.cpu_side
index 0c927651d30060ef3c6c507f41cb6be900fd8ca0..b118294f7d9eefa5797d834ffe5bacd1566acde0 100644 (file)
@@ -42,7 +42,7 @@
  */
 
 #include "base/trace.hh"
-#include "debug/BusAddrRanges.hh"
+#include "debug/AddrRanges.hh"
 #include "dev/io_device.hh"
 #include "sim/system.hh"
 
@@ -55,7 +55,7 @@ Tick
 PioPort::recvAtomic(PacketPtr pkt)
 {
     // @todo: We need to pay for this and not just zero it out
-    pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+    pkt->firstWordDelay = pkt->lastWordDelay = 0;
 
     return pkt->isRead() ? device->read(pkt) : device->write(pkt);
 }
@@ -113,7 +113,7 @@ BasicPioDevice::getAddrRanges() const
 {
     assert(pioSize != 0);
     AddrRangeList ranges;
-    DPRINTF(BusAddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize);
+    DPRINTF(AddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize);
     ranges.push_back(RangeSize(pioAddr, pioSize));
     return ranges;
 }
index adc12bb55aa24fa879bb6d2c23273c1f3bea9633..b27547519b89627009b3d17465352e9552fa1947 100644 (file)
@@ -80,7 +80,7 @@ PciDevice::PciConfigPort::recvAtomic(PacketPtr pkt)
     assert(pkt->getAddr() >= configAddr &&
            pkt->getAddr() < configAddr + PCI_CONFIG_SIZE);
     // @todo someone should pay for this
-    pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+    pkt->firstWordDelay = pkt->lastWordDelay = 0;
     return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt);
 }
 
index 078ea2b6fcc3f5f87c0045c0cf1becac89a00a2e..294a2b887e3489aa1b87b3c1d03cf1bab1357bcb 100644 (file)
@@ -82,7 +82,7 @@ class IntDevice
         Tick recvMessage(PacketPtr pkt)
         {
             // @todo someone should pay for this
-            pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+            pkt->firstWordDelay = pkt->lastWordDelay = 0;
             return device->recvMessage(pkt);
         }
     };
diff --git a/src/mem/Bus.py b/src/mem/Bus.py
deleted file mode 100644 (file)
index 06fff93..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-# 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.
-#
-# 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: Nathan Binkert
-#          Andreas Hansson
-
-from MemObject import MemObject
-from System import System
-from m5.params import *
-from m5.proxy import *
-from m5.SimObject import SimObject
-
-class BaseBus(MemObject):
-    type = 'BaseBus'
-    abstract = True
-    cxx_header = "mem/bus.hh"
-    slave = VectorSlavePort("vector port for connecting masters")
-    master = VectorMasterPort("vector port for connecting slaves")
-    header_cycles = Param.Cycles(1, "cycles of overhead per transaction")
-    width = Param.Unsigned(8, "bus width (bytes)")
-
-    # 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'
-    cxx_header = "mem/noncoherent_bus.hh"
-
-class CoherentBus(BaseBus):
-    type = 'CoherentBus'
-    cxx_header = "mem/coherent_bus.hh"
-
-    system = Param.System(Parent.any, "System that the bus belongs to.")
-    snoop_filter = Param.SnoopFilter(NULL, "Selected snoop filter for the bus.")
-
-class SnoopFilter(SimObject):
-    type = 'SnoopFilter'
-    cxx_header = "mem/snoop_filter.hh"
-    lookup_latency = Param.Cycles(3, "lookup latency (cycles)")
-
-    system = Param.System(Parent.any, "System that the bus belongs to.")
index c351661b87fdfaa7ffe1862e0d465cb2fa6df79a..35f2e9ce444c3da254b5a4026f211de0fcc37fea 100644 (file)
@@ -39,28 +39,28 @@ if env['HAVE_PROTOBUF']:
 SimObject('AbstractMemory.py')
 SimObject('AddrMapper.py')
 SimObject('Bridge.py')
-SimObject('Bus.py')
 SimObject('DRAMCtrl.py')
 SimObject('MemObject.py')
 SimObject('SimpleMemory.py')
+SimObject('XBar.py')
 
 Source('abstract_mem.cc')
 Source('addr_mapper.cc')
 Source('bridge.cc')
-Source('bus.cc')
-Source('coherent_bus.cc')
+Source('coherent_xbar.cc')
 Source('dram_ctrl.cc')
 Source('mem_object.cc')
 Source('mport.cc')
-Source('noncoherent_bus.cc')
+Source('noncoherent_xbar.cc')
 Source('packet.cc')
 Source('port.cc')
 Source('packet_queue.cc')
-Source('tport.cc')
 Source('port_proxy.cc')
-Source('simple_mem.cc')
 Source('physical.cc')
+Source('simple_mem.cc')
 Source('snoop_filter.cc')
+Source('tport.cc')
+Source('xbar.cc')
 
 if env['TARGET_ISA'] != 'null':
     Source('fs_translating_port_proxy.cc')
@@ -74,13 +74,13 @@ if env['HAVE_DRAMSIM']:
     Source('dramsim2_wrapper.cc')
     Source('dramsim2.cc')
 
-DebugFlag('BaseBus')
-DebugFlag('BusAddrRanges')
-DebugFlag('CoherentBus')
-DebugFlag('NoncoherentBus')
+DebugFlag('AddrRanges')
+DebugFlag('BaseXBar')
+DebugFlag('CoherentXBar')
+DebugFlag('NoncoherentXBar')
 DebugFlag('SnoopFilter')
-CompoundFlag('Bus', ['BaseBus', 'BusAddrRanges', 'CoherentBus',
-                     'NoncoherentBus', 'SnoopFilter'])
+CompoundFlag('XBar', ['BaseXBar', 'CoherentXBar', 'NoncoherentXBar',
+                      'SnoopFilter'])
 
 DebugFlag('Bridge')
 DebugFlag('CommMonitor')
diff --git a/src/mem/XBar.py b/src/mem/XBar.py
new file mode 100644 (file)
index 0000000..2aeefe1
--- /dev/null
@@ -0,0 +1,85 @@
+# 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.
+#
+# 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: Nathan Binkert
+#          Andreas Hansson
+
+from MemObject import MemObject
+from System import System
+from m5.params import *
+from m5.proxy import *
+from m5.SimObject import SimObject
+
+class BaseXBar(MemObject):
+    type = 'BaseXBar'
+    abstract = True
+    cxx_header = "mem/xbar.hh"
+    slave = VectorSlavePort("vector port for connecting masters")
+    master = VectorMasterPort("vector port for connecting slaves")
+    header_cycles = Param.Cycles(1, "cycles of overhead per transaction")
+    width = Param.Unsigned(8, "xbar width (bytes)")
+
+    # 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
+    # xbar configuration.
+    use_default_range = Param.Bool(False, "Perform address mapping for " \
+                                       "the default port")
+
+class NoncoherentXBar(BaseXBar):
+    type = 'NoncoherentXBar'
+    cxx_header = "mem/noncoherent_xbar.hh"
+
+class CoherentXBar(BaseXBar):
+    type = 'CoherentXBar'
+    cxx_header = "mem/coherent_xbar.hh"
+
+    system = Param.System(Parent.any, "System that the crossbar belongs to.")
+    snoop_filter = Param.SnoopFilter(NULL, "Selected snoop filter.")
+
+class SnoopFilter(SimObject):
+    type = 'SnoopFilter'
+    cxx_header = "mem/snoop_filter.hh"
+    lookup_latency = Param.Cycles(3, "lookup latency (cycles)")
+
+    system = Param.System(Parent.any, "System that the crossbar belongs to.")
index 3b101ceab649b84af173f3279d2fcc8882164b7d..085c97b53ef18757675072ddcdb0f79415bedbb7 100644 (file)
@@ -44,7 +44,7 @@
 
 /**
  * @file
- * Implementation of a memory-mapped bus bridge that connects a master
+ * Implementation of a memory-mapped bridge that connects a master
  * and a slave through a request and response queue.
  */
 
@@ -108,7 +108,7 @@ Bridge::init()
 {
     // make sure both sides are connected and have the same block size
     if (!slavePort.isConnected() || !masterPort.isConnected())
-        fatal("Both ports of bus bridge are not connected to a bus.\n");
+        fatal("Both ports of a bridge must be connected.\n");
 
     // notify the master side  of our address ranges
     slavePort.sendRangeChange();
@@ -137,7 +137,7 @@ Bridge::BridgeMasterPort::recvTimingResp(PacketPtr pkt)
     DPRINTF(Bridge, "Request queue size: %d\n", transmitList.size());
 
     // @todo: We need to pay for this and not just zero it out
-    pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+    pkt->firstWordDelay = pkt->lastWordDelay = 0;
 
     slavePort.schedTimingResp(pkt, bridge.clockEdge(delay));
 
@@ -181,7 +181,7 @@ Bridge::BridgeSlavePort::recvTimingReq(PacketPtr pkt)
 
         if (!retryReq) {
             // @todo: We need to pay for this and not just zero it out
-            pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+            pkt->firstWordDelay = pkt->lastWordDelay = 0;
 
             masterPort.schedTimingReq(pkt, bridge.clockEdge(delay));
         }
@@ -209,7 +209,7 @@ Bridge::BridgeMasterPort::schedTimingReq(PacketPtr pkt, Tick when)
 {
     // If we expect to see a response, we need to restore the source
     // and destination field that is potentially changed by a second
-    // bus
+    // crossbar
     if (!pkt->memInhibitAsserted() && pkt->needsResponse()) {
         // Update the sender state so we can deal with the response
         // appropriately
@@ -242,7 +242,7 @@ Bridge::BridgeSlavePort::schedTimingResp(PacketPtr pkt, Tick when)
     pkt->setDest(req_state->origSrc);
     delete req_state;
 
-    // the bridge assumes that at least one bus has set the
+    // the bridge assumes that at least one crossbar has set the
     // destination field of the packet
     assert(pkt->isDestValid());
     DPRINTF(Bridge, "response, new dest %d\n", pkt->getDest());
index e672c1f7a5111edfc0a9cc14d8f1f8676704dd98..a79d6748489cbea4010b74baebca61cb32f6d906 100644 (file)
@@ -44,7 +44,7 @@
 
 /**
  * @file
- * Declaration of a memory-mapped bus bridge that connects a master
+ * Declaration of a memory-mapped bridge that connects a master
  * and a slave through a request and response queue.
  */
 
@@ -58,7 +58,7 @@
 #include "params/Bridge.hh"
 
 /**
- * A bridge is used to interface two different busses (or in general a
+ * A bridge is used to interface two different crossbars (or in general a
  * memory-mapped master and slave), with buffering for requests and
  * responses. The bridge has a fixed delay for packets passing through
  * it and responds to a fixed set of address ranges.
@@ -125,8 +125,7 @@ class Bridge : public MemObject
         Bridge& bridge;
 
         /**
-         * Master port on the other side of the bridge (connected to
-         * the other bus).
+         * Master port on the other side of the bridge.
          */
         BridgeMasterPort& masterPort;
 
@@ -241,8 +240,7 @@ class Bridge : public MemObject
         Bridge& bridge;
 
         /**
-         * The slave port on the other side of the bridge (connected
-         * to the other bus).
+         * The slave port on the other side of the bridge.
          */
         BridgeSlavePort& slavePort;
 
@@ -343,4 +341,4 @@ class Bridge : public MemObject
     Bridge(Params *p);
 };
 
-#endif //__MEM_BUS_HH__
+#endif //__MEM_BRIDGE_HH__
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
deleted file mode 100644 (file)
index 730c612..0000000
+++ /dev/null
@@ -1,622 +0,0 @@
-/*
- * Copyright (c) 2011-2013 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/Drain.hh"
-#include "mem/bus.hh"
-
-BaseBus::BaseBus(const BaseBusParams *p)
-    : MemObject(p),
-      headerCycles(p->header_cycles), width(p->width),
-      gotAddrRanges(p->port_default_connection_count +
-                          p->port_master_connection_count, false),
-      gotAllAddrRanges(false), defaultPortID(InvalidPortID),
-      useDefaultRange(p->use_default_range)
-{}
-
-BaseBus::~BaseBus()
-{
-    for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end();
-         ++m) {
-        delete *m;
-    }
-
-    for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end();
-         ++s) {
-        delete *s;
-    }
-}
-
-void
-BaseBus::init()
-{
-}
-
-BaseMasterPort &
-BaseBus::getMasterPort(const std::string &if_name, PortID idx)
-{
-    if (if_name == "master" && idx < masterPorts.size()) {
-        // the master port index translates directly to the vector position
-        return *masterPorts[idx];
-    } else  if (if_name == "default") {
-        return *masterPorts[defaultPortID];
-    } else {
-        return MemObject::getMasterPort(if_name, idx);
-    }
-}
-
-BaseSlavePort &
-BaseBus::getSlavePort(const std::string &if_name, PortID idx)
-{
-    if (if_name == "slave" && idx < slavePorts.size()) {
-        // the slave port index translates directly to the vector position
-        return *slavePorts[idx];
-    } else {
-        return MemObject::getSlavePort(if_name, idx);
-    }
-}
-
-void
-BaseBus::calcPacketTiming(PacketPtr pkt)
-{
-    // the bus will be called at a time that is not necessarily
-    // coinciding with its own clock, so start by determining how long
-    // until the next clock edge (could be zero)
-    Tick offset = clockEdge() - curTick();
-
-    // determine how many cycles are needed to send the data
-    unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0;
-
-    // before setting the bus delay fields of the packet, ensure that
-    // the delay from any previous bus has been accounted for
-    if (pkt->busFirstWordDelay != 0 || pkt->busLastWordDelay != 0)
-        panic("Packet %s already has bus delay (%d, %d) that should be "
-              "accounted for.\n", pkt->cmdString(), pkt->busFirstWordDelay,
-              pkt->busLastWordDelay);
-
-    // The first word will be delivered on the cycle after the header.
-    pkt->busFirstWordDelay = (headerCycles + 1) * clockPeriod() + offset;
-
-    // Note that currently busLastWordDelay can be smaller than
-    // busFirstWordDelay if the packet has no data
-    pkt->busLastWordDelay = (headerCycles + dataCycles) * clockPeriod() +
-        offset;
-}
-
-template <typename SrcType, typename DstType>
-BaseBus::Layer<SrcType,DstType>::Layer(DstType& _port, BaseBus& _bus,
-                                       const std::string& _name) :
-    port(_port), bus(_bus), _name(_name), state(IDLE), drainManager(NULL),
-    waitingForPeer(NULL), releaseEvent(this)
-{
-}
-
-template <typename SrcType, typename DstType>
-void BaseBus::Layer<SrcType,DstType>::occupyLayer(Tick until)
-{
-    // ensure the state is busy at this point, as the bus should
-    // transition from idle as soon as it has decided to forward the
-    // packet to prevent any follow-on calls to sendTiming seeing an
-    // unoccupied bus
-    assert(state == BUSY);
-
-    // until should never be 0 as express snoops never occupy the bus
-    assert(until != 0);
-    bus.schedule(releaseEvent, until);
-
-    // account for the occupied ticks
-    occupancy += until - curTick();
-
-    DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n",
-            curTick(), until);
-}
-
-template <typename SrcType, typename DstType>
-bool
-BaseBus::Layer<SrcType,DstType>::tryTiming(SrcType* src_port)
-{
-    // if we are in the retry state, we will not see anything but the
-    // retrying port (or in the case of the snoop ports the snoop
-    // response port that mirrors the actual slave port) as we leave
-    // this state again in zero time if the peer does not immediately
-    // call the bus when receiving the retry
-
-    // first we see if the layer is busy, next we check if the
-    // destination port is already engaged in a transaction waiting
-    // for a retry from the peer
-    if (state == BUSY || waitingForPeer != NULL) {
-        // the port should not be waiting already
-        assert(std::find(waitingForLayer.begin(), waitingForLayer.end(),
-                         src_port) == waitingForLayer.end());
-
-        // put the port at the end of the retry list waiting for the
-        // layer to be freed up (and in the case of a busy peer, for
-        // that transaction to go through, and then the bus to free
-        // up)
-        waitingForLayer.push_back(src_port);
-        return false;
-    }
-
-    // update the state to busy
-    state = BUSY;
-
-    return true;
-}
-
-template <typename SrcType, typename DstType>
-void
-BaseBus::Layer<SrcType,DstType>::succeededTiming(Tick busy_time)
-{
-    // we should have gone from idle or retry to busy in the tryTiming
-    // test
-    assert(state == BUSY);
-
-    // occupy the bus accordingly
-    occupyLayer(busy_time);
-}
-
-template <typename SrcType, typename DstType>
-void
-BaseBus::Layer<SrcType,DstType>::failedTiming(SrcType* src_port,
-                                              Tick busy_time)
-{
-    // ensure no one got in between and tried to send something to
-    // this port
-    assert(waitingForPeer == NULL);
-
-    // if the source port is the current retrying one or not, we have
-    // failed in forwarding and should track that we are now waiting
-    // for the peer to send a retry
-    waitingForPeer = src_port;
-
-    // we should have gone from idle or retry to busy in the tryTiming
-    // test
-    assert(state == BUSY);
-
-    // occupy the bus accordingly
-    occupyLayer(busy_time);
-}
-
-template <typename SrcType, typename DstType>
-void
-BaseBus::Layer<SrcType,DstType>::releaseLayer()
-{
-    // releasing the bus means we should now be idle
-    assert(state == BUSY);
-    assert(!releaseEvent.scheduled());
-
-    // update the state
-    state = IDLE;
-
-    // bus layer is now idle, so if someone is waiting we can retry
-    if (!waitingForLayer.empty()) {
-        // there is no point in sending a retry if someone is still
-        // waiting for the peer
-        if (waitingForPeer == NULL)
-            retryWaiting();
-    } else if (waitingForPeer == NULL && drainManager) {
-        DPRINTF(Drain, "Bus done draining, signaling drain manager\n");
-        //If we weren't able to drain before, do it now.
-        drainManager->signalDrainDone();
-        // Clear the drain event once we're done with it.
-        drainManager = NULL;
-    }
-}
-
-template <typename SrcType, typename DstType>
-void
-BaseBus::Layer<SrcType,DstType>::retryWaiting()
-{
-    // this should never be called with no one waiting
-    assert(!waitingForLayer.empty());
-
-    // we always go to retrying from idle
-    assert(state == IDLE);
-
-    // update the state
-    state = RETRY;
-
-    // set the retrying port to the front of the retry list and pop it
-    // off the list
-    SrcType* retryingPort = waitingForLayer.front();
-    waitingForLayer.pop_front();
-
-    // tell the port to retry, which in some cases ends up calling the
-    // bus
-    retryingPort->sendRetry();
-
-    // If the bus is still in the retry state, sendTiming wasn't
-    // called in zero time (e.g. the cache does this), burn a cycle
-    if (state == RETRY) {
-        // update the state to busy and reset the retrying port, we
-        // have done our bit and sent the retry
-        state = BUSY;
-
-        // occupy the bus layer until the next cycle ends
-        occupyLayer(bus.clockEdge(Cycles(1)));
-    }
-}
-
-template <typename SrcType, typename DstType>
-void
-BaseBus::Layer<SrcType,DstType>::recvRetry()
-{
-    // we should never get a retry without having failed to forward
-    // something to this port
-    assert(waitingForPeer != NULL);
-
-    // add the port where the failed packet originated to the front of
-    // the waiting ports for the layer, this allows us to call retry
-    // on the port immediately if the bus layer is idle
-    waitingForLayer.push_front(waitingForPeer);
-
-    // we are no longer waiting for the peer
-    waitingForPeer = NULL;
-
-    // if the bus layer is idle, retry this port straight away, if we
-    // are busy, then simply let the port wait for its turn
-    if (state == IDLE) {
-        retryWaiting();
-    } else {
-        assert(state == BUSY);
-    }
-}
-
-PortID
-BaseBus::findPort(Addr addr)
-{
-    // we should never see any address lookups before we've got the
-    // ranges of all connected slave modules
-    assert(gotAllAddrRanges);
-
-    // Check the cache
-    PortID dest_id = checkPortCache(addr);
-    if (dest_id != InvalidPortID)
-        return dest_id;
-
-    // Check the address map interval tree
-    PortMapConstIter i = portMap.find(addr);
-    if (i != portMap.end()) {
-        dest_id = i->second;
-        updatePortCache(dest_id, i->first);
-        return dest_id;
-    }
-
-    // Check if this matches the default range
-    if (useDefaultRange) {
-        if (defaultRange.contains(addr)) {
-            DPRINTF(BusAddrRanges, "  found addr %#llx on default\n",
-                    addr);
-            return defaultPortID;
-        }
-    } else if (defaultPortID != InvalidPortID) {
-        DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, "
-                "will use default port\n", addr);
-        return defaultPortID;
-    }
-
-    // we should use the range for the default port and it did not
-    // match, or the default port is not set
-    fatal("Unable to find destination for addr %#llx on bus %s\n", addr,
-          name());
-}
-
-/** Function called by the port when the bus is receiving a range change.*/
-void
-BaseBus::recvRangeChange(PortID master_port_id)
-{
-    DPRINTF(BusAddrRanges, "Received range change from slave port %s\n",
-            masterPorts[master_port_id]->getSlavePort().name());
-
-    // remember that we got a range from this master port and thus the
-    // connected slave module
-    gotAddrRanges[master_port_id] = true;
-
-    // update the global flag
-    if (!gotAllAddrRanges) {
-        // take a logical AND of all the ports and see if we got
-        // ranges from everyone
-        gotAllAddrRanges = true;
-        std::vector<bool>::const_iterator r = gotAddrRanges.begin();
-        while (gotAllAddrRanges &&  r != gotAddrRanges.end()) {
-            gotAllAddrRanges &= *r++;
-        }
-        if (gotAllAddrRanges)
-            DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n");
-    }
-
-    // note that we could get the range from the default port at any
-    // point in time, and we cannot assume that the default range is
-    // set before the other ones are, so we do additional checks once
-    // all ranges are provided
-    if (master_port_id == defaultPortID) {
-        // only update if we are indeed checking ranges for the
-        // default port since the port might not have a valid range
-        // otherwise
-        if (useDefaultRange) {
-            AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
-
-            if (ranges.size() != 1)
-                fatal("Bus %s may only have a single default range",
-                      name());
-
-            defaultRange = ranges.front();
-        }
-    } else {
-        // the ports are allowed to update their address ranges
-        // dynamically, so remove any existing entries
-        if (gotAddrRanges[master_port_id]) {
-            for (PortMapIter p = portMap.begin(); p != portMap.end(); ) {
-                if (p->second == master_port_id)
-                    // erasing invalidates the iterator, so advance it
-                    // before the deletion takes place
-                    portMap.erase(p++);
-                else
-                    p++;
-            }
-        }
-
-        AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
-
-        for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) {
-            DPRINTF(BusAddrRanges, "Adding range %s for id %d\n",
-                    r->to_string(), master_port_id);
-            if (portMap.insert(*r, master_port_id) == portMap.end()) {
-                PortID conflict_id = portMap.find(*r)->second;
-                fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
-                      name(),
-                      masterPorts[master_port_id]->getSlavePort().name(),
-                      masterPorts[conflict_id]->getSlavePort().name());
-            }
-        }
-    }
-
-    // if we have received ranges from all our neighbouring slave
-    // modules, go ahead and tell our connected master modules in
-    // turn, this effectively assumes a tree structure of the system
-    if (gotAllAddrRanges) {
-        DPRINTF(BusAddrRanges, "Aggregating bus ranges\n");
-        busRanges.clear();
-
-        // start out with the default range
-        if (useDefaultRange) {
-            if (!gotAddrRanges[defaultPortID])
-                fatal("Bus %s uses default range, but none provided",
-                      name());
-
-            busRanges.push_back(defaultRange);
-            DPRINTF(BusAddrRanges, "-- Adding default %s\n",
-                    defaultRange.to_string());
-        }
-
-        // merge all interleaved ranges and add any range that is not
-        // a subset of the default range
-        std::vector<AddrRange> intlv_ranges;
-        for (AddrRangeMap<PortID>::const_iterator r = portMap.begin();
-             r != portMap.end(); ++r) {
-            // if the range is interleaved then save it for now
-            if (r->first.interleaved()) {
-                // if we already got interleaved ranges that are not
-                // part of the same range, then first do a merge
-                // before we add the new one
-                if (!intlv_ranges.empty() &&
-                    !intlv_ranges.back().mergesWith(r->first)) {
-                    DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n",
-                            intlv_ranges.size());
-                    AddrRange merged_range(intlv_ranges);
-                    // next decide if we keep the merged range or not
-                    if (!(useDefaultRange &&
-                          merged_range.isSubset(defaultRange))) {
-                        busRanges.push_back(merged_range);
-                        DPRINTF(BusAddrRanges, "-- Adding merged range %s\n",
-                                merged_range.to_string());
-                    }
-                    intlv_ranges.clear();
-                }
-                intlv_ranges.push_back(r->first);
-            } else {
-                // keep the current range if not a subset of the default
-                if (!(useDefaultRange &&
-                      r->first.isSubset(defaultRange))) {
-                    busRanges.push_back(r->first);
-                    DPRINTF(BusAddrRanges, "-- Adding range %s\n",
-                            r->first.to_string());
-                }
-            }
-        }
-
-        // if there is still interleaved ranges waiting to be merged,
-        // go ahead and do it
-        if (!intlv_ranges.empty()) {
-            DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n",
-                    intlv_ranges.size());
-            AddrRange merged_range(intlv_ranges);
-            if (!(useDefaultRange && merged_range.isSubset(defaultRange))) {
-                busRanges.push_back(merged_range);
-                DPRINTF(BusAddrRanges, "-- Adding merged range %s\n",
-                        merged_range.to_string());
-            }
-        }
-
-        // also check that no range partially overlaps with the
-        // default range, this has to be done after all ranges are set
-        // as there are no guarantees for when the default range is
-        // update with respect to the other ones
-        if (useDefaultRange) {
-            for (AddrRangeConstIter r = busRanges.begin();
-                 r != busRanges.end(); ++r) {
-                // see if the new range is partially
-                // overlapping the default range
-                if (r->intersects(defaultRange) &&
-                    !r->isSubset(defaultRange))
-                    fatal("Range %s intersects the "                    \
-                          "default range of %s but is not a "           \
-                          "subset\n", r->to_string(), name());
-            }
-        }
-
-        // tell all our neighbouring master ports that our address
-        // ranges have changed
-        for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end();
-             ++s)
-            (*s)->sendRangeChange();
-    }
-
-    clearPortCache();
-}
-
-AddrRangeList
-BaseBus::getAddrRanges() const
-{
-    // we should never be asked without first having sent a range
-    // change, and the latter is only done once we have all the ranges
-    // of the connected devices
-    assert(gotAllAddrRanges);
-
-    // at the moment, this never happens, as there are no cycles in
-    // the range queries and no devices on the master side of a bus
-    // (CPU, cache, bridge etc) actually care about the ranges of the
-    // ports they are connected to
-
-    DPRINTF(BusAddrRanges, "Received address range request\n");
-
-    return busRanges;
-}
-
-void
-BaseBus::regStats()
-{
-    using namespace Stats;
-
-    transDist
-        .init(MemCmd::NUM_MEM_CMDS)
-        .name(name() + ".trans_dist")
-        .desc("Transaction distribution")
-        .flags(nozero);
-
-    // get the string representation of the commands
-    for (int i = 0; i < MemCmd::NUM_MEM_CMDS; i++) {
-        MemCmd cmd(i);
-        const std::string &cstr = cmd.toString();
-        transDist.subname(i, cstr);
-    }
-
-    pktCount
-        .init(slavePorts.size(), masterPorts.size())
-        .name(name() + ".pkt_count")
-        .desc("Packet count per connected master and slave (bytes)")
-        .flags(total | nozero | nonan);
-
-    totPktSize
-        .init(slavePorts.size(), masterPorts.size())
-        .name(name() + ".tot_pkt_size")
-        .desc("Cumulative packet size per connected master and slave (bytes)")
-        .flags(total | nozero | nonan);
-
-    // both the packet count and total size are two-dimensional
-    // vectors, indexed by slave port id and master port id, thus the
-    // neighbouring master and slave, they do not differentiate what
-    // came from the master and was forwarded to the slave (requests
-    // and snoop responses) and what came from the slave and was
-    // forwarded to the master (responses and snoop requests)
-    for (int i = 0; i < slavePorts.size(); i++) {
-        pktCount.subname(i, slavePorts[i]->getMasterPort().name());
-        totPktSize.subname(i, slavePorts[i]->getMasterPort().name());
-        for (int j = 0; j < masterPorts.size(); j++) {
-            pktCount.ysubname(j, masterPorts[j]->getSlavePort().name());
-            totPktSize.ysubname(j, masterPorts[j]->getSlavePort().name());
-        }
-    }
-}
-
-template <typename SrcType, typename DstType>
-unsigned int
-BaseBus::Layer<SrcType,DstType>::drain(DrainManager *dm)
-{
-    //We should check that we're not "doing" anything, and that noone is
-    //waiting. We might be idle but have someone waiting if the device we
-    //contacted for a retry didn't actually retry.
-    if (state != IDLE) {
-        DPRINTF(Drain, "Bus not drained\n");
-        drainManager = dm;
-        return 1;
-    }
-    return 0;
-}
-
-template <typename SrcType, typename DstType>
-void
-BaseBus::Layer<SrcType,DstType>::regStats()
-{
-    using namespace Stats;
-
-    occupancy
-        .name(name() + ".occupancy")
-        .desc("Layer occupancy (ticks)")
-        .flags(nozero);
-
-    utilization
-        .name(name() + ".utilization")
-        .desc("Layer utilization (%)")
-        .precision(1)
-        .flags(nozero);
-
-    utilization = 100 * occupancy / simTicks;
-}
-
-/**
- * Bus layer template instantiations. Could be removed with _impl.hh
- * file, but since there are only two given options (MasterPort and
- * SlavePort) it seems a bit excessive at this point.
- */
-template class BaseBus::Layer<SlavePort,MasterPort>;
-template class BaseBus::Layer<MasterPort,SlavePort>;
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
deleted file mode 100644 (file)
index f01a3ae..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * Copyright (c) 2011-2013 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 an abstract bus base class.
- */
-
-#ifndef __MEM_BUS_HH__
-#define __MEM_BUS_HH__
-
-#include <deque>
-
-#include "base/addr_range_map.hh"
-#include "base/types.hh"
-#include "mem/mem_object.hh"
-#include "params/BaseBus.hh"
-#include "sim/stats.hh"
-
-/**
- * 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
-{
-
-  protected:
-
-    /**
-     * A bus layer is an internal bus structure with its own flow
-     * control and arbitration. Hence, a single-layer bus mimics a
-     * traditional off-chip tri-state bus (like PCI), where only one
-     * set of wires are shared. For on-chip buses, a good starting
-     * point is to have three layers, for requests, responses, and
-     * snoop responses respectively (snoop requests are instantaneous
-     * and do not need any flow control or arbitration). This case is
-     * similar to AHB and some OCP configurations.
-     *
-     * As a further extensions beyond the three-layer bus, a future
-     * multi-layer bus has with one layer per connected slave port
-     * provides a full or partial crossbar, like AXI, OCP, PCIe etc.
-     *
-     * The template parameter, PortClass, indicates the destination
-     * port type for the bus. The retry list holds either master ports
-     * or slave ports, depending on the direction of the layer. Thus,
-     * a request layer has a retry list containing slave ports,
-     * whereas a response layer holds master ports.
-     */
-    template <typename SrcType, typename DstType>
-    class Layer : public Drainable
-    {
-
-      public:
-
-        /**
-         * Create a bus layer and give it a name. The bus layer uses
-         * the bus an event manager.
-         *
-         * @param _port destination port the layer converges at
-         * @param _bus the bus this layer belongs to
-         * @param _name the layer's name
-         */
-        Layer(DstType& _port, BaseBus& _bus, const std::string& _name);
-
-        /**
-         * Drain according to the normal semantics, so that the bus
-         * can tell the layer to drain, and pass an event to signal
-         * back when drained.
-         *
-         * @param de drain event to call once drained
-         *
-         * @return 1 if busy or waiting to retry, or 0 if idle
-         */
-        unsigned int drain(DrainManager *dm);
-
-        /**
-         * Get the bus layer's name
-         */
-        const std::string name() const { return bus.name() + _name; }
-
-
-        /**
-         * Determine if the bus layer accepts a packet from a specific
-         * port. If not, the port in question is also added to the
-         * retry list. In either case the state of the layer is
-         * updated accordingly.
-         *
-         * @param port Source port presenting the packet
-         *
-         * @return True if the bus layer accepts the packet
-         */
-        bool tryTiming(SrcType* src_port);
-
-        /**
-         * Deal with a destination port accepting a packet by potentially
-         * removing the source port from the retry list (if retrying) and
-         * occupying the bus layer accordingly.
-         *
-         * @param busy_time Time to spend as a result of a successful send
-         */
-        void succeededTiming(Tick busy_time);
-
-        /**
-         * Deal with a destination port not accepting a packet by
-         * potentially adding the source port to the retry list (if
-         * not already at the front) and occupying the bus layer
-         * accordingly.
-         *
-         * @param src_port Source port
-         * @param busy_time Time to spend as a result of a failed send
-         */
-        void failedTiming(SrcType* src_port, Tick busy_time);
-
-        /** Occupy the bus layer until until */
-        void occupyLayer(Tick until);
-
-        /**
-         * Send a retry to the port at the head of waitingForLayer. The
-         * caller must ensure that the list is not empty.
-         */
-        void retryWaiting();
-
-        /**
-         * Handle a retry from a neighbouring module. This wraps
-         * retryWaiting by verifying that there are ports waiting
-         * before calling retryWaiting.
-         */
-        void recvRetry();
-
-        /**
-         * Register stats for the layer
-         */
-        void regStats();
-
-      private:
-
-        /** The destination port this layer converges at. */
-        DstType& port;
-
-        /** The bus this layer is a part of. */
-        BaseBus& bus;
-
-        /** A name for this layer. */
-        std::string _name;
-
-        /**
-         * We declare an enum to track the state of the bus layer. The
-         * starting point is an idle state where the bus layer is
-         * waiting for a packet to arrive. Upon arrival, the bus layer
-         * transitions to the busy state, where it remains either
-         * until the packet transfer is done, or the header time is
-         * spent. Once the bus layer leaves the busy state, it can
-         * either go back to idle, if no packets have arrived while it
-         * was busy, or the bus layer goes on to retry the first port
-         * in waitingForLayer. A similar transition takes place from
-         * idle to retry if the bus layer receives a retry from one of
-         * its connected ports. The retry state lasts until the port
-         * in questions calls sendTiming and returns control to the
-         * bus layer, or goes to a busy state if the port does not
-         * immediately react to the retry by calling sendTiming.
-         */
-        enum State { IDLE, BUSY, RETRY };
-
-        /** track the state of the bus layer */
-        State state;
-
-        /** manager to signal when drained */
-        DrainManager *drainManager;
-
-        /**
-         * A deque of ports that retry should be called on because
-         * the original send was delayed due to a busy layer.
-         */
-        std::deque<SrcType*> waitingForLayer;
-
-        /**
-         * Track who is waiting for the retry when receiving it from a
-         * peer. If no port is waiting NULL is stored.
-         */
-        SrcType* waitingForPeer;
-
-        /**
-         * Release the bus layer after being occupied and return to an
-         * idle state where we proceed to send a retry to any
-         * potential waiting port, or drain if asked to do so.
-         */
-        void releaseLayer();
-
-        /** event used to schedule a release of the layer */
-        EventWrapper<Layer, &Layer::releaseLayer> releaseEvent;
-
-        /**
-         * Stats for occupancy and utilization. These stats capture
-         * the time the bus spends in the busy state and are thus only
-         * relevant when the memory system is in timing mode.
-         */
-        Stats::Scalar occupancy;
-        Stats::Formula utilization;
-
-    };
-
-    /** cycles of overhead per transaction */
-    const Cycles headerCycles;
-    /** the width of the bus in bytes */
-    const uint32_t width;
-
-    typedef AddrRangeMap<PortID>::iterator PortMapIter;
-    typedef AddrRangeMap<PortID>::const_iterator PortMapConstIter;
-    AddrRangeMap<PortID> portMap;
-
-    /** all contigous ranges seen by this bus */
-    AddrRangeList busRanges;
-
-    AddrRange defaultRange;
-
-    /**
-     * Function called by the port when the bus is recieving a range change.
-     *
-     * @param master_port_id id of the port that received the change
-     */
-    void recvRangeChange(PortID master_port_id);
-
-    /** Find which port connected to this bus (if any) should be given a packet
-     * with this address.
-     * @param addr Address to find port for.
-     * @return id of port that the packet should be sent out of.
-     */
-    PortID findPort(Addr addr);
-
-    // Cache for the findPort function storing recently used ports from portMap
-    struct PortCache {
-        bool valid;
-        PortID id;
-        AddrRange range;
-    };
-
-    PortCache portCache[3];
-
-    // Checks the cache and returns the id of the port that has the requested
-    // address within its range
-    inline PortID checkPortCache(Addr addr) const {
-        if (portCache[0].valid && portCache[0].range.contains(addr)) {
-            return portCache[0].id;
-        }
-        if (portCache[1].valid && portCache[1].range.contains(addr)) {
-            return portCache[1].id;
-        }
-        if (portCache[2].valid && portCache[2].range.contains(addr)) {
-            return portCache[2].id;
-        }
-
-        return InvalidPortID;
-    }
-
-    // Clears the earliest entry of the cache and inserts a new port entry
-    inline void updatePortCache(short id, const AddrRange& range) {
-        portCache[2].valid = portCache[1].valid;
-        portCache[2].id    = portCache[1].id;
-        portCache[2].range = portCache[1].range;
-
-        portCache[1].valid = portCache[0].valid;
-        portCache[1].id    = portCache[0].id;
-        portCache[1].range = portCache[0].range;
-
-        portCache[0].valid = true;
-        portCache[0].id    = id;
-        portCache[0].range = range;
-    }
-
-    // Clears the cache. Needs to be called in constructor.
-    inline void clearPortCache() {
-        portCache[2].valid = false;
-        portCache[1].valid = false;
-        portCache[0].valid = false;
-    }
-
-    /**
-     * Return the address ranges the bus is responsible for.
-     *
-     * @return a list of non-overlapping address ranges
-     */
-    AddrRangeList getAddrRanges() const;
-
-    /**
-     * Calculate the timing parameters for the packet. Updates the
-     * busFirstWordDelay and busLastWordDelay fields of the packet
-     * object with the relative number of ticks required to transmit
-     * the header and the first word, and the last word, respectively.
-     */
-    void calcPacketTiming(PacketPtr pkt);
-
-    /**
-     * Remember for each of the master ports of the bus if we got an
-     * address range from the connected slave. For convenience, also
-     * keep track of if we got ranges from all the slave modules or
-     * not.
-     */
-    std::vector<bool> gotAddrRanges;
-    bool gotAllAddrRanges;
-
-    /** The master and slave ports of the bus */
-    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;
-
-    /** Port that handles requests that don't match any of the interfaces.*/
-    PortID defaultPortID;
-
-    /** If true, use address range provided by default device.  Any
-       address not handled by another port and not in default device's
-       range will cause a fatal error.  If false, just send all
-       addresses not handled by another port to default device. */
-    const bool useDefaultRange;
-
-    BaseBus(const BaseBusParams *p);
-
-    virtual ~BaseBus();
-
-    /**
-     * Stats for transaction distribution and data passing through the
-     * bus. The transaction distribution is globally counting
-     * different types of commands. The packet count and total packet
-     * size are two-dimensional vectors that are indexed by the bus
-     * slave port and master port id (thus the neighbouring master and
-     * neighbouring slave), summing up both directions (request and
-     * response).
-     */
-    Stats::Formula throughput;
-    Stats::Vector transDist;
-    Stats::Vector2d pktCount;
-    Stats::Vector2d totPktSize;
-
-  public:
-
-    virtual void init();
-
-    /** A function used to return the port associated with this bus object. */
-    BaseMasterPort& getMasterPort(const std::string& if_name,
-                                  PortID idx = InvalidPortID);
-    BaseSlavePort& getSlavePort(const std::string& if_name,
-                                PortID idx = InvalidPortID);
-
-    virtual unsigned int drain(DrainManager *dm) = 0;
-
-    virtual void regStats();
-
-};
-
-#endif //__MEM_BUS_HH__
index 8c091fa3978d3b5eb3313399f7a06202fc240154..e4a6f3c242506348b5c0dfedc7b97fdb8dd146cc 100644 (file)
@@ -423,7 +423,7 @@ Cache<TagStore>::recvTimingSnoopResp(PacketPtr pkt)
     pkt->setDest(rec->prevSrc);
     delete rec;
     // @todo someone should pay for this
-    pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+    pkt->firstWordDelay = pkt->lastWordDelay = 0;
     memSidePort->schedTimingSnoopResp(pkt, time);
 }
 
@@ -482,7 +482,7 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt)
             Packet *snoopPkt = new Packet(pkt, true);  // clear flags
             // also reset the bus time that the original packet has
             // not yet paid for
-            snoopPkt->busFirstWordDelay = snoopPkt->busLastWordDelay = 0;
+            snoopPkt->firstWordDelay = snoopPkt->lastWordDelay = 0;
             snoopPkt->setExpressSnoop();
             snoopPkt->assertMemInhibit();
             bool M5_VAR_USED success = memSidePort->sendTimingReq(snoopPkt);
@@ -505,7 +505,7 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt)
         uncacheableFlush(pkt);
 
         // @todo: someone should pay for this
-        pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+        pkt->firstWordDelay = pkt->lastWordDelay = 0;
 
         // writes go in write buffer, reads use MSHR,
         // prefetches are acknowledged (responded to) and dropped
@@ -562,7 +562,7 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt)
         if (needsResponse) {
             pkt->makeTimingResponse();
             // @todo: Make someone pay for this
-            pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+            pkt->firstWordDelay = pkt->lastWordDelay = 0;
             cpuSidePort->schedTimingResp(pkt, clockEdge(lat));
         } else {
             /// @todo nominally we should just delete the packet here,
@@ -574,7 +574,7 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt)
         // miss
 
         // @todo: Make someone pay for this
-        pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+        pkt->firstWordDelay = pkt->lastWordDelay = 0;
 
         if (blk && blk->isValid() && (blk->status & BlkCanGoExclusive) &&
             pkt->isWrite() && (pkt->cmd != MemCmd::WriteInvalidateReq)) {
@@ -1115,8 +1115,8 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt)
                 // from lower level caches/memory to an upper level cache or
                 // the core.
                 completion_time = clockEdge(responseLatency) +
-                    (transfer_offset ? pkt->busLastWordDelay :
-                     pkt->busFirstWordDelay);
+                    (transfer_offset ? pkt->lastWordDelay :
+                     pkt->firstWordDelay);
 
                 assert(!target->pkt->req->isUncacheable());
 
@@ -1132,7 +1132,7 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt)
                 // from lower level caches/memory to an upper level cache or
                 // the core.
                 completion_time = clockEdge(responseLatency) +
-                    pkt->busLastWordDelay;
+                    pkt->lastWordDelay;
                 target->pkt->req->setExtraData(0);
             } else if (pkt->cmd == MemCmd::WriteInvalidateResp) {
                 if (blk) {
@@ -1165,13 +1165,13 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt)
                 // will occur for its impatience (since it will think it
                 // has dirty data), but it really can't be helped.
                 completion_time = clockEdge(responseLatency) +
-                    pkt->busLastWordDelay;
+                    pkt->lastWordDelay;
             } else {
                 // not a cache fill, just forwarding response
                 // responseLatency is the latency of the return path
                 // from lower level cahces/memory to the core.
                 completion_time = clockEdge(responseLatency) +
-                    pkt->busLastWordDelay;
+                    pkt->lastWordDelay;
                 if (pkt->isRead() && !is_error) {
                     target->pkt->setData(pkt->getPtr<uint8_t>());
                 }
@@ -1191,7 +1191,7 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt)
                         target->pkt->getAddr());
             }
             // reset the bus additional time as it is now accounted for
-            target->pkt->busFirstWordDelay = target->pkt->busLastWordDelay = 0;
+            target->pkt->firstWordDelay = target->pkt->lastWordDelay = 0;
             cpuSidePort->schedTimingResp(target->pkt, completion_time);
             break;
 
@@ -1239,7 +1239,7 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt)
         mq = mshr->queue;
         mq->markPending(mshr);
         requestMemSideBus((RequestCause)mq->index, clockEdge() +
-                          pkt->busLastWordDelay);
+                          pkt->lastWordDelay);
     } else {
         mq->deallocate(mshr);
         if (wasFull && !mq->isFull()) {
@@ -1495,7 +1495,7 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk,
     }
 
     blk->whenReady = clockEdge() + responseLatency * clockPeriod() +
-        pkt->busLastWordDelay;
+        pkt->lastWordDelay;
 
     return blk;
 }
@@ -1522,7 +1522,7 @@ doTimingSupplyResponse(PacketPtr req_pkt, uint8_t *blk_data,
     pkt->allocate();
     pkt->makeTimingResponse();
     // @todo Make someone pay for this
-    pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+    pkt->firstWordDelay = pkt->lastWordDelay = 0;
     if (pkt->isRead()) {
         pkt->setDataFromBlock(blk_data, blkSize);
     }
@@ -1572,7 +1572,7 @@ Cache<TagStore>::handleSnoop(PacketPtr pkt, BlkType *blk,
             snoopPkt.pushSenderState(new ForwardResponseRecord(pkt->getSrc()));
             // the snoop packet does not need to wait any additional
             // time
-            snoopPkt.busFirstWordDelay = snoopPkt.busLastWordDelay = 0;
+            snoopPkt.firstWordDelay = snoopPkt.lastWordDelay = 0;
             cpuSidePort->sendTimingSnoopReq(&snoopPkt);
             if (snoopPkt.memInhibitAsserted()) {
                 // cache-to-cache response from some upper cache
diff --git a/src/mem/coherent_bus.cc b/src/mem/coherent_bus.cc
deleted file mode 100644 (file)
index 9529e9e..0000000
+++ /dev/null
@@ -1,830 +0,0 @@
-/*
- * Copyright (c) 2011-2013 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"
-#include "sim/system.hh"
-
-CoherentBus::CoherentBus(const CoherentBusParams *p)
-    : BaseBus(p), system(p->system), snoopFilter(p->snoop_filter)
-{
-    // 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.master[%d]", name(), i);
-        MasterPort* bp = new CoherentBusMasterPort(portName, *this, i);
-        masterPorts.push_back(bp);
-        reqLayers.push_back(new ReqLayer(*bp, *this,
-                                         csprintf(".reqLayer%d", i)));
-        snoopLayers.push_back(new SnoopLayer(*bp, *this,
-                                             csprintf(".snoopLayer%d", i)));
-    }
-
-    // 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 = name() + ".default";
-        MasterPort* bp = new CoherentBusMasterPort(portName, *this,
-                                                   defaultPortID);
-        masterPorts.push_back(bp);
-        reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%d",
-                                             defaultPortID)));
-        snoopLayers.push_back(new SnoopLayer(*bp, *this,
-                                             csprintf(".snoopLayer%d",
-                                                      defaultPortID)));
-    }
-
-    // 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.slave[%d]", name(), i);
-        SlavePort* bp = new CoherentBusSlavePort(portName, *this, i);
-        slavePorts.push_back(bp);
-        respLayers.push_back(new RespLayer(*bp, *this,
-                                           csprintf(".respLayer%d", i)));
-        snoopRespPorts.push_back(new SnoopRespPort(*bp, *this));
-    }
-
-    if (snoopFilter)
-        snoopFilter->setSlavePorts(slavePorts);
-
-    clearPortCache();
-}
-
-CoherentBus::~CoherentBus()
-{
-    for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l)
-        delete *l;
-    for (auto l = respLayers.begin(); l != respLayers.end(); ++l)
-        delete *l;
-    for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l)
-        delete *l;
-    for (auto p = snoopRespPorts.begin(); p != snoopRespPorts.end(); ++p)
-        delete *p;
-}
-
-void
-CoherentBus::init()
-{
-    // the base class is responsible for determining the block size
-    BaseBus::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) {
-        // check if the connected master port is snooping
-        if ((*p)->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];
-
-    // remember if the packet is an express snoop
-    bool is_express_snoop = pkt->isExpressSnoop();
-
-    // determine the destination based on the address
-    PortID master_port_id = findPort(pkt->getAddr());
-
-    // test if the bus should be considered occupied for the current
-    // port, and exclude express snoops from the check
-    if (!is_express_snoop && !reqLayers[master_port_id]->tryTiming(src_port)) {
-        DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUS BUSY\n",
-                src_port->name(), pkt->cmdString(), pkt->getAddr());
-        return false;
-    }
-
-    DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n",
-            src_port->name(), pkt->cmdString(), is_express_snoop,
-            pkt->getAddr());
-
-    // store size and command as they might be modified when
-    // forwarding the packet
-    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
-    unsigned int pkt_cmd = pkt->cmdToIndex();
-
-    // set the source port for routing of the response
-    pkt->setSrc(slave_port_id);
-
-    calcPacketTiming(pkt);
-    Tick packetFinishTime = pkt->busLastWordDelay + curTick();
-
-    // uncacheable requests need never be snooped
-    if (!pkt->req->isUncacheable() && !system->bypassCaches()) {
-        // the packet is a memory-mapped request and should be
-        // broadcasted to our snoopers but the source
-        if (snoopFilter) {
-            // check with the snoop filter where to forward this packet
-            auto sf_res = snoopFilter->lookupRequest(pkt, *src_port);
-            packetFinishTime += sf_res.second * clockPeriod();
-            DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x"\
-                    " SF size: %i lat: %i\n", src_port->name(),
-                    pkt->cmdString(), pkt->getAddr(), sf_res.first.size(),
-                    sf_res.second);
-            forwardTiming(pkt, slave_port_id, sf_res.first);
-        } else {
-            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 = !is_express_snoop && 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);
-    }
-
-    // Note: Cannot create a copy of the full packet, here.
-    MemCmd orig_cmd(pkt->cmd);
-
-    // since it is a normal request, attempt to send the packet
-    bool success = masterPorts[master_port_id]->sendTimingReq(pkt);
-
-    if (snoopFilter && !pkt->req->isUncacheable()
-        && !system->bypassCaches()) {
-        // The packet may already be overwritten by the sendTimingReq function.
-        // The snoop filter needs to see the original request *and* the return
-        // status of the send operation, so we need to recreate the original
-        // request.  Atomic mode does not have the issue, as there the send
-        // operation and the response happen instantaneously and don't need two
-        // phase tracking.
-        MemCmd tmp_cmd(pkt->cmd);
-        pkt->cmd = orig_cmd;
-        // Let the snoop filter know about the success of the send operation
-        snoopFilter->updateRequest(pkt, *src_port, !success);
-        pkt->cmd = tmp_cmd;
-    }
-
-    // if this is an express snoop, we are done at this point
-    if (is_express_snoop) {
-        assert(success);
-        snoopDataThroughBus += pkt_size;
-        snoopsThroughBus++;
-    } else {
-        // for normal requests, check if successful
-        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);
-
-            // undo the calculation so we can check for 0 again
-            pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
-
-            DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
-                    src_port->name(), pkt->cmdString(), pkt->getAddr());
-
-            // update the bus state and schedule an idle event
-            reqLayers[master_port_id]->failedTiming(src_port,
-                                                    clockEdge(headerCycles));
-        } else {
-            // update the bus state and schedule an idle event
-            reqLayers[master_port_id]->succeededTiming(packetFinishTime);
-            dataThroughBus += pkt_size;
-        }
-    }
-
-    // stats updates only consider packets that were successfully sent
-    if (success) {
-        pktCount[slave_port_id][master_port_id]++;
-        totPktSize[slave_port_id][master_port_id] += pkt_size;
-        transDist[pkt_cmd]++;
-    }
-
-    return success;
-}
-
-bool
-CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
-{
-    // determine the source port based on the id
-    MasterPort *src_port = masterPorts[master_port_id];
-
-    // determine the destination based on what is stored in the packet
-    PortID slave_port_id = pkt->getDest();
-
-    // test if the bus should be considered occupied for the current
-    // port
-    if (!respLayers[slave_port_id]->tryTiming(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());
-
-    // store size and command as they might be modified when
-    // forwarding the packet
-    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
-    unsigned int pkt_cmd = pkt->cmdToIndex();
-
-    calcPacketTiming(pkt);
-    Tick packetFinishTime = pkt->busLastWordDelay + curTick();
-
-    // 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());
-
-    if (snoopFilter && !pkt->req->isUncacheable() && !system->bypassCaches()) {
-        // let the snoop filter inspect the response and update its state
-        snoopFilter->updateResponse(pkt, *slavePorts[slave_port_id]);
-    }
-
-    // remove it as outstanding
-    outstandingReq.erase(pkt->req);
-
-    // send the packet through the destination slave port
-    bool success M5_VAR_USED = slavePorts[slave_port_id]->sendTimingResp(pkt);
-
-    // currently it is illegal to block responses... can lead to
-    // deadlock
-    assert(success);
-
-    respLayers[slave_port_id]->succeededTiming(packetFinishTime);
-
-    // stats updates
-    dataThroughBus += pkt_size;
-    pktCount[slave_port_id][master_port_id]++;
-    totPktSize[slave_port_id][master_port_id] += pkt_size;
-    transDist[pkt_cmd]++;
-
-    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());
-
-    // update stats here as we know the forwarding will succeed
-    transDist[pkt->cmdToIndex()]++;
-    snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
-    snoopsThroughBus++;
-
-    // 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);
-
-    if (snoopFilter) {
-        // let the Snoop Filter work its magic and guide probing
-        auto sf_res = snoopFilter->lookupSnoop(pkt);
-        // No timing here: packetFinishTime += sf_res.second * clockPeriod();
-        DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x"\
-                " SF size: %i lat: %i\n", masterPorts[master_port_id]->name(),
-                pkt->cmdString(), pkt->getAddr(), sf_res.first.size(),
-                sf_res.second);
-
-        // forward to all snoopers
-        forwardTiming(pkt, InvalidPortID, sf_res.first);
-    } else {
-        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()));
-}
-
-bool
-CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
-{
-    // determine the source port based on the id
-    SlavePort* src_port = slavePorts[slave_port_id];
-
-    // get the destination from the packet
-    PortID dest_port_id = pkt->getDest();
-
-    // 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
-    bool forwardAsSnoop = outstandingReq.find(pkt->req) ==
-        outstandingReq.end();
-
-    // test if the bus should be considered occupied for the current
-    // port, note that the check is bypassed if the response is being
-    // passed on as a normal response since this is occupying the
-    // response layer rather than the snoop response layer
-    if (forwardAsSnoop) {
-        if (!snoopLayers[dest_port_id]->tryTiming(src_port)) {
-            DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
-                    src_port->name(), pkt->cmdString(), pkt->getAddr());
-            return false;
-        }
-    } else {
-        // get the master port that mirrors this slave port internally
-        MasterPort* snoop_port = snoopRespPorts[slave_port_id];
-        if (!respLayers[dest_port_id]->tryTiming(snoop_port)) {
-            DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
-                    snoop_port->name(), pkt->cmdString(), pkt->getAddr());
-            return false;
-        }
-    }
-
-    DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x\n",
-            src_port->name(), pkt->cmdString(), pkt->getAddr());
-
-    // store size and command as they might be modified when
-    // forwarding the packet
-    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
-    unsigned int pkt_cmd = pkt->cmdToIndex();
-
-    // responses are never express snoops
-    assert(!pkt->isExpressSnoop());
-
-    calcPacketTiming(pkt);
-    Tick packetFinishTime = pkt->busLastWordDelay + curTick();
-
-    // forward it either as a snoop response or a normal response
-    if (forwardAsSnoop) {
-        // this is a snoop response to a snoop request we forwarded,
-        // e.g. coming from the L1 and going to the L2, and it should
-        // be forwarded as a snoop response
-
-        if (snoopFilter) {
-            // update the probe filter so that it can properly track the line
-            snoopFilter->updateSnoopForward(pkt, *slavePorts[slave_port_id],
-                                            *masterPorts[dest_port_id]);
-        }
-
-        bool success M5_VAR_USED =
-            masterPorts[dest_port_id]->sendTimingSnoopResp(pkt);
-        pktCount[slave_port_id][dest_port_id]++;
-        totPktSize[slave_port_id][dest_port_id] += pkt_size;
-        assert(success);
-
-        snoopLayers[dest_port_id]->succeededTiming(packetFinishTime);
-    } 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_port_id);
-
-        if (snoopFilter) {
-            // update the probe filter so that it can properly track the line
-            snoopFilter->updateSnoopResponse(pkt, *slavePorts[slave_port_id],
-                                    *slavePorts[dest_port_id]);
-        }
-
-        DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x"\
-                " FWD RESP\n", src_port->name(), pkt->cmdString(),
-                pkt->getAddr());
-
-        // as a normal response, it should go back to a master through
-        // one of our slave ports, at this point we are ignoring the
-        // fact that the response layer could be busy and do not touch
-        // its state
-        bool success M5_VAR_USED =
-            slavePorts[dest_port_id]->sendTimingResp(pkt);
-
-        // @todo Put the response in an internal FIFO and pass it on
-        // to the response layer from there
-
-        // currently it is illegal to block responses... can lead
-        // to deadlock
-        assert(success);
-
-        respLayers[dest_port_id]->succeededTiming(packetFinishTime);
-    }
-
-    // stats updates
-    transDist[pkt_cmd]++;
-    snoopDataThroughBus += pkt_size;
-    snoopsThroughBus++;
-
-    return true;
-}
-
-
-void
-CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id,
-                           const std::vector<SlavePort*>& dests)
-{
-    DPRINTF(CoherentBus, "%s for %s address %x size %d\n", __func__,
-            pkt->cmdString(), pkt->getAddr(), pkt->getSize());
-
-    // snoops should only happen if the system isn't bypassing caches
-    assert(!system->bypassCaches());
-
-    unsigned fanout = 0;
-
-    for (SlavePortConstIter s = dests.begin(); s != dests.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);
-            fanout++;
-        }
-    }
-
-    // Stats for fanout of this forward operation
-    snoopFanout.sample(fanout);
-}
-
-void
-CoherentBus::recvRetry(PortID master_port_id)
-{
-    // responses and snoop responses never block on forwarding them,
-    // so the retry will always be coming from a port to which we
-    // tried to forward a request
-    reqLayers[master_port_id]->recvRetry();
-}
-
-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());
-
-    // add the request data
-    dataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
-
-    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
-    Tick snoop_response_latency = 0;
-
-    // uncacheable requests need never be snooped
-    if (!pkt->req->isUncacheable() && !system->bypassCaches()) {
-        // forward to all snoopers but the source
-        std::pair<MemCmd, Tick> snoop_result;
-        if (snoopFilter) {
-            // check with the snoop filter where to forward this packet
-            auto sf_res =
-                snoopFilter->lookupRequest(pkt, *slavePorts[slave_port_id]);
-            snoop_response_latency += sf_res.second * clockPeriod();
-            DPRINTF(CoherentBus, "%s: src %s %s 0x%x"\
-                    " SF size: %i lat: %i\n", __func__,
-                    slavePorts[slave_port_id]->name(), pkt->cmdString(),
-                    pkt->getAddr(), sf_res.first.size(), sf_res.second);
-            snoop_result = forwardAtomic(pkt, slave_port_id, InvalidPortID,
-                                         sf_res.first);
-        } else {
-            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);
-
-    // Lower levels have replied, tell the snoop filter
-    if (snoopFilter && !pkt->req->isUncacheable() && !system->bypassCaches() &&
-        pkt->isResponse()) {
-        snoopFilter->updateResponse(pkt, *slavePorts[slave_port_id]);
-    }
-
-    // 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;
-    }
-
-    // add the response data
-    if (pkt->isResponse())
-        dataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
-
-    // @todo: Not setting first-word time
-    pkt->busLastWordDelay = 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());
-
-    // add the request snoop data
-    snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
-    snoopsThroughBus++;
-
-    // forward to all snoopers
-    std::pair<MemCmd, Tick> snoop_result;
-    Tick snoop_response_latency = 0;
-    if (snoopFilter) {
-        auto sf_res = snoopFilter->lookupSnoop(pkt);
-        snoop_response_latency += sf_res.second * clockPeriod();
-        DPRINTF(CoherentBus, "%s: src %s %s 0x%x SF size: %i lat: %i\n",
-                __func__, masterPorts[master_port_id]->name(), pkt->cmdString(),
-                pkt->getAddr(), sf_res.first.size(), sf_res.second);
-        snoop_result = forwardAtomic(pkt, InvalidPortID, master_port_id,
-                                     sf_res.first);
-    } else {
-        snoop_result = forwardAtomic(pkt, InvalidPortID);
-    }
-    MemCmd snoop_response_cmd = snoop_result.first;
-    snoop_response_latency += snoop_result.second;
-
-    if (snoop_response_cmd != MemCmd::InvalidCmd)
-        pkt->cmd = snoop_response_cmd;
-
-    // add the response snoop data
-    if (pkt->isResponse()) {
-        snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
-        snoopsThroughBus++;
-    }
-
-    // @todo: Not setting first-word time
-    pkt->busLastWordDelay = snoop_response_latency;
-    return snoop_response_latency;
-}
-
-std::pair<MemCmd, Tick>
-CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id,
-                           PortID source_master_port_id,
-                           const std::vector<SlavePort*>& dests)
-{
-    // 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;
-
-    // snoops should only happen if the system isn't bypassing caches
-    assert(!system->bypassCaches());
-
-    unsigned fanout = 0;
-
-    for (SlavePortConstIter s = dests.begin(); s != dests.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)
-            continue;
-
-        Tick latency = p->sendAtomicSnoop(pkt);
-        fanout++;
-
-        // 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())
-            continue;
-
-        // 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;
-
-        if (snoopFilter) {
-            // Handle responses by the snoopers and differentiate between
-            // responses to requests from above and snoops from below
-            if (source_master_port_id != InvalidPortID) {
-                // Getting a response for a snoop from below
-                assert(exclude_slave_port_id == InvalidPortID);
-                snoopFilter->updateSnoopForward(pkt, *p,
-                             *masterPorts[source_master_port_id]);
-            } else {
-                // Getting a response for a request from above
-                assert(source_master_port_id == InvalidPortID);
-                snoopFilter->updateSnoopResponse(pkt, *p,
-                             *slavePorts[exclude_slave_port_id]);
-            }
-        }
-        // restore original packet state for remaining snoopers
-        pkt->cmd = orig_cmd;
-    }
-
-    // Stats for fanout
-    snoopFanout.sample(fanout);
-
-    // 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() && !system->bypassCaches()) {
-        // 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)
-{
-    // snoops should only happen if the system isn't bypassing caches
-    assert(!system->bypassCaches());
-
-    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;
-        }
-    }
-}
-
-unsigned int
-CoherentBus::drain(DrainManager *dm)
-{
-    // sum up the individual layers
-    unsigned int total = 0;
-    for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l)
-        total += (*l)->drain(dm);
-    for (auto l = respLayers.begin(); l != respLayers.end(); ++l)
-        total += (*l)->drain(dm);
-    for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l)
-        total += (*l)->drain(dm);
-    return total;
-}
-
-void
-CoherentBus::regStats()
-{
-    // register the stats of the base class and our three bus layers
-    BaseBus::regStats();
-    for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l)
-        (*l)->regStats();
-    for (auto l = respLayers.begin(); l != respLayers.end(); ++l)
-        (*l)->regStats();
-    for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l)
-        (*l)->regStats();
-
-    dataThroughBus
-        .name(name() + ".data_through_bus")
-        .desc("Total data (bytes)")
-        ;
-
-    snoopDataThroughBus
-        .name(name() + ".snoop_data_through_bus")
-        .desc("Total snoop data (bytes)")
-    ;
-
-    snoopsThroughBus
-        .name(name() + ".snoops_through_bus")
-        .desc("Total snoops (count)")
-    ;
-
-    snoopFanout
-        .init(0, snoopPorts.size(), 1)
-        .name(name() + ".snoop_fanout")
-        .desc("Request fanout histogram")
-    ;
-
-    throughput
-        .name(name() + ".throughput")
-        .desc("Throughput (bytes/s)")
-        .precision(0)
-        ;
-
-    throughput = (dataThroughBus + snoopDataThroughBus) / simSeconds;
-}
-
-CoherentBus *
-CoherentBusParams::create()
-{
-    return new CoherentBus(this);
-}
diff --git a/src/mem/coherent_bus.hh b/src/mem/coherent_bus.hh
deleted file mode 100644 (file)
index 26ad927..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * Copyright (c) 2011-2013 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 "base/hashmap.hh"
-#include "mem/bus.hh"
-#include "mem/snoop_filter.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.
- * @sa  \ref gem5MemorySystem "gem5 Memory System"
- */
-class CoherentBus : public BaseBus
-{
-
-  protected:
-
-    /**
-     * Declare the layers of this bus, one vector for requests, one
-     * for responses, and one for snoop responses
-     */
-    typedef Layer<SlavePort,MasterPort> ReqLayer;
-    typedef Layer<MasterPort,SlavePort> RespLayer;
-    typedef Layer<SlavePort,MasterPort> SnoopLayer;
-    std::vector<ReqLayer*> reqLayers;
-    std::vector<RespLayer*> respLayers;
-    std::vector<SnoopLayer*> snoopLayers;
-
-    /**
-     * 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() const
-        { return bus.getAddrRanges(); }
-
-    };
-
-    /**
-     * 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(id); }
-
-    };
-
-    /**
-     * Internal class to bridge between an incoming snoop response
-     * from a slave port and forwarding it through an outgoing slave
-     * port. It is effectively a dangling master port.
-     */
-    class SnoopRespPort : public MasterPort
-    {
-
-      private:
-
-        /** The port which we mirror internally. */
-        SlavePort& slavePort;
-
-      public:
-
-        /**
-         * Create a snoop response port that mirrors a given slave port.
-         */
-        SnoopRespPort(SlavePort& slave_port, CoherentBus& _bus) :
-            MasterPort(slave_port.name() + ".snoopRespPort", &_bus),
-            slavePort(slave_port) { }
-
-        /**
-         * Override the sending of retries and pass them on through
-         * the mirrored slave port.
-         */
-        void sendRetry() {
-            slavePort.sendRetry();
-        }
-
-        /**
-         * Provided as necessary.
-         */
-        void recvRetry() { panic("SnoopRespPort should never see retry\n"); }
-
-        /**
-         * Provided as necessary.
-         */
-        bool recvTimingResp(PacketPtr pkt)
-        {
-            panic("SnoopRespPort should never see timing response\n");
-            return false;
-        }
-
-    };
-
-    std::vector<SnoopRespPort*> snoopRespPorts;
-
-    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.
-     */
-    m5::hash_set<RequestPtr> outstandingReq;
-
-    /**
-     * Keep a pointer to the system to be allow to querying memory system
-     * properties.
-     */
-    System *system;
-
-    /** A snoop filter that tracks cache line residency and can restrict the
-      * broadcast needed for probes.  NULL denotes an absent filter. */
-    SnoopFilter *snoopFilter;
-
-    /** 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);
-
-    /** Timing function called by port when it is once again able to process
-     * requests. */
-    void recvRetry(PortID master_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) {
-        forwardTiming(pkt, exclude_slave_port_id, snoopPorts);
-    }
-
-    /**
-     * Forward a timing packet to a selected list of 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
-     * @param dests Vector of destination ports for the forwarded pkt
-     */
-    void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id,
-                       const std::vector<SlavePort*>& dests);
-
-    /** 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)
-    {
-        return forwardAtomic(pkt, exclude_slave_port_id, InvalidPortID, snoopPorts);
-    }
-
-    /**
-     * Forward an atomic packet to a selected list of 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
-     * @param source_master_port_id Id of the master port for snoops from below
-     * @param dests Vector of destination ports for the forwarded pkt
-     *
-     * @return a pair containing the snoop response and snoop latency
-     */
-    std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
-                                          PortID exclude_slave_port_id,
-                                          PortID source_master_port_id,
-                                          const std::vector<SlavePort*>& dests);
-
-    /** 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);
-
-    Stats::Scalar dataThroughBus;
-    Stats::Scalar snoopDataThroughBus;
-    Stats::Scalar snoopsThroughBus;
-    Stats::Distribution snoopFanout;
-
-  public:
-
-    virtual void init();
-
-    CoherentBus(const CoherentBusParams *p);
-
-    virtual ~CoherentBus();
-
-    unsigned int drain(DrainManager *dm);
-
-    virtual void regStats();
-};
-
-#endif //__MEM_COHERENT_BUS_HH__
diff --git a/src/mem/coherent_xbar.cc b/src/mem/coherent_xbar.cc
new file mode 100644 (file)
index 0000000..ce5116d
--- /dev/null
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 2011-2014 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 crossbar object.
+ */
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "debug/AddrRanges.hh"
+#include "debug/CoherentXBar.hh"
+#include "mem/coherent_xbar.hh"
+#include "sim/system.hh"
+
+CoherentXBar::CoherentXBar(const CoherentXBarParams *p)
+    : BaseXBar(p), system(p->system), snoopFilter(p->snoop_filter)
+{
+    // 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.master[%d]", name(), i);
+        MasterPort* bp = new CoherentXBarMasterPort(portName, *this, i);
+        masterPorts.push_back(bp);
+        reqLayers.push_back(new ReqLayer(*bp, *this,
+                                         csprintf(".reqLayer%d", i)));
+        snoopLayers.push_back(new SnoopLayer(*bp, *this,
+                                             csprintf(".snoopLayer%d", i)));
+    }
+
+    // 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 = name() + ".default";
+        MasterPort* bp = new CoherentXBarMasterPort(portName, *this,
+                                                   defaultPortID);
+        masterPorts.push_back(bp);
+        reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%d",
+                                             defaultPortID)));
+        snoopLayers.push_back(new SnoopLayer(*bp, *this,
+                                             csprintf(".snoopLayer%d",
+                                                      defaultPortID)));
+    }
+
+    // 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.slave[%d]", name(), i);
+        SlavePort* bp = new CoherentXBarSlavePort(portName, *this, i);
+        slavePorts.push_back(bp);
+        respLayers.push_back(new RespLayer(*bp, *this,
+                                           csprintf(".respLayer%d", i)));
+        snoopRespPorts.push_back(new SnoopRespPort(*bp, *this));
+    }
+
+    if (snoopFilter)
+        snoopFilter->setSlavePorts(slavePorts);
+
+    clearPortCache();
+}
+
+CoherentXBar::~CoherentXBar()
+{
+    for (auto l: reqLayers)
+        delete l;
+    for (auto l: respLayers)
+        delete l;
+    for (auto l: snoopLayers)
+        delete l;
+    for (auto p: snoopRespPorts)
+        delete p;
+}
+
+void
+CoherentXBar::init()
+{
+    // the base class is responsible for determining the block size
+    BaseXBar::init();
+
+    // iterate over our slave ports and determine which of our
+    // neighbouring master ports are snooping and add them as snoopers
+    for (const auto& p: slavePorts) {
+        // check if the connected master port is snooping
+        if (p->isSnooping()) {
+            DPRINTF(AddrRanges, "Adding snooping master %s\n",
+                    p->getMasterPort().name());
+            snoopPorts.push_back(p);
+        }
+    }
+
+    if (snoopPorts.empty())
+        warn("CoherentXBar %s has no snooping ports attached!\n", name());
+}
+
+bool
+CoherentXBar::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
+{
+    // determine the source port based on the id
+    SlavePort *src_port = slavePorts[slave_port_id];
+
+    // remember if the packet is an express snoop
+    bool is_express_snoop = pkt->isExpressSnoop();
+
+    // determine the destination based on the address
+    PortID master_port_id = findPort(pkt->getAddr());
+
+    // test if the crossbar should be considered occupied for the current
+    // port, and exclude express snoops from the check
+    if (!is_express_snoop && !reqLayers[master_port_id]->tryTiming(src_port)) {
+        DPRINTF(CoherentXBar, "recvTimingReq: src %s %s 0x%x BUSY\n",
+                src_port->name(), pkt->cmdString(), pkt->getAddr());
+        return false;
+    }
+
+    DPRINTF(CoherentXBar, "recvTimingReq: src %s %s expr %d 0x%x\n",
+            src_port->name(), pkt->cmdString(), is_express_snoop,
+            pkt->getAddr());
+
+    // store size and command as they might be modified when
+    // forwarding the packet
+    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+    unsigned int pkt_cmd = pkt->cmdToIndex();
+
+    // set the source port for routing of the response
+    pkt->setSrc(slave_port_id);
+
+    calcPacketTiming(pkt);
+    Tick packetFinishTime = pkt->lastWordDelay + curTick();
+
+    // uncacheable requests need never be snooped
+    if (!pkt->req->isUncacheable() && !system->bypassCaches()) {
+        // the packet is a memory-mapped request and should be
+        // broadcasted to our snoopers but the source
+        if (snoopFilter) {
+            // check with the snoop filter where to forward this packet
+            auto sf_res = snoopFilter->lookupRequest(pkt, *src_port);
+            packetFinishTime += sf_res.second * clockPeriod();
+            DPRINTF(CoherentXBar, "recvTimingReq: src %s %s 0x%x"\
+                    " SF size: %i lat: %i\n", src_port->name(),
+                    pkt->cmdString(), pkt->getAddr(), sf_res.first.size(),
+                    sf_res.second);
+            forwardTiming(pkt, slave_port_id, sf_res.first);
+        } else {
+            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 = !is_express_snoop && 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);
+    }
+
+    // Note: Cannot create a copy of the full packet, here.
+    MemCmd orig_cmd(pkt->cmd);
+
+    // since it is a normal request, attempt to send the packet
+    bool success = masterPorts[master_port_id]->sendTimingReq(pkt);
+
+    if (snoopFilter && !pkt->req->isUncacheable()
+        && !system->bypassCaches()) {
+        // The packet may already be overwritten by the sendTimingReq function.
+        // The snoop filter needs to see the original request *and* the return
+        // status of the send operation, so we need to recreate the original
+        // request.  Atomic mode does not have the issue, as there the send
+        // operation and the response happen instantaneously and don't need two
+        // phase tracking.
+        MemCmd tmp_cmd(pkt->cmd);
+        pkt->cmd = orig_cmd;
+        // Let the snoop filter know about the success of the send operation
+        snoopFilter->updateRequest(pkt, *src_port, !success);
+        pkt->cmd = tmp_cmd;
+    }
+
+    // if this is an express snoop, we are done at this point
+    if (is_express_snoop) {
+        assert(success);
+        snoops++;
+    } else {
+        // for normal requests, check if successful
+        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);
+
+            // undo the calculation so we can check for 0 again
+            pkt->firstWordDelay = pkt->lastWordDelay = 0;
+
+            DPRINTF(CoherentXBar, "recvTimingReq: src %s %s 0x%x RETRY\n",
+                    src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+            // update the layer state and schedule an idle event
+            reqLayers[master_port_id]->failedTiming(src_port,
+                                                    clockEdge(headerCycles));
+        } else {
+            // update the layer state and schedule an idle event
+            reqLayers[master_port_id]->succeededTiming(packetFinishTime);
+        }
+    }
+
+    // stats updates only consider packets that were successfully sent
+    if (success) {
+        pktCount[slave_port_id][master_port_id]++;
+        pktSize[slave_port_id][master_port_id] += pkt_size;
+        transDist[pkt_cmd]++;
+    }
+
+    return success;
+}
+
+bool
+CoherentXBar::recvTimingResp(PacketPtr pkt, PortID master_port_id)
+{
+    // determine the source port based on the id
+    MasterPort *src_port = masterPorts[master_port_id];
+
+    // determine the destination based on what is stored in the packet
+    PortID slave_port_id = pkt->getDest();
+
+    // test if the crossbar should be considered occupied for the
+    // current port
+    if (!respLayers[slave_port_id]->tryTiming(src_port)) {
+        DPRINTF(CoherentXBar, "recvTimingResp: src %s %s 0x%x BUSY\n",
+                src_port->name(), pkt->cmdString(), pkt->getAddr());
+        return false;
+    }
+
+    DPRINTF(CoherentXBar, "recvTimingResp: src %s %s 0x%x\n",
+            src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+    // store size and command as they might be modified when
+    // forwarding the packet
+    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+    unsigned int pkt_cmd = pkt->cmdToIndex();
+
+    calcPacketTiming(pkt);
+    Tick packetFinishTime = pkt->lastWordDelay + curTick();
+
+    // the packet is a normal response to a request that we should
+    // have seen passing through the crossbar
+    assert(outstandingReq.find(pkt->req) != outstandingReq.end());
+
+    if (snoopFilter && !pkt->req->isUncacheable() && !system->bypassCaches()) {
+        // let the snoop filter inspect the response and update its state
+        snoopFilter->updateResponse(pkt, *slavePorts[slave_port_id]);
+    }
+
+    // remove it as outstanding
+    outstandingReq.erase(pkt->req);
+
+    // send the packet through the destination slave port
+    bool success M5_VAR_USED = slavePorts[slave_port_id]->sendTimingResp(pkt);
+
+    // currently it is illegal to block responses... can lead to
+    // deadlock
+    assert(success);
+
+    respLayers[slave_port_id]->succeededTiming(packetFinishTime);
+
+    // stats updates
+    pktCount[slave_port_id][master_port_id]++;
+    pktSize[slave_port_id][master_port_id] += pkt_size;
+    transDist[pkt_cmd]++;
+
+    return true;
+}
+
+void
+CoherentXBar::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id)
+{
+    DPRINTF(CoherentXBar, "recvTimingSnoopReq: src %s %s 0x%x\n",
+            masterPorts[master_port_id]->name(), pkt->cmdString(),
+            pkt->getAddr());
+
+    // update stats here as we know the forwarding will succeed
+    transDist[pkt->cmdToIndex()]++;
+    snoops++;
+
+    // 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);
+
+    if (snoopFilter) {
+        // let the Snoop Filter work its magic and guide probing
+        auto sf_res = snoopFilter->lookupSnoop(pkt);
+        // No timing here: packetFinishTime += sf_res.second * clockPeriod();
+        DPRINTF(CoherentXBar, "recvTimingSnoopReq: src %s %s 0x%x"\
+                " SF size: %i lat: %i\n", masterPorts[master_port_id]->name(),
+                pkt->cmdString(), pkt->getAddr(), sf_res.first.size(),
+                sf_res.second);
+
+        // forward to all snoopers
+        forwardTiming(pkt, InvalidPortID, sf_res.first);
+    } else {
+        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()));
+}
+
+bool
+CoherentXBar::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
+{
+    // determine the source port based on the id
+    SlavePort* src_port = slavePorts[slave_port_id];
+
+    // get the destination from the packet
+    PortID dest_port_id = pkt->getDest();
+
+    // 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
+    bool forwardAsSnoop = outstandingReq.find(pkt->req) ==
+        outstandingReq.end();
+
+    // test if the crossbar should be considered occupied for the
+    // current port, note that the check is bypassed if the response
+    // is being passed on as a normal response since this is occupying
+    // the response layer rather than the snoop response layer
+    if (forwardAsSnoop) {
+        if (!snoopLayers[dest_port_id]->tryTiming(src_port)) {
+            DPRINTF(CoherentXBar, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
+                    src_port->name(), pkt->cmdString(), pkt->getAddr());
+            return false;
+        }
+    } else {
+        // get the master port that mirrors this slave port internally
+        MasterPort* snoop_port = snoopRespPorts[slave_port_id];
+        if (!respLayers[dest_port_id]->tryTiming(snoop_port)) {
+            DPRINTF(CoherentXBar, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
+                    snoop_port->name(), pkt->cmdString(), pkt->getAddr());
+            return false;
+        }
+    }
+
+    DPRINTF(CoherentXBar, "recvTimingSnoopResp: src %s %s 0x%x\n",
+            src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+    // store size and command as they might be modified when
+    // forwarding the packet
+    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+    unsigned int pkt_cmd = pkt->cmdToIndex();
+
+    // responses are never express snoops
+    assert(!pkt->isExpressSnoop());
+
+    calcPacketTiming(pkt);
+    Tick packetFinishTime = pkt->lastWordDelay + curTick();
+
+    // forward it either as a snoop response or a normal response
+    if (forwardAsSnoop) {
+        // this is a snoop response to a snoop request we forwarded,
+        // e.g. coming from the L1 and going to the L2, and it should
+        // be forwarded as a snoop response
+
+        if (snoopFilter) {
+            // update the probe filter so that it can properly track the line
+            snoopFilter->updateSnoopForward(pkt, *slavePorts[slave_port_id],
+                                            *masterPorts[dest_port_id]);
+        }
+
+        bool success M5_VAR_USED =
+            masterPorts[dest_port_id]->sendTimingSnoopResp(pkt);
+        pktCount[slave_port_id][dest_port_id]++;
+        pktSize[slave_port_id][dest_port_id] += pkt_size;
+        assert(success);
+
+        snoopLayers[dest_port_id]->succeededTiming(packetFinishTime);
+    } else {
+        // we got a snoop response on one of our slave ports,
+        // i.e. from a coherent master connected to the crossbar, 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 crossbar 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_port_id);
+
+        if (snoopFilter) {
+            // update the probe filter so that it can properly track the line
+            snoopFilter->updateSnoopResponse(pkt, *slavePorts[slave_port_id],
+                                    *slavePorts[dest_port_id]);
+        }
+
+        DPRINTF(CoherentXBar, "recvTimingSnoopResp: src %s %s 0x%x"\
+                " FWD RESP\n", src_port->name(), pkt->cmdString(),
+                pkt->getAddr());
+
+        // as a normal response, it should go back to a master through
+        // one of our slave ports, at this point we are ignoring the
+        // fact that the response layer could be busy and do not touch
+        // its state
+        bool success M5_VAR_USED =
+            slavePorts[dest_port_id]->sendTimingResp(pkt);
+
+        // @todo Put the response in an internal FIFO and pass it on
+        // to the response layer from there
+
+        // currently it is illegal to block responses... can lead
+        // to deadlock
+        assert(success);
+
+        respLayers[dest_port_id]->succeededTiming(packetFinishTime);
+    }
+
+    // stats updates
+    transDist[pkt_cmd]++;
+    snoops++;
+
+    return true;
+}
+
+
+void
+CoherentXBar::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id,
+                           const std::vector<SlavePort*>& dests)
+{
+    DPRINTF(CoherentXBar, "%s for %s address %x size %d\n", __func__,
+            pkt->cmdString(), pkt->getAddr(), pkt->getSize());
+
+    // snoops should only happen if the system isn't bypassing caches
+    assert(!system->bypassCaches());
+
+    unsigned fanout = 0;
+
+    for (const auto& p: dests) {
+        // 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);
+            fanout++;
+        }
+    }
+
+    // Stats for fanout of this forward operation
+    snoopFanout.sample(fanout);
+}
+
+void
+CoherentXBar::recvRetry(PortID master_port_id)
+{
+    // responses and snoop responses never block on forwarding them,
+    // so the retry will always be coming from a port to which we
+    // tried to forward a request
+    reqLayers[master_port_id]->recvRetry();
+}
+
+Tick
+CoherentXBar::recvAtomic(PacketPtr pkt, PortID slave_port_id)
+{
+    DPRINTF(CoherentXBar, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
+            slavePorts[slave_port_id]->name(), pkt->getAddr(),
+            pkt->cmdString());
+
+    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+    unsigned int pkt_cmd = pkt->cmdToIndex();
+
+    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
+    Tick snoop_response_latency = 0;
+
+    // uncacheable requests need never be snooped
+    if (!pkt->req->isUncacheable() && !system->bypassCaches()) {
+        // forward to all snoopers but the source
+        std::pair<MemCmd, Tick> snoop_result;
+        if (snoopFilter) {
+            // check with the snoop filter where to forward this packet
+            auto sf_res =
+                snoopFilter->lookupRequest(pkt, *slavePorts[slave_port_id]);
+            snoop_response_latency += sf_res.second * clockPeriod();
+            DPRINTF(CoherentXBar, "%s: src %s %s 0x%x"\
+                    " SF size: %i lat: %i\n", __func__,
+                    slavePorts[slave_port_id]->name(), pkt->cmdString(),
+                    pkt->getAddr(), sf_res.first.size(), sf_res.second);
+            snoop_result = forwardAtomic(pkt, slave_port_id, InvalidPortID,
+                                         sf_res.first);
+        } else {
+            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 master_port_id = findPort(pkt->getAddr());
+
+    // stats updates for the request
+    pktCount[slave_port_id][master_port_id]++;
+    pktSize[slave_port_id][master_port_id] += pkt_size;
+    transDist[pkt_cmd]++;
+
+    // forward the request to the appropriate destination
+    Tick response_latency = masterPorts[master_port_id]->sendAtomic(pkt);
+
+    // Lower levels have replied, tell the snoop filter
+    if (snoopFilter && !pkt->req->isUncacheable() && !system->bypassCaches() &&
+        pkt->isResponse()) {
+        snoopFilter->updateResponse(pkt, *slavePorts[slave_port_id]);
+    }
+
+    // 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;
+    }
+
+    // add the response data
+    if (pkt->isResponse()) {
+        pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+        pkt_cmd = pkt->cmdToIndex();
+
+        // stats updates
+        pktCount[slave_port_id][master_port_id]++;
+        pktSize[slave_port_id][master_port_id] += pkt_size;
+        transDist[pkt_cmd]++;
+    }
+
+    // @todo: Not setting first-word time
+    pkt->lastWordDelay = response_latency;
+    return response_latency;
+}
+
+Tick
+CoherentXBar::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id)
+{
+    DPRINTF(CoherentXBar, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n",
+            masterPorts[master_port_id]->name(), pkt->getAddr(),
+            pkt->cmdString());
+
+    // add the request snoop data
+    snoops++;
+
+    // forward to all snoopers
+    std::pair<MemCmd, Tick> snoop_result;
+    Tick snoop_response_latency = 0;
+    if (snoopFilter) {
+        auto sf_res = snoopFilter->lookupSnoop(pkt);
+        snoop_response_latency += sf_res.second * clockPeriod();
+        DPRINTF(CoherentXBar, "%s: src %s %s 0x%x SF size: %i lat: %i\n",
+                __func__, masterPorts[master_port_id]->name(), pkt->cmdString(),
+                pkt->getAddr(), sf_res.first.size(), sf_res.second);
+        snoop_result = forwardAtomic(pkt, InvalidPortID, master_port_id,
+                                     sf_res.first);
+    } else {
+        snoop_result = forwardAtomic(pkt, InvalidPortID);
+    }
+    MemCmd snoop_response_cmd = snoop_result.first;
+    snoop_response_latency += snoop_result.second;
+
+    if (snoop_response_cmd != MemCmd::InvalidCmd)
+        pkt->cmd = snoop_response_cmd;
+
+    // add the response snoop data
+    if (pkt->isResponse()) {
+        snoops++;
+    }
+
+    // @todo: Not setting first-word time
+    pkt->lastWordDelay = snoop_response_latency;
+    return snoop_response_latency;
+}
+
+std::pair<MemCmd, Tick>
+CoherentXBar::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id,
+                           PortID source_master_port_id,
+                           const std::vector<SlavePort*>& dests)
+{
+    // 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;
+
+    // snoops should only happen if the system isn't bypassing caches
+    assert(!system->bypassCaches());
+
+    unsigned fanout = 0;
+
+    for (const auto& p: dests) {
+        // 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)
+            continue;
+
+        Tick latency = p->sendAtomicSnoop(pkt);
+        fanout++;
+
+        // 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())
+            continue;
+
+        // 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;
+
+        if (snoopFilter) {
+            // Handle responses by the snoopers and differentiate between
+            // responses to requests from above and snoops from below
+            if (source_master_port_id != InvalidPortID) {
+                // Getting a response for a snoop from below
+                assert(exclude_slave_port_id == InvalidPortID);
+                snoopFilter->updateSnoopForward(pkt, *p,
+                             *masterPorts[source_master_port_id]);
+            } else {
+                // Getting a response for a request from above
+                assert(source_master_port_id == InvalidPortID);
+                snoopFilter->updateSnoopResponse(pkt, *p,
+                             *slavePorts[exclude_slave_port_id]);
+            }
+        }
+        // restore original packet state for remaining snoopers
+        pkt->cmd = orig_cmd;
+    }
+
+    // Stats for fanout
+    snoopFanout.sample(fanout);
+
+    // 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
+CoherentXBar::recvFunctional(PacketPtr pkt, PortID slave_port_id)
+{
+    if (!pkt->isPrint()) {
+        // don't do DPRINTFs on PrintReq as it clutters up the output
+        DPRINTF(CoherentXBar,
+                "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() && !system->bypassCaches()) {
+        // 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
+CoherentXBar::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id)
+{
+    if (!pkt->isPrint()) {
+        // don't do DPRINTFs on PrintReq as it clutters up the output
+        DPRINTF(CoherentXBar,
+                "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
+CoherentXBar::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
+{
+    // snoops should only happen if the system isn't bypassing caches
+    assert(!system->bypassCaches());
+
+    for (const auto& p: snoopPorts) {
+        // 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;
+        }
+    }
+}
+
+unsigned int
+CoherentXBar::drain(DrainManager *dm)
+{
+    // sum up the individual layers
+    unsigned int total = 0;
+    for (auto l: reqLayers)
+        total += l->drain(dm);
+    for (auto l: respLayers)
+        total += l->drain(dm);
+    for (auto l: snoopLayers)
+        total += l->drain(dm);
+    return total;
+}
+
+void
+CoherentXBar::regStats()
+{
+    // register the stats of the base class and our layers
+    BaseXBar::regStats();
+    for (auto l: reqLayers)
+        l->regStats();
+    for (auto l: respLayers)
+        l->regStats();
+    for (auto l: snoopLayers)
+        l->regStats();
+
+    snoops
+        .name(name() + ".snoops")
+        .desc("Total snoops (count)")
+    ;
+
+    snoopFanout
+        .init(0, snoopPorts.size(), 1)
+        .name(name() + ".snoop_fanout")
+        .desc("Request fanout histogram")
+    ;
+}
+
+CoherentXBar *
+CoherentXBarParams::create()
+{
+    return new CoherentXBar(this);
+}
diff --git a/src/mem/coherent_xbar.hh b/src/mem/coherent_xbar.hh
new file mode 100644 (file)
index 0000000..fd4dd1c
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2011-2014 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 crossbar.
+ */
+
+#ifndef __MEM_COHERENT_XBAR_HH__
+#define __MEM_COHERENT_XBAR_HH__
+
+#include "base/hashmap.hh"
+#include "mem/snoop_filter.hh"
+#include "mem/xbar.hh"
+#include "params/CoherentXBar.hh"
+
+/**
+ * A coherent crossbar 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 crossbar 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.  @sa
+ * \ref gem5MemorySystem "gem5 Memory System"
+ */
+class CoherentXBar : public BaseXBar
+{
+
+  protected:
+
+    /**
+     * Declare the layers of this crossbar, one vector for requests,
+     * one for responses, and one for snoop responses
+     */
+    typedef Layer<SlavePort,MasterPort> ReqLayer;
+    typedef Layer<MasterPort,SlavePort> RespLayer;
+    typedef Layer<SlavePort,MasterPort> SnoopLayer;
+    std::vector<ReqLayer*> reqLayers;
+    std::vector<RespLayer*> respLayers;
+    std::vector<SnoopLayer*> snoopLayers;
+
+    /**
+     * Declaration of the coherent crossbar slave port type, one will
+     * be instantiated for each of the master ports connecting to the
+     * crossbar.
+     */
+    class CoherentXBarSlavePort : public SlavePort
+    {
+
+      private:
+
+        /** A reference to the crossbar to which this port belongs. */
+        CoherentXBar &xbar;
+
+      public:
+
+        CoherentXBarSlavePort(const std::string &_name,
+                             CoherentXBar &_xbar, PortID _id)
+            : SlavePort(_name, &_xbar, _id), xbar(_xbar)
+        { }
+
+      protected:
+
+        /**
+         * When receiving a timing request, pass it to the crossbar.
+         */
+        virtual bool recvTimingReq(PacketPtr pkt)
+        { return xbar.recvTimingReq(pkt, id); }
+
+        /**
+         * When receiving a timing snoop response, pass it to the crossbar.
+         */
+        virtual bool recvTimingSnoopResp(PacketPtr pkt)
+        { return xbar.recvTimingSnoopResp(pkt, id); }
+
+        /**
+         * When receiving an atomic request, pass it to the crossbar.
+         */
+        virtual Tick recvAtomic(PacketPtr pkt)
+        { return xbar.recvAtomic(pkt, id); }
+
+        /**
+         * When receiving a functional request, pass it to the crossbar.
+         */
+        virtual void recvFunctional(PacketPtr pkt)
+        { xbar.recvFunctional(pkt, id); }
+
+        /**
+         * When receiving a retry, pass it to the crossbar.
+         */
+        virtual void recvRetry()
+        { panic("Crossbar slave ports should never retry.\n"); }
+
+        /**
+         * Return the union of all adress ranges seen by this crossbar.
+         */
+        virtual AddrRangeList getAddrRanges() const
+        { return xbar.getAddrRanges(); }
+
+    };
+
+    /**
+     * Declaration of the coherent crossbar master port type, one will be
+     * instantiated for each of the slave interfaces connecting to the
+     * crossbar.
+     */
+    class CoherentXBarMasterPort : public MasterPort
+    {
+      private:
+        /** A reference to the crossbar to which this port belongs. */
+        CoherentXBar &xbar;
+
+      public:
+
+        CoherentXBarMasterPort(const std::string &_name,
+                              CoherentXBar &_xbar, PortID _id)
+            : MasterPort(_name, &_xbar, _id), xbar(_xbar)
+        { }
+
+      protected:
+
+        /**
+         * Determine if this port should be considered a snooper. For
+         * a coherent crossbar 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 crossbar.
+         */
+        virtual bool recvTimingResp(PacketPtr pkt)
+        { return xbar.recvTimingResp(pkt, id); }
+
+        /**
+         * When receiving a timing snoop request, pass it to the crossbar.
+         */
+        virtual void recvTimingSnoopReq(PacketPtr pkt)
+        { return xbar.recvTimingSnoopReq(pkt, id); }
+
+        /**
+         * When receiving an atomic snoop request, pass it to the crossbar.
+         */
+        virtual Tick recvAtomicSnoop(PacketPtr pkt)
+        { return xbar.recvAtomicSnoop(pkt, id); }
+
+        /**
+         * When receiving a functional snoop request, pass it to the crossbar.
+         */
+        virtual void recvFunctionalSnoop(PacketPtr pkt)
+        { xbar.recvFunctionalSnoop(pkt, id); }
+
+        /** When reciving a range change from the peer port (at id),
+            pass it to the crossbar. */
+        virtual void recvRangeChange()
+        { xbar.recvRangeChange(id); }
+
+        /** When reciving a retry from the peer port (at id),
+            pass it to the crossbar. */
+        virtual void recvRetry()
+        { xbar.recvRetry(id); }
+
+    };
+
+    /**
+     * Internal class to bridge between an incoming snoop response
+     * from a slave port and forwarding it through an outgoing slave
+     * port. It is effectively a dangling master port.
+     */
+    class SnoopRespPort : public MasterPort
+    {
+
+      private:
+
+        /** The port which we mirror internally. */
+        SlavePort& slavePort;
+
+      public:
+
+        /**
+         * Create a snoop response port that mirrors a given slave port.
+         */
+        SnoopRespPort(SlavePort& slave_port, CoherentXBar& _xbar) :
+            MasterPort(slave_port.name() + ".snoopRespPort", &_xbar),
+            slavePort(slave_port) { }
+
+        /**
+         * Override the sending of retries and pass them on through
+         * the mirrored slave port.
+         */
+        void sendRetry() {
+            slavePort.sendRetry();
+        }
+
+        /**
+         * Provided as necessary.
+         */
+        void recvRetry() { panic("SnoopRespPort should never see retry\n"); }
+
+        /**
+         * Provided as necessary.
+         */
+        bool recvTimingResp(PacketPtr pkt)
+        {
+            panic("SnoopRespPort should never see timing response\n");
+            return false;
+        }
+
+    };
+
+    std::vector<SnoopRespPort*> snoopRespPorts;
+
+    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 crossbar when coherency responses come back.
+     */
+    m5::hash_set<RequestPtr> outstandingReq;
+
+    /**
+     * Keep a pointer to the system to be allow to querying memory system
+     * properties.
+     */
+    System *system;
+
+    /** A snoop filter that tracks cache line residency and can restrict the
+      * broadcast needed for probes.  NULL denotes an absent filter. */
+    SnoopFilter *snoopFilter;
+
+    /** Function called by the port when the crossbar is recieving a Timing
+      request packet.*/
+    bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
+
+    /** Function called by the port when the crossbar is recieving a Timing
+      response packet.*/
+    bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
+
+    /** Function called by the port when the crossbar is recieving a timing
+        snoop request.*/
+    void recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id);
+
+    /** Function called by the port when the crossbar is recieving a timing
+        snoop response.*/
+    bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id);
+
+    /** Timing function called by port when it is once again able to process
+     * requests. */
+    void recvRetry(PortID master_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) {
+        forwardTiming(pkt, exclude_slave_port_id, snoopPorts);
+    }
+
+    /**
+     * Forward a timing packet to a selected list of 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
+     * @param dests Vector of destination ports for the forwarded pkt
+     */
+    void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id,
+                       const std::vector<SlavePort*>& dests);
+
+    /** Function called by the port when the crossbar is recieving a Atomic
+      transaction.*/
+    Tick recvAtomic(PacketPtr pkt, PortID slave_port_id);
+
+    /** Function called by the port when the crossbar 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)
+    {
+        return forwardAtomic(pkt, exclude_slave_port_id, InvalidPortID, snoopPorts);
+    }
+
+    /**
+     * Forward an atomic packet to a selected list of 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
+     * @param source_master_port_id Id of the master port for snoops from below
+     * @param dests Vector of destination ports for the forwarded pkt
+     *
+     * @return a pair containing the snoop response and snoop latency
+     */
+    std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
+                                          PortID exclude_slave_port_id,
+                                          PortID source_master_port_id,
+                                          const std::vector<SlavePort*>& dests);
+
+    /** Function called by the port when the crossbar is recieving a Functional
+        transaction.*/
+    void recvFunctional(PacketPtr pkt, PortID slave_port_id);
+
+    /** Function called by the port when the crossbar 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);
+
+    Stats::Scalar snoops;
+    Stats::Distribution snoopFanout;
+
+  public:
+
+    virtual void init();
+
+    CoherentXBar(const CoherentXBarParams *p);
+
+    virtual ~CoherentXBar();
+
+    unsigned int drain(DrainManager *dm);
+
+    virtual void regStats();
+};
+
+#endif //__MEM_COHERENT_XBAR_HH__
index 38c240fcff216839a3b06085a10ad65bc8e83de7..198cb52a4f18656a12c2e8f6e8f3de6b44fe4e3c 100644 (file)
@@ -819,7 +819,7 @@ DRAMCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency)
         assert(pkt->isResponse());
 
         // @todo someone should pay for this
-        pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+        pkt->firstWordDelay = pkt->lastWordDelay = 0;
 
         // queue the packet in the response queue to be sent out after
         // the static latency has passed
index 27dc3697651b49a598145d6949f2b0249277c18f..3356fd7d2fd5bc8697a683da87f7d29186538b52 100644 (file)
@@ -268,7 +268,7 @@ DRAMSim2::accessAndRespond(PacketPtr pkt)
         assert(pkt->isResponse());
 
         // @todo someone should pay for this
-        pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+        pkt->firstWordDelay = pkt->lastWordDelay = 0;
 
         DPRINTF(DRAMSim2, "Queuing response for address %lld\n",
                 pkt->getAddr());
diff --git a/src/mem/noncoherent_bus.cc b/src/mem/noncoherent_bus.cc
deleted file mode 100644 (file)
index d34ae6d..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (c) 2011-2013 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.master[%d]", name(), i);
-        MasterPort* bp = new NoncoherentBusMasterPort(portName, *this, i);
-        masterPorts.push_back(bp);
-        reqLayers.push_back(new ReqLayer(*bp, *this,
-                                         csprintf(".reqLayer%d", i)));
-    }
-
-    // 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 = name() + ".default";
-        MasterPort* bp = new NoncoherentBusMasterPort(portName, *this,
-                                                      defaultPortID);
-        masterPorts.push_back(bp);
-        reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%d",
-                                                              defaultPortID)));
-    }
-
-    // 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.slave[%d]", name(), i);
-        SlavePort* bp = new NoncoherentBusSlavePort(portName, *this, i);
-        slavePorts.push_back(bp);
-        respLayers.push_back(new RespLayer(*bp, *this,
-                                           csprintf(".respLayer%d", i)));
-    }
-
-    clearPortCache();
-}
-
-NoncoherentBus::~NoncoherentBus()
-{
-    for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l)
-        delete *l;
-    for (auto l = respLayers.begin(); l != respLayers.end(); ++l)
-        delete *l;
-}
-
-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());
-
-    // determine the destination based on the address
-    PortID master_port_id = findPort(pkt->getAddr());
-
-    // test if the bus should be considered occupied for the current
-    // port
-    if (!reqLayers[master_port_id]->tryTiming(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());
-
-    // store size and command as they might be modified when
-    // forwarding the packet
-    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
-    unsigned int pkt_cmd = pkt->cmdToIndex();
-
-    // set the source port for routing of the response
-    pkt->setSrc(slave_port_id);
-
-    calcPacketTiming(pkt);
-    Tick packetFinishTime = pkt->busLastWordDelay + curTick();
-
-    // since it is a normal request, attempt to send the packet
-    bool success = masterPorts[master_port_id]->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());
-
-        // undo the calculation so we can check for 0 again
-        pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
-
-        // occupy until the header is sent
-        reqLayers[master_port_id]->failedTiming(src_port,
-                                                clockEdge(headerCycles));
-
-        return false;
-    }
-
-    reqLayers[master_port_id]->succeededTiming(packetFinishTime);
-
-    // stats updates
-    dataThroughBus += pkt_size;
-    pktCount[slave_port_id][master_port_id]++;
-    totPktSize[slave_port_id][master_port_id] += pkt_size;
-    transDist[pkt_cmd]++;
-
-    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];
-
-    // determine the destination based on what is stored in the packet
-    PortID slave_port_id = pkt->getDest();
-
-    // test if the bus should be considered occupied for the current
-    // port
-    if (!respLayers[slave_port_id]->tryTiming(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());
-
-    // store size and command as they might be modified when
-    // forwarding the packet
-    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
-    unsigned int pkt_cmd = pkt->cmdToIndex();
-
-    calcPacketTiming(pkt);
-    Tick packetFinishTime = pkt->busLastWordDelay + curTick();
-
-    // send the packet through the destination slave port
-    bool success M5_VAR_USED = slavePorts[slave_port_id]->sendTimingResp(pkt);
-
-    // currently it is illegal to block responses... can lead to
-    // deadlock
-    assert(success);
-
-    respLayers[slave_port_id]->succeededTiming(packetFinishTime);
-
-    // stats updates
-    dataThroughBus += pkt_size;
-    pktCount[slave_port_id][master_port_id]++;
-    totPktSize[slave_port_id][master_port_id] += pkt_size;
-    transDist[pkt_cmd]++;
-
-    return true;
-}
-
-void
-NoncoherentBus::recvRetry(PortID master_port_id)
-{
-    // responses never block on forwarding them, so the retry will
-    // always be coming from a port to which we tried to forward a
-    // request
-    reqLayers[master_port_id]->recvRetry();
-}
-
-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());
-
-    // add the request data
-    dataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
-
-    // 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);
-
-    // add the response data
-    if (pkt->isResponse())
-        dataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
-
-    // @todo: Not setting first-word time
-    pkt->busLastWordDelay = 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);
-}
-
-unsigned int
-NoncoherentBus::drain(DrainManager *dm)
-{
-    // sum up the individual layers
-    unsigned int total = 0;
-    for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l)
-        total += (*l)->drain(dm);
-    for (auto l = respLayers.begin(); l != respLayers.end(); ++l)
-        total += (*l)->drain(dm);
-    return total;
-}
-
-NoncoherentBus*
-NoncoherentBusParams::create()
-{
-    return new NoncoherentBus(this);
-}
-
-void
-NoncoherentBus::regStats()
-{
-    // register the stats of the base class and our two bus layers
-    BaseBus::regStats();
-    for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l)
-        (*l)->regStats();
-    for (auto l = respLayers.begin(); l != respLayers.end(); ++l)
-        (*l)->regStats();
-
-    dataThroughBus
-        .name(name() + ".data_through_bus")
-        .desc("Total data (bytes)")
-        ;
-
-    throughput
-        .name(name() + ".throughput")
-        .desc("Throughput (bytes/s)")
-        .precision(0)
-        ;
-
-    throughput = dataThroughBus / simSeconds;
-}
diff --git a/src/mem/noncoherent_bus.hh b/src/mem/noncoherent_bus.hh
deleted file mode 100644 (file)
index a1b9da6..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (c) 2011-2013 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:
-
-    /**
-     * Declare the layers of this bus, one vector for requests and one
-     * for responses.
-     */
-    typedef Layer<SlavePort,MasterPort> ReqLayer;
-    typedef Layer<MasterPort,SlavePort> RespLayer;
-    std::vector<ReqLayer*> reqLayers;
-    std::vector<RespLayer*> respLayers;
-
-    /**
-     * 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() const
-        { return bus.getAddrRanges(); }
-
-    };
-
-    /**
-     * 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(id); }
-
-    };
-
-    /** Function called by the port when the bus is recieving a Timing
-      request packet.*/
-    virtual bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
-
-    /** Function called by the port when the bus is recieving a Timing
-      response packet.*/
-    virtual bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
-
-    /** Timing function called by port when it is once again able to process
-     * requests. */
-    void recvRetry(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);
-
-    virtual ~NoncoherentBus();
-
-    unsigned int drain(DrainManager *dm);
-
-    /**
-     * stats
-     */
-    virtual void regStats();
-    Stats::Scalar dataThroughBus;
-};
-
-#endif //__MEM_NONCOHERENT_BUS_HH__
diff --git a/src/mem/noncoherent_xbar.cc b/src/mem/noncoherent_xbar.cc
new file mode 100644 (file)
index 0000000..bc51be5
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2011-2014 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 non-coherent crossbar object.
+ */
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "debug/NoncoherentXBar.hh"
+#include "debug/XBar.hh"
+#include "mem/noncoherent_xbar.hh"
+
+NoncoherentXBar::NoncoherentXBar(const NoncoherentXBarParams *p)
+    : BaseXBar(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.master[%d]", name(), i);
+        MasterPort* bp = new NoncoherentXBarMasterPort(portName, *this, i);
+        masterPorts.push_back(bp);
+        reqLayers.push_back(new ReqLayer(*bp, *this,
+                                         csprintf(".reqLayer%d", i)));
+    }
+
+    // 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 = name() + ".default";
+        MasterPort* bp = new NoncoherentXBarMasterPort(portName, *this,
+                                                      defaultPortID);
+        masterPorts.push_back(bp);
+        reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%d",
+                                                              defaultPortID)));
+    }
+
+    // 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.slave[%d]", name(), i);
+        SlavePort* bp = new NoncoherentXBarSlavePort(portName, *this, i);
+        slavePorts.push_back(bp);
+        respLayers.push_back(new RespLayer(*bp, *this,
+                                           csprintf(".respLayer%d", i)));
+    }
+
+    clearPortCache();
+}
+
+NoncoherentXBar::~NoncoherentXBar()
+{
+    for (auto l: reqLayers)
+        delete l;
+    for (auto l: respLayers)
+        delete l;
+}
+
+bool
+NoncoherentXBar::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 crossbar
+    assert(!pkt->isExpressSnoop());
+
+    // determine the destination based on the address
+    PortID master_port_id = findPort(pkt->getAddr());
+
+    // test if the layer should be considered occupied for the current
+    // port
+    if (!reqLayers[master_port_id]->tryTiming(src_port)) {
+        DPRINTF(NoncoherentXBar, "recvTimingReq: src %s %s 0x%x BUSY\n",
+                src_port->name(), pkt->cmdString(), pkt->getAddr());
+        return false;
+    }
+
+    DPRINTF(NoncoherentXBar, "recvTimingReq: src %s %s 0x%x\n",
+            src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+    // store size and command as they might be modified when
+    // forwarding the packet
+    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+    unsigned int pkt_cmd = pkt->cmdToIndex();
+
+    // set the source port for routing of the response
+    pkt->setSrc(slave_port_id);
+
+    calcPacketTiming(pkt);
+    Tick packetFinishTime = pkt->lastWordDelay + curTick();
+
+    // since it is a normal request, attempt to send the packet
+    bool success = masterPorts[master_port_id]->sendTimingReq(pkt);
+
+    if (!success)  {
+        // inhibited packets should never be forced to retry
+        assert(!pkt->memInhibitAsserted());
+
+        DPRINTF(NoncoherentXBar, "recvTimingReq: src %s %s 0x%x RETRY\n",
+                src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+        // undo the calculation so we can check for 0 again
+        pkt->firstWordDelay = pkt->lastWordDelay = 0;
+
+        // occupy until the header is sent
+        reqLayers[master_port_id]->failedTiming(src_port,
+                                                clockEdge(headerCycles));
+
+        return false;
+    }
+
+    reqLayers[master_port_id]->succeededTiming(packetFinishTime);
+
+    // stats updates
+    pktCount[slave_port_id][master_port_id]++;
+    pktSize[slave_port_id][master_port_id] += pkt_size;
+    transDist[pkt_cmd]++;
+
+    return true;
+}
+
+bool
+NoncoherentXBar::recvTimingResp(PacketPtr pkt, PortID master_port_id)
+{
+    // determine the source port based on the id
+    MasterPort *src_port = masterPorts[master_port_id];
+
+    // determine the destination based on what is stored in the packet
+    PortID slave_port_id = pkt->getDest();
+
+    // test if the layer should be considered occupied for the current
+    // port
+    if (!respLayers[slave_port_id]->tryTiming(src_port)) {
+        DPRINTF(NoncoherentXBar, "recvTimingResp: src %s %s 0x%x BUSY\n",
+                src_port->name(), pkt->cmdString(), pkt->getAddr());
+        return false;
+    }
+
+    DPRINTF(NoncoherentXBar, "recvTimingResp: src %s %s 0x%x\n",
+            src_port->name(), pkt->cmdString(), pkt->getAddr());
+
+    // store size and command as they might be modified when
+    // forwarding the packet
+    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+    unsigned int pkt_cmd = pkt->cmdToIndex();
+
+    calcPacketTiming(pkt);
+    Tick packetFinishTime = pkt->lastWordDelay + curTick();
+
+    // send the packet through the destination slave port
+    bool success M5_VAR_USED = slavePorts[slave_port_id]->sendTimingResp(pkt);
+
+    // currently it is illegal to block responses... can lead to
+    // deadlock
+    assert(success);
+
+    respLayers[slave_port_id]->succeededTiming(packetFinishTime);
+
+    // stats updates
+    pktCount[slave_port_id][master_port_id]++;
+    pktSize[slave_port_id][master_port_id] += pkt_size;
+    transDist[pkt_cmd]++;
+
+    return true;
+}
+
+void
+NoncoherentXBar::recvRetry(PortID master_port_id)
+{
+    // responses never block on forwarding them, so the retry will
+    // always be coming from a port to which we tried to forward a
+    // request
+    reqLayers[master_port_id]->recvRetry();
+}
+
+Tick
+NoncoherentXBar::recvAtomic(PacketPtr pkt, PortID slave_port_id)
+{
+    DPRINTF(NoncoherentXBar, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
+            slavePorts[slave_port_id]->name(), pkt->getAddr(),
+            pkt->cmdString());
+
+    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+    unsigned int pkt_cmd = pkt->cmdToIndex();
+
+    // determine the destination port
+    PortID master_port_id = findPort(pkt->getAddr());
+
+    // stats updates for the request
+    pktCount[slave_port_id][master_port_id]++;
+    pktSize[slave_port_id][master_port_id] += pkt_size;
+    transDist[pkt_cmd]++;
+
+    // forward the request to the appropriate destination
+    Tick response_latency = masterPorts[master_port_id]->sendAtomic(pkt);
+
+    // add the response data
+    if (pkt->isResponse()) {
+        pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+        pkt_cmd = pkt->cmdToIndex();
+
+        // stats updates
+        pktCount[slave_port_id][master_port_id]++;
+        pktSize[slave_port_id][master_port_id] += pkt_size;
+        transDist[pkt_cmd]++;
+    }
+
+    // @todo: Not setting first-word time
+    pkt->lastWordDelay = response_latency;
+    return response_latency;
+}
+
+void
+NoncoherentXBar::recvFunctional(PacketPtr pkt, PortID slave_port_id)
+{
+    if (!pkt->isPrint()) {
+        // don't do DPRINTFs on PrintReq as it clutters up the output
+        DPRINTF(NoncoherentXBar,
+                "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);
+}
+
+unsigned int
+NoncoherentXBar::drain(DrainManager *dm)
+{
+    // sum up the individual layers
+    unsigned int total = 0;
+    for (auto l: reqLayers)
+        total += l->drain(dm);
+    for (auto l: respLayers)
+        total += l->drain(dm);
+    return total;
+}
+
+NoncoherentXBar*
+NoncoherentXBarParams::create()
+{
+    return new NoncoherentXBar(this);
+}
+
+void
+NoncoherentXBar::regStats()
+{
+    // register the stats of the base class and our layers
+    BaseXBar::regStats();
+    for (auto l: reqLayers)
+        l->regStats();
+    for (auto l: respLayers)
+        l->regStats();
+}
diff --git a/src/mem/noncoherent_xbar.hh b/src/mem/noncoherent_xbar.hh
new file mode 100644 (file)
index 0000000..122fc6b
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2011-2014 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 crossbar.
+ */
+
+#ifndef __MEM_NONCOHERENT_XBAR_HH__
+#define __MEM_NONCOHERENT_XBAR_HH__
+
+#include "mem/xbar.hh"
+#include "params/NoncoherentXBar.hh"
+
+/**
+ * A non-coherent crossbar 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 crossbar could still snoop in caches attached to a
+ * coherent crossbar, 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 crossbar itself.
+ *
+ * The non-coherent crossbar can be used as a template for modelling
+ * PCIe, and non-coherent AMBA and OCP buses, and is typically used
+ * for the I/O buses.
+ */
+class NoncoherentXBar : public BaseXBar
+{
+
+  protected:
+
+    /**
+     * Declare the layers of this crossbar, one vector for requests
+     * and one for responses.
+     */
+    typedef Layer<SlavePort,MasterPort> ReqLayer;
+    typedef Layer<MasterPort,SlavePort> RespLayer;
+    std::vector<ReqLayer*> reqLayers;
+    std::vector<RespLayer*> respLayers;
+
+    /**
+     * Declaration of the non-coherent crossbar slave port type, one
+     * will be instantiated for each of the master ports connecting to
+     * the crossbar.
+     */
+    class NoncoherentXBarSlavePort : public SlavePort
+    {
+      private:
+
+        /** A reference to the crossbar to which this port belongs. */
+        NoncoherentXBar &xbar;
+
+      public:
+
+        NoncoherentXBarSlavePort(const std::string &_name,
+                                NoncoherentXBar &_xbar, PortID _id)
+            : SlavePort(_name, &_xbar, _id), xbar(_xbar)
+        { }
+
+      protected:
+
+        /**
+         * When receiving a timing request, pass it to the crossbar.
+         */
+        virtual bool recvTimingReq(PacketPtr pkt)
+        { return xbar.recvTimingReq(pkt, id); }
+
+        /**
+         * When receiving an atomic request, pass it to the crossbar.
+         */
+        virtual Tick recvAtomic(PacketPtr pkt)
+        { return xbar.recvAtomic(pkt, id); }
+
+        /**
+         * When receiving a functional request, pass it to the crossbar.
+         */
+        virtual void recvFunctional(PacketPtr pkt)
+        { xbar.recvFunctional(pkt, id); }
+
+        /**
+         * When receiving a retry, pass it to the crossbar.
+         */
+        virtual void recvRetry()
+        { panic("Crossbar slave ports should never retry.\n"); }
+
+        /**
+         * Return the union of all adress ranges seen by this crossbar.
+         */
+        virtual AddrRangeList getAddrRanges() const
+        { return xbar.getAddrRanges(); }
+
+    };
+
+    /**
+     * Declaration of the crossbar master port type, one will be
+     * instantiated for each of the slave ports connecting to the
+     * crossbar.
+     */
+    class NoncoherentXBarMasterPort : public MasterPort
+    {
+      private:
+
+        /** A reference to the crossbar to which this port belongs. */
+        NoncoherentXBar &xbar;
+
+      public:
+
+        NoncoherentXBarMasterPort(const std::string &_name,
+                                 NoncoherentXBar &_xbar, PortID _id)
+            : MasterPort(_name, &_xbar, _id), xbar(_xbar)
+        { }
+
+      protected:
+
+        /**
+         * When receiving a timing response, pass it to the crossbar.
+         */
+        virtual bool recvTimingResp(PacketPtr pkt)
+        { return xbar.recvTimingResp(pkt, id); }
+
+        /** When reciving a range change from the peer port (at id),
+            pass it to the crossbar. */
+        virtual void recvRangeChange()
+        { xbar.recvRangeChange(id); }
+
+        /** When reciving a retry from the peer port (at id),
+            pass it to the crossbar. */
+        virtual void recvRetry()
+        { xbar.recvRetry(id); }
+
+    };
+
+    /** Function called by the port when the crossbar is recieving a Timing
+      request packet.*/
+    virtual bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
+
+    /** Function called by the port when the crossbar is recieving a Timing
+      response packet.*/
+    virtual bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
+
+    /** Timing function called by port when it is once again able to process
+     * requests. */
+    void recvRetry(PortID master_port_id);
+
+    /** Function called by the port when the crossbar is recieving a Atomic
+      transaction.*/
+    Tick recvAtomic(PacketPtr pkt, PortID slave_port_id);
+
+    /** Function called by the port when the crossbar is recieving a Functional
+        transaction.*/
+    void recvFunctional(PacketPtr pkt, PortID slave_port_id);
+
+  public:
+
+    NoncoherentXBar(const NoncoherentXBarParams *p);
+
+    virtual ~NoncoherentXBar();
+
+    unsigned int drain(DrainManager *dm);
+
+    /**
+     * stats
+     */
+    virtual void regStats();
+    Stats::Scalar totPktSize;
+};
+
+#endif //__MEM_NONCOHERENT_XBAR_HH__
index c070eaea776fb57a797d02eec4f5d6bd3ee8b185..4ed307f66e57d2b192afce39292020de5218e423 100644 (file)
@@ -293,14 +293,14 @@ class Packet : public Printable
     /**
      * Source port identifier set on a request packet to enable
      * appropriate routing of the responses. The source port
-     * identifier is set by any multiplexing component, e.g. a bus, as
-     * the timing responses need this information to be routed back to
-     * the appropriate port at a later point in time. The field can be
-     * updated (over-written) as the request packet passes through
-     * additional multiplexing components, and it is their
-     * responsibility to remember the original source port identifier,
-     * for example by using an appropriate sender state. The latter is
-     * done in the cache and bridge.
+     * identifier is set by any multiplexing component, e.g. a
+     * crossbar, as the timing responses need this information to be
+     * routed back to the appropriate port at a later point in
+     * time. The field can be updated (over-written) as the request
+     * packet passes through additional multiplexing components, and
+     * it is their responsibility to remember the original source port
+     * identifier, for example by using an appropriate sender
+     * state. The latter is done in the cache and bridge.
      */
     PortID src;
 
@@ -309,7 +309,7 @@ class Packet : public Printable
      * packets that passed through a multiplexing component as a
      * request packet. The source port identifier is turned into a
      * destination port identifier when the packet is turned into a
-     * response, and the destination is used, e.g. by the bus, to
+     * response, and the destination is used, e.g. by the crossbar, to
      * select the appropriate path through the interconnect.
      */
     PortID dest;
@@ -333,21 +333,22 @@ class Packet : public Printable
 
     /**
      * The extra delay from seeing the packet until the first word is
-     * transmitted by the bus that provided it (if any). This delay is
-     * used to communicate the bus waiting time to the neighbouring
-     * object (e.g. a cache) that actually makes the packet wait. As
-     * the delay is relative, a 32-bit unsigned should be sufficient.
+     * transmitted. This delay is used to communicate the crossbar
+     * forwarding latency to the neighbouring object (e.g. a cache)
+     * that actually makes the packet wait. As the delay is relative,
+     * a 32-bit unsigned should be sufficient.
      */
-    uint32_t busFirstWordDelay;
+    uint32_t firstWordDelay;
 
     /**
-     * The extra delay from seeing the packet until the last word is
-     * transmitted by the bus that provided it (if any). Similar to
-     * the first word time, this is used to make up for the fact that
-     * the bus does not make the packet wait. As the delay is relative,
-     * a 32-bit unsigned should be sufficient.
+     * The extra pipelining delay from seeing the packet until the
+     * last word is transmitted by the component that provided it (if
+     * any). This includes the first word delay. Similar to the first
+     * word delay, this is used to make up for the fact that the
+     * crossbar does not make the packet wait. As the delay is
+     * relative, a 32-bit unsigned should be sufficient.
      */
-    uint32_t busLastWordDelay;
+    uint32_t lastWordDelay;
 
     /**
      * A virtual base opaque structure used to hold state associated
@@ -541,8 +542,6 @@ class Packet : public Printable
     PortID getSrc() const { assert(isSrcValid()); return src; }
     /// Accessor function to set the source index of the packet.
     void setSrc(PortID _src) { src = _src; }
-    /// Reset source field, e.g. to retransmit packet on different bus.
-    void clearSrc() { src = InvalidPortID; }
 
     bool isDestValid() const { return dest != InvalidPortID; }
     /// Accessor function for the destination index of the packet.
@@ -604,7 +603,7 @@ class Packet : public Printable
         :  cmd(_cmd), req(_req), data(nullptr), addr(0), _isSecure(false),
            src(InvalidPortID), dest(InvalidPortID),
            bytesValidStart(0), bytesValidEnd(0),
-           busFirstWordDelay(0), busLastWordDelay(0),
+           firstWordDelay(0), lastWordDelay(0),
            senderState(NULL)
     {
         if (req->hasPaddr()) {
@@ -627,7 +626,7 @@ class Packet : public Printable
         :  cmd(_cmd), req(_req), data(nullptr), addr(0), _isSecure(false),
            src(InvalidPortID), dest(InvalidPortID),
            bytesValidStart(0), bytesValidEnd(0),
-           busFirstWordDelay(0), busLastWordDelay(0),
+           firstWordDelay(0), lastWordDelay(0),
            senderState(NULL)
     {
         if (req->hasPaddr()) {
@@ -653,8 +652,8 @@ class Packet : public Printable
            src(pkt->src), dest(pkt->dest),
            bytesValidStart(pkt->bytesValidStart),
            bytesValidEnd(pkt->bytesValidEnd),
-           busFirstWordDelay(pkt->busFirstWordDelay),
-           busLastWordDelay(pkt->busLastWordDelay),
+           firstWordDelay(pkt->firstWordDelay),
+           lastWordDelay(pkt->lastWordDelay),
            senderState(pkt->senderState)
     {
         if (!clearFlags)
@@ -739,8 +738,8 @@ class Packet : public Printable
         dest = InvalidPortID;
         bytesValidStart = 0;
         bytesValidEnd = 0;
-        busFirstWordDelay = 0;
-        busLastWordDelay = 0;
+        firstWordDelay = 0;
+        lastWordDelay = 0;
 
         flags.set(VALID_ADDR|VALID_SIZE);
         deleteData();
@@ -766,7 +765,7 @@ class Packet : public Printable
         flags.clear(EXPRESS_SNOOP);
 
         dest = src;
-        clearSrc();
+        src = InvalidPortID;
     }
 
     void
index 1b76b52e8f33df0b699c8dd919c12aa6861daf2a..08ec83410ffc1d5a8fb1621bc6d0f9bdb6a0310f 100644 (file)
@@ -51,7 +51,7 @@
 #include <string>
 
 #include "base/trace.hh"
-#include "debug/BusAddrRanges.hh"
+#include "debug/AddrRanges.hh"
 #include "debug/Checkpoint.hh"
 #include "mem/abstract_mem.hh"
 #include "mem/physical.hh"
@@ -79,7 +79,7 @@ PhysicalMemory::PhysicalMemory(const string& _name,
                 fatal("Memory address range for %s is overlapping\n",
                       (*m)->name());
         } else {
-            DPRINTF(BusAddrRanges,
+            DPRINTF(AddrRanges,
                     "Skipping memory %s that is not in global address map\n",
                     (*m)->name());
             // this type of memory is used e.g. as reference memory by
@@ -144,7 +144,7 @@ PhysicalMemory::createBackingStore(AddrRange range,
               range.to_string());
 
     // perform the actual mmap
-    DPRINTF(BusAddrRanges, "Creating backing store for range %s with size %d\n",
+    DPRINTF(AddrRanges, "Creating backing store for range %s with size %d\n",
             range.to_string(), range.size());
     int map_flags = MAP_ANON | MAP_PRIVATE;
     uint8_t* pmem = (uint8_t*) mmap(NULL, range.size(),
@@ -164,7 +164,7 @@ PhysicalMemory::createBackingStore(AddrRange range,
     // point the memories to their backing store
     for (vector<AbstractMemory*>::const_iterator m = _memories.begin();
          m != _memories.end(); ++m) {
-        DPRINTF(BusAddrRanges, "Mapping memory %s to backing store\n",
+        DPRINTF(AddrRanges, "Mapping memory %s to backing store\n",
                 (*m)->name());
         (*m)->setBackingStore(pmem);
     }
index b2d518dc76442f31f18a910ab03b5f905b6ae60a..11ed74b3b2127ab030071ecca72f31112094c97c 100644 (file)
@@ -122,7 +122,7 @@ SimpleMemory::recvTimingReq(PacketPtr pkt)
     }
 
     // @todo someone should pay for this
-    pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+    pkt->firstWordDelay = pkt->lastWordDelay = 0;
 
     // update the release time according to the bandwidth limit, and
     // do so with respect to the time it takes to finish this request
diff --git a/src/mem/xbar.cc b/src/mem/xbar.cc
new file mode 100644 (file)
index 0000000..6e4630f
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * Copyright (c) 2011-2014 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 crossbar object.
+ */
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "debug/AddrRanges.hh"
+#include "debug/Drain.hh"
+#include "debug/XBar.hh"
+#include "mem/xbar.hh"
+
+BaseXBar::BaseXBar(const BaseXBarParams *p)
+    : MemObject(p),
+      headerCycles(p->header_cycles), width(p->width),
+      gotAddrRanges(p->port_default_connection_count +
+                          p->port_master_connection_count, false),
+      gotAllAddrRanges(false), defaultPortID(InvalidPortID),
+      useDefaultRange(p->use_default_range)
+{}
+
+BaseXBar::~BaseXBar()
+{
+    for (auto m: masterPorts)
+        delete m;
+
+    for (auto s: slavePorts)
+        delete s;
+}
+
+void
+BaseXBar::init()
+{
+}
+
+BaseMasterPort &
+BaseXBar::getMasterPort(const std::string &if_name, PortID idx)
+{
+    if (if_name == "master" && idx < masterPorts.size()) {
+        // the master port index translates directly to the vector position
+        return *masterPorts[idx];
+    } else  if (if_name == "default") {
+        return *masterPorts[defaultPortID];
+    } else {
+        return MemObject::getMasterPort(if_name, idx);
+    }
+}
+
+BaseSlavePort &
+BaseXBar::getSlavePort(const std::string &if_name, PortID idx)
+{
+    if (if_name == "slave" && idx < slavePorts.size()) {
+        // the slave port index translates directly to the vector position
+        return *slavePorts[idx];
+    } else {
+        return MemObject::getSlavePort(if_name, idx);
+    }
+}
+
+void
+BaseXBar::calcPacketTiming(PacketPtr pkt)
+{
+    // the crossbar will be called at a time that is not necessarily
+    // coinciding with its own clock, so start by determining how long
+    // until the next clock edge (could be zero)
+    Tick offset = clockEdge() - curTick();
+
+    // determine how many cycles are needed to send the data
+    unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0;
+
+    // before setting the bus delay fields of the packet, ensure that
+    // the delay from any previous crossbar has been accounted for
+    if (pkt->firstWordDelay != 0 || pkt->lastWordDelay != 0)
+        panic("Packet %s already has delay (%d, %d) that should be "
+              "accounted for.\n", pkt->cmdString(), pkt->firstWordDelay,
+              pkt->lastWordDelay);
+
+    // The first word will be delivered on the cycle after the header.
+    pkt->firstWordDelay = (headerCycles + 1) * clockPeriod() + offset;
+
+    // Note that currently lastWordDelay can be smaller than
+    // firstWordDelay if the packet has no data
+    pkt->lastWordDelay = (headerCycles + dataCycles) * clockPeriod() +
+        offset;
+}
+
+template <typename SrcType, typename DstType>
+BaseXBar::Layer<SrcType,DstType>::Layer(DstType& _port, BaseXBar& _xbar,
+                                       const std::string& _name) :
+    port(_port), xbar(_xbar), _name(_name), state(IDLE), drainManager(NULL),
+    waitingForPeer(NULL), releaseEvent(this)
+{
+}
+
+template <typename SrcType, typename DstType>
+void BaseXBar::Layer<SrcType,DstType>::occupyLayer(Tick until)
+{
+    // ensure the state is busy at this point, as the layer should
+    // transition from idle as soon as it has decided to forward the
+    // packet to prevent any follow-on calls to sendTiming seeing an
+    // unoccupied layer
+    assert(state == BUSY);
+
+    // until should never be 0 as express snoops never occupy the layer
+    assert(until != 0);
+    xbar.schedule(releaseEvent, until);
+
+    // account for the occupied ticks
+    occupancy += until - curTick();
+
+    DPRINTF(BaseXBar, "The crossbar layer is now busy from tick %d to %d\n",
+            curTick(), until);
+}
+
+template <typename SrcType, typename DstType>
+bool
+BaseXBar::Layer<SrcType,DstType>::tryTiming(SrcType* src_port)
+{
+    // if we are in the retry state, we will not see anything but the
+    // retrying port (or in the case of the snoop ports the snoop
+    // response port that mirrors the actual slave port) as we leave
+    // this state again in zero time if the peer does not immediately
+    // call the layer when receiving the retry
+
+    // first we see if the layer is busy, next we check if the
+    // destination port is already engaged in a transaction waiting
+    // for a retry from the peer
+    if (state == BUSY || waitingForPeer != NULL) {
+        // the port should not be waiting already
+        assert(std::find(waitingForLayer.begin(), waitingForLayer.end(),
+                         src_port) == waitingForLayer.end());
+
+        // put the port at the end of the retry list waiting for the
+        // layer to be freed up (and in the case of a busy peer, for
+        // that transaction to go through, and then the layer to free
+        // up)
+        waitingForLayer.push_back(src_port);
+        return false;
+    }
+
+    state = BUSY;
+
+    return true;
+}
+
+template <typename SrcType, typename DstType>
+void
+BaseXBar::Layer<SrcType,DstType>::succeededTiming(Tick busy_time)
+{
+    // we should have gone from idle or retry to busy in the tryTiming
+    // test
+    assert(state == BUSY);
+
+    // occupy the layer accordingly
+    occupyLayer(busy_time);
+}
+
+template <typename SrcType, typename DstType>
+void
+BaseXBar::Layer<SrcType,DstType>::failedTiming(SrcType* src_port,
+                                              Tick busy_time)
+{
+    // ensure no one got in between and tried to send something to
+    // this port
+    assert(waitingForPeer == NULL);
+
+    // if the source port is the current retrying one or not, we have
+    // failed in forwarding and should track that we are now waiting
+    // for the peer to send a retry
+    waitingForPeer = src_port;
+
+    // we should have gone from idle or retry to busy in the tryTiming
+    // test
+    assert(state == BUSY);
+
+    // occupy the bus accordingly
+    occupyLayer(busy_time);
+}
+
+template <typename SrcType, typename DstType>
+void
+BaseXBar::Layer<SrcType,DstType>::releaseLayer()
+{
+    // releasing the bus means we should now be idle
+    assert(state == BUSY);
+    assert(!releaseEvent.scheduled());
+
+    // update the state
+    state = IDLE;
+
+    // bus layer is now idle, so if someone is waiting we can retry
+    if (!waitingForLayer.empty()) {
+        // there is no point in sending a retry if someone is still
+        // waiting for the peer
+        if (waitingForPeer == NULL)
+            retryWaiting();
+    } else if (waitingForPeer == NULL && drainManager) {
+        DPRINTF(Drain, "Crossbar done draining, signaling drain manager\n");
+        //If we weren't able to drain before, do it now.
+        drainManager->signalDrainDone();
+        // Clear the drain event once we're done with it.
+        drainManager = NULL;
+    }
+}
+
+template <typename SrcType, typename DstType>
+void
+BaseXBar::Layer<SrcType,DstType>::retryWaiting()
+{
+    // this should never be called with no one waiting
+    assert(!waitingForLayer.empty());
+
+    // we always go to retrying from idle
+    assert(state == IDLE);
+
+    // update the state
+    state = RETRY;
+
+    // set the retrying port to the front of the retry list and pop it
+    // off the list
+    SrcType* retryingPort = waitingForLayer.front();
+    waitingForLayer.pop_front();
+
+    // tell the port to retry, which in some cases ends up calling the
+    // layer again
+    retryingPort->sendRetry();
+
+    // If the layer is still in the retry state, sendTiming wasn't
+    // called in zero time (e.g. the cache does this), burn a cycle
+    if (state == RETRY) {
+        // update the state to busy and reset the retrying port, we
+        // have done our bit and sent the retry
+        state = BUSY;
+
+        // occupy the crossbar layer until the next cycle ends
+        occupyLayer(xbar.clockEdge(Cycles(1)));
+    }
+}
+
+template <typename SrcType, typename DstType>
+void
+BaseXBar::Layer<SrcType,DstType>::recvRetry()
+{
+    // we should never get a retry without having failed to forward
+    // something to this port
+    assert(waitingForPeer != NULL);
+
+    // add the port where the failed packet originated to the front of
+    // the waiting ports for the layer, this allows us to call retry
+    // on the port immediately if the crossbar layer is idle
+    waitingForLayer.push_front(waitingForPeer);
+
+    // we are no longer waiting for the peer
+    waitingForPeer = NULL;
+
+    // if the layer is idle, retry this port straight away, if we
+    // are busy, then simply let the port wait for its turn
+    if (state == IDLE) {
+        retryWaiting();
+    } else {
+        assert(state == BUSY);
+    }
+}
+
+PortID
+BaseXBar::findPort(Addr addr)
+{
+    // we should never see any address lookups before we've got the
+    // ranges of all connected slave modules
+    assert(gotAllAddrRanges);
+
+    // Check the cache
+    PortID dest_id = checkPortCache(addr);
+    if (dest_id != InvalidPortID)
+        return dest_id;
+
+    // Check the address map interval tree
+    auto i = portMap.find(addr);
+    if (i != portMap.end()) {
+        dest_id = i->second;
+        updatePortCache(dest_id, i->first);
+        return dest_id;
+    }
+
+    // Check if this matches the default range
+    if (useDefaultRange) {
+        if (defaultRange.contains(addr)) {
+            DPRINTF(AddrRanges, "  found addr %#llx on default\n",
+                    addr);
+            return defaultPortID;
+        }
+    } else if (defaultPortID != InvalidPortID) {
+        DPRINTF(AddrRanges, "Unable to find destination for addr %#llx, "
+                "will use default port\n", addr);
+        return defaultPortID;
+    }
+
+    // we should use the range for the default port and it did not
+    // match, or the default port is not set
+    fatal("Unable to find destination for addr %#llx on %s\n", addr,
+          name());
+}
+
+/** Function called by the port when the crossbar is receiving a range change.*/
+void
+BaseXBar::recvRangeChange(PortID master_port_id)
+{
+    DPRINTF(AddrRanges, "Received range change from slave port %s\n",
+            masterPorts[master_port_id]->getSlavePort().name());
+
+    // remember that we got a range from this master port and thus the
+    // connected slave module
+    gotAddrRanges[master_port_id] = true;
+
+    // update the global flag
+    if (!gotAllAddrRanges) {
+        // take a logical AND of all the ports and see if we got
+        // ranges from everyone
+        gotAllAddrRanges = true;
+        std::vector<bool>::const_iterator r = gotAddrRanges.begin();
+        while (gotAllAddrRanges &&  r != gotAddrRanges.end()) {
+            gotAllAddrRanges &= *r++;
+        }
+        if (gotAllAddrRanges)
+            DPRINTF(AddrRanges, "Got address ranges from all slaves\n");
+    }
+
+    // note that we could get the range from the default port at any
+    // point in time, and we cannot assume that the default range is
+    // set before the other ones are, so we do additional checks once
+    // all ranges are provided
+    if (master_port_id == defaultPortID) {
+        // only update if we are indeed checking ranges for the
+        // default port since the port might not have a valid range
+        // otherwise
+        if (useDefaultRange) {
+            AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
+
+            if (ranges.size() != 1)
+                fatal("Crossbar %s may only have a single default range",
+                      name());
+
+            defaultRange = ranges.front();
+        }
+    } else {
+        // the ports are allowed to update their address ranges
+        // dynamically, so remove any existing entries
+        if (gotAddrRanges[master_port_id]) {
+            for (auto p = portMap.begin(); p != portMap.end(); ) {
+                if (p->second == master_port_id)
+                    // erasing invalidates the iterator, so advance it
+                    // before the deletion takes place
+                    portMap.erase(p++);
+                else
+                    p++;
+            }
+        }
+
+        AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges();
+
+        for (const auto& r: ranges) {
+            DPRINTF(AddrRanges, "Adding range %s for id %d\n",
+                    r.to_string(), master_port_id);
+            if (portMap.insert(r, master_port_id) == portMap.end()) {
+                PortID conflict_id = portMap.find(r)->second;
+                fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
+                      name(),
+                      masterPorts[master_port_id]->getSlavePort().name(),
+                      masterPorts[conflict_id]->getSlavePort().name());
+            }
+        }
+    }
+
+    // if we have received ranges from all our neighbouring slave
+    // modules, go ahead and tell our connected master modules in
+    // turn, this effectively assumes a tree structure of the system
+    if (gotAllAddrRanges) {
+        DPRINTF(AddrRanges, "Aggregating address ranges\n");
+        xbarRanges.clear();
+
+        // start out with the default range
+        if (useDefaultRange) {
+            if (!gotAddrRanges[defaultPortID])
+                fatal("Crossbar %s uses default range, but none provided",
+                      name());
+
+            xbarRanges.push_back(defaultRange);
+            DPRINTF(AddrRanges, "-- Adding default %s\n",
+                    defaultRange.to_string());
+        }
+
+        // merge all interleaved ranges and add any range that is not
+        // a subset of the default range
+        std::vector<AddrRange> intlv_ranges;
+        for (const auto& r: portMap) {
+            // if the range is interleaved then save it for now
+            if (r.first.interleaved()) {
+                // if we already got interleaved ranges that are not
+                // part of the same range, then first do a merge
+                // before we add the new one
+                if (!intlv_ranges.empty() &&
+                    !intlv_ranges.back().mergesWith(r.first)) {
+                    DPRINTF(AddrRanges, "-- Merging range from %d ranges\n",
+                            intlv_ranges.size());
+                    AddrRange merged_range(intlv_ranges);
+                    // next decide if we keep the merged range or not
+                    if (!(useDefaultRange &&
+                          merged_range.isSubset(defaultRange))) {
+                        xbarRanges.push_back(merged_range);
+                        DPRINTF(AddrRanges, "-- Adding merged range %s\n",
+                                merged_range.to_string());
+                    }
+                    intlv_ranges.clear();
+                }
+                intlv_ranges.push_back(r.first);
+            } else {
+                // keep the current range if not a subset of the default
+                if (!(useDefaultRange &&
+                      r.first.isSubset(defaultRange))) {
+                    xbarRanges.push_back(r.first);
+                    DPRINTF(AddrRanges, "-- Adding range %s\n",
+                            r.first.to_string());
+                }
+            }
+        }
+
+        // if there is still interleaved ranges waiting to be merged,
+        // go ahead and do it
+        if (!intlv_ranges.empty()) {
+            DPRINTF(AddrRanges, "-- Merging range from %d ranges\n",
+                    intlv_ranges.size());
+            AddrRange merged_range(intlv_ranges);
+            if (!(useDefaultRange && merged_range.isSubset(defaultRange))) {
+                xbarRanges.push_back(merged_range);
+                DPRINTF(AddrRanges, "-- Adding merged range %s\n",
+                        merged_range.to_string());
+            }
+        }
+
+        // also check that no range partially overlaps with the
+        // default range, this has to be done after all ranges are set
+        // as there are no guarantees for when the default range is
+        // update with respect to the other ones
+        if (useDefaultRange) {
+            for (const auto& r: xbarRanges) {
+                // see if the new range is partially
+                // overlapping the default range
+                if (r.intersects(defaultRange) &&
+                    !r.isSubset(defaultRange))
+                    fatal("Range %s intersects the "                    \
+                          "default range of %s but is not a "           \
+                          "subset\n", r.to_string(), name());
+            }
+        }
+
+        // tell all our neighbouring master ports that our address
+        // ranges have changed
+        for (const auto& s: slavePorts)
+            s->sendRangeChange();
+    }
+
+    clearPortCache();
+}
+
+AddrRangeList
+BaseXBar::getAddrRanges() const
+{
+    // we should never be asked without first having sent a range
+    // change, and the latter is only done once we have all the ranges
+    // of the connected devices
+    assert(gotAllAddrRanges);
+
+    // at the moment, this never happens, as there are no cycles in
+    // the range queries and no devices on the master side of a crossbar
+    // (CPU, cache, bridge etc) actually care about the ranges of the
+    // ports they are connected to
+
+    DPRINTF(AddrRanges, "Received address range request\n");
+
+    return xbarRanges;
+}
+
+void
+BaseXBar::regStats()
+{
+    using namespace Stats;
+
+    transDist
+        .init(MemCmd::NUM_MEM_CMDS)
+        .name(name() + ".trans_dist")
+        .desc("Transaction distribution")
+        .flags(nozero);
+
+    // get the string representation of the commands
+    for (int i = 0; i < MemCmd::NUM_MEM_CMDS; i++) {
+        MemCmd cmd(i);
+        const std::string &cstr = cmd.toString();
+        transDist.subname(i, cstr);
+    }
+
+    pktCount
+        .init(slavePorts.size(), masterPorts.size())
+        .name(name() + ".pkt_count")
+        .desc("Packet count per connected master and slave (bytes)")
+        .flags(total | nozero | nonan);
+
+    pktSize
+        .init(slavePorts.size(), masterPorts.size())
+        .name(name() + ".pkt_size")
+        .desc("Cumulative packet size per connected master and slave (bytes)")
+        .flags(total | nozero | nonan);
+
+    // both the packet count and total size are two-dimensional
+    // vectors, indexed by slave port id and master port id, thus the
+    // neighbouring master and slave, they do not differentiate what
+    // came from the master and was forwarded to the slave (requests
+    // and snoop responses) and what came from the slave and was
+    // forwarded to the master (responses and snoop requests)
+    for (int i = 0; i < slavePorts.size(); i++) {
+        pktCount.subname(i, slavePorts[i]->getMasterPort().name());
+        pktSize.subname(i, slavePorts[i]->getMasterPort().name());
+        for (int j = 0; j < masterPorts.size(); j++) {
+            pktCount.ysubname(j, masterPorts[j]->getSlavePort().name());
+            pktSize.ysubname(j, masterPorts[j]->getSlavePort().name());
+        }
+    }
+}
+
+template <typename SrcType, typename DstType>
+unsigned int
+BaseXBar::Layer<SrcType,DstType>::drain(DrainManager *dm)
+{
+    //We should check that we're not "doing" anything, and that noone is
+    //waiting. We might be idle but have someone waiting if the device we
+    //contacted for a retry didn't actually retry.
+    if (state != IDLE) {
+        DPRINTF(Drain, "Crossbar not drained\n");
+        drainManager = dm;
+        return 1;
+    }
+    return 0;
+}
+
+template <typename SrcType, typename DstType>
+void
+BaseXBar::Layer<SrcType,DstType>::regStats()
+{
+    using namespace Stats;
+
+    occupancy
+        .name(name() + ".occupancy")
+        .desc("Layer occupancy (ticks)")
+        .flags(nozero);
+
+    utilization
+        .name(name() + ".utilization")
+        .desc("Layer utilization (%)")
+        .precision(1)
+        .flags(nozero);
+
+    utilization = 100 * occupancy / simTicks;
+}
+
+/**
+ * Crossbar layer template instantiations. Could be removed with _impl.hh
+ * file, but since there are only two given options (MasterPort and
+ * SlavePort) it seems a bit excessive at this point.
+ */
+template class BaseXBar::Layer<SlavePort,MasterPort>;
+template class BaseXBar::Layer<MasterPort,SlavePort>;
diff --git a/src/mem/xbar.hh b/src/mem/xbar.hh
new file mode 100644 (file)
index 0000000..7f3c176
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2011-2014 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 an abstract crossbar base class.
+ */
+
+#ifndef __MEM_XBAR_HH__
+#define __MEM_XBAR_HH__
+
+#include <deque>
+
+#include "base/addr_range_map.hh"
+#include "base/types.hh"
+#include "mem/mem_object.hh"
+#include "params/BaseXBar.hh"
+#include "sim/stats.hh"
+
+/**
+ * The base crossbar contains the common elements of the non-coherent
+ * and coherent crossbar. 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 BaseXBar is responsible for the basic flow control (busy or
+ * not), the administration of retries, and the address decoding.
+ */
+class BaseXBar : public MemObject
+{
+
+  protected:
+
+    /**
+     * A layer is an internal crossbar arbitration point with its own
+     * flow control. Each layer is a converging multiplexer tree. By
+     * instantiating one layer per destination port (and per packet
+     * type, i.e. request, response, snoop request and snoop
+     * response), we model full crossbar structures like AXI, ACE,
+     * PCIe, etc.
+     *
+     * The template parameter, PortClass, indicates the destination
+     * port type for the layer. The retry list holds either master
+     * ports or slave ports, depending on the direction of the
+     * layer. Thus, a request layer has a retry list containing slave
+     * ports, whereas a response layer holds master ports.
+     */
+    template <typename SrcType, typename DstType>
+    class Layer : public Drainable
+    {
+
+      public:
+
+        /**
+         * Create a layer and give it a name. The layer uses
+         * the crossbar an event manager.
+         *
+         * @param _port destination port the layer converges at
+         * @param _xbar the crossbar this layer belongs to
+         * @param _name the layer's name
+         */
+        Layer(DstType& _port, BaseXBar& _xbar, const std::string& _name);
+
+        /**
+         * Drain according to the normal semantics, so that the crossbar
+         * can tell the layer to drain, and pass an event to signal
+         * back when drained.
+         *
+         * @param de drain event to call once drained
+         *
+         * @return 1 if busy or waiting to retry, or 0 if idle
+         */
+        unsigned int drain(DrainManager *dm);
+
+        /**
+         * Get the crossbar layer's name
+         */
+        const std::string name() const { return xbar.name() + _name; }
+
+
+        /**
+         * Determine if the layer accepts a packet from a specific
+         * port. If not, the port in question is also added to the
+         * retry list. In either case the state of the layer is
+         * updated accordingly.
+         *
+         * @param port Source port presenting the packet
+         *
+         * @return True if the layer accepts the packet
+         */
+        bool tryTiming(SrcType* src_port);
+
+        /**
+         * Deal with a destination port accepting a packet by potentially
+         * removing the source port from the retry list (if retrying) and
+         * occupying the layer accordingly.
+         *
+         * @param busy_time Time to spend as a result of a successful send
+         */
+        void succeededTiming(Tick busy_time);
+
+        /**
+         * Deal with a destination port not accepting a packet by
+         * potentially adding the source port to the retry list (if
+         * not already at the front) and occupying the layer
+         * accordingly.
+         *
+         * @param src_port Source port
+         * @param busy_time Time to spend as a result of a failed send
+         */
+        void failedTiming(SrcType* src_port, Tick busy_time);
+
+        /** Occupy the layer until until */
+        void occupyLayer(Tick until);
+
+        /**
+         * Send a retry to the port at the head of waitingForLayer. The
+         * caller must ensure that the list is not empty.
+         */
+        void retryWaiting();
+
+        /**
+         * Handle a retry from a neighbouring module. This wraps
+         * retryWaiting by verifying that there are ports waiting
+         * before calling retryWaiting.
+         */
+        void recvRetry();
+
+        /**
+         * Register stats for the layer
+         */
+        void regStats();
+
+      private:
+
+        /** The destination port this layer converges at. */
+        DstType& port;
+
+        /** The crossbar this layer is a part of. */
+        BaseXBar& xbar;
+
+        /** A name for this layer. */
+        std::string _name;
+
+        /**
+         * We declare an enum to track the state of the layer. The
+         * starting point is an idle state where the layer is waiting
+         * for a packet to arrive. Upon arrival, the layer
+         * transitions to the busy state, where it remains either
+         * until the packet transfer is done, or the header time is
+         * spent. Once the layer leaves the busy state, it can
+         * either go back to idle, if no packets have arrived while it
+         * was busy, or the layer goes on to retry the first port
+         * in waitingForLayer. A similar transition takes place from
+         * idle to retry if the layer receives a retry from one of
+         * its connected ports. The retry state lasts until the port
+         * in questions calls sendTiming and returns control to the
+         * layer, or goes to a busy state if the port does not
+         * immediately react to the retry by calling sendTiming.
+         */
+        enum State { IDLE, BUSY, RETRY };
+
+        /** track the state of the layer */
+        State state;
+
+        /** manager to signal when drained */
+        DrainManager *drainManager;
+
+        /**
+         * A deque of ports that retry should be called on because
+         * the original send was delayed due to a busy layer.
+         */
+        std::deque<SrcType*> waitingForLayer;
+
+        /**
+         * Track who is waiting for the retry when receiving it from a
+         * peer. If no port is waiting NULL is stored.
+         */
+        SrcType* waitingForPeer;
+
+        /**
+         * Release the layer after being occupied and return to an
+         * idle state where we proceed to send a retry to any
+         * potential waiting port, or drain if asked to do so.
+         */
+        void releaseLayer();
+
+        /** event used to schedule a release of the layer */
+        EventWrapper<Layer, &Layer::releaseLayer> releaseEvent;
+
+        /**
+         * Stats for occupancy and utilization. These stats capture
+         * the time the layer spends in the busy state and are thus only
+         * relevant when the memory system is in timing mode.
+         */
+        Stats::Scalar occupancy;
+        Stats::Formula utilization;
+
+    };
+
+    /** cycles of overhead per transaction */
+    const Cycles headerCycles;
+    /** the width of the xbar in bytes */
+    const uint32_t width;
+
+    AddrRangeMap<PortID> portMap;
+
+    /** all contigous ranges seen by this crossbar */
+    AddrRangeList xbarRanges;
+
+    AddrRange defaultRange;
+
+    /**
+     * Function called by the port when the crossbar is recieving a
+     * range change.
+     *
+     * @param master_port_id id of the port that received the change
+     */
+    void recvRangeChange(PortID master_port_id);
+
+    /** Find which port connected to this crossbar (if any) should be
+     * given a packet with this address.
+     *
+     * @param addr Address to find port for.
+     * @return id of port that the packet should be sent out of.
+     */
+    PortID findPort(Addr addr);
+
+    // Cache for the findPort function storing recently used ports from portMap
+    struct PortCache {
+        bool valid;
+        PortID id;
+        AddrRange range;
+    };
+
+    PortCache portCache[3];
+
+    // Checks the cache and returns the id of the port that has the requested
+    // address within its range
+    inline PortID checkPortCache(Addr addr) const {
+        if (portCache[0].valid && portCache[0].range.contains(addr)) {
+            return portCache[0].id;
+        }
+        if (portCache[1].valid && portCache[1].range.contains(addr)) {
+            return portCache[1].id;
+        }
+        if (portCache[2].valid && portCache[2].range.contains(addr)) {
+            return portCache[2].id;
+        }
+
+        return InvalidPortID;
+    }
+
+    // Clears the earliest entry of the cache and inserts a new port entry
+    inline void updatePortCache(short id, const AddrRange& range) {
+        portCache[2].valid = portCache[1].valid;
+        portCache[2].id    = portCache[1].id;
+        portCache[2].range = portCache[1].range;
+
+        portCache[1].valid = portCache[0].valid;
+        portCache[1].id    = portCache[0].id;
+        portCache[1].range = portCache[0].range;
+
+        portCache[0].valid = true;
+        portCache[0].id    = id;
+        portCache[0].range = range;
+    }
+
+    // Clears the cache. Needs to be called in constructor.
+    inline void clearPortCache() {
+        portCache[2].valid = false;
+        portCache[1].valid = false;
+        portCache[0].valid = false;
+    }
+
+    /**
+     * Return the address ranges the crossbar is responsible for.
+     *
+     * @return a list of non-overlapping address ranges
+     */
+    AddrRangeList getAddrRanges() const;
+
+    /**
+     * Calculate the timing parameters for the packet. Updates the
+     * firstWordDelay and lastWordDelay fields of the packet
+     * object with the relative number of ticks required to transmit
+     * the header and the first word, and the last word, respectively.
+     */
+    void calcPacketTiming(PacketPtr pkt);
+
+    /**
+     * Remember for each of the master ports of the crossbar if we got
+     * an address range from the connected slave. For convenience,
+     * also keep track of if we got ranges from all the slave modules
+     * or not.
+     */
+    std::vector<bool> gotAddrRanges;
+    bool gotAllAddrRanges;
+
+    /** The master and slave ports of the crossbar */
+    std::vector<SlavePort*> slavePorts;
+    std::vector<MasterPort*> masterPorts;
+
+    /** Port that handles requests that don't match any of the interfaces.*/
+    PortID defaultPortID;
+
+    /** If true, use address range provided by default device.  Any
+       address not handled by another port and not in default device's
+       range will cause a fatal error.  If false, just send all
+       addresses not handled by another port to default device. */
+    const bool useDefaultRange;
+
+    BaseXBar(const BaseXBarParams *p);
+
+    virtual ~BaseXBar();
+
+    /**
+     * Stats for transaction distribution and data passing through the
+     * crossbar. The transaction distribution is globally counting
+     * different types of commands. The packet count and total packet
+     * size are two-dimensional vectors that are indexed by the
+     * slave port and master port id (thus the neighbouring master and
+     * neighbouring slave), summing up both directions (request and
+     * response).
+     */
+    Stats::Vector transDist;
+    Stats::Vector2d pktCount;
+    Stats::Vector2d pktSize;
+
+  public:
+
+    virtual void init();
+
+    /** A function used to return the port associated with this object. */
+    BaseMasterPort& getMasterPort(const std::string& if_name,
+                                  PortID idx = InvalidPortID);
+    BaseSlavePort& getSlavePort(const std::string& if_name,
+                                PortID idx = InvalidPortID);
+
+    virtual unsigned int drain(DrainManager *dm) = 0;
+
+    virtual void regStats();
+
+};
+
+#endif //__MEM_XBAR_HH__
index cf576453033ab45565e8fdbc6a5377c2ac139bd1..6c4a61d6ae1056ff201c143c5208444b708da856 100644 (file)
@@ -1870,7 +1870,7 @@ class SlavePort(Port):
             raise TypeError, 'wrong number of arguments'
 
 # VectorPort description object.  Like Port, but represents a vector
-# of connections (e.g., as on a Bus).
+# of connections (e.g., as on a XBar).
 class VectorPort(Port):
     def __init__(self, *args):
         self.isVec = True
index ab4687f7f25a5162e58209385147393f27ac778d..f54d6a1ab022806e240b4b46c5113dc3eb59fdd4 100644 (file)
@@ -173,7 +173,7 @@ def dot_create_node(simNode, full_path, label):
 class NodeType:
     SYS = 0
     CPU = 1
-    BUS = 2
+    XBAR = 2
     MEM = 3
     DEV = 4
     OTHER = 5
@@ -190,8 +190,8 @@ def get_node_type(simNode):
     elif 'PioDevice' in dir(m5.objects) and \
             isinstance(simNode, m5.objects.PioDevice):
         return NodeType.DEV
-    elif isinstance(simNode, m5.objects.BaseBus):
-        return NodeType.BUS
+    elif isinstance(simNode, m5.objects.BaseXBar):
+        return NodeType.XBAR
     elif isinstance(simNode, m5.objects.AbstractMemory):
         return NodeType.MEM
     else:
@@ -205,7 +205,7 @@ def get_type_colour(nodeType):
         return (228, 231, 235)
     elif nodeType == NodeType.CPU:
         return (187, 198, 217)
-    elif nodeType == NodeType.BUS:
+    elif nodeType == NodeType.XBAR:
         return (111, 121, 140)
     elif nodeType == NodeType.MEM:
         return (94, 89, 88)
index e9487546d9c03c168b525c2b3aa3f7d65576368b..ccf1ea6f8761f0e4cb7b75ea44b2e7a945d022b0 100644 (file)
@@ -102,7 +102,7 @@ class BaseSystem(object):
         Returns:
           A bus that CPUs should use to connect to the shared cache.
         """
-        system.toL2Bus = CoherentBus(clk_domain=system.cpu_clk_domain)
+        system.toL2Bus = CoherentXBar(clk_domain=system.cpu_clk_domain)
         system.l2c = L2Cache(clk_domain=system.cpu_clk_domain,
                              size='4MB', assoc=8)
         system.l2c.cpu_side = system.toL2Bus.master
@@ -184,7 +184,7 @@ class BaseSESystem(BaseSystem):
 
     def create_system(self):
         system = System(physmem = self.mem_class(),
-                        membus = CoherentBus(),
+                        membus = CoherentXBar(),
                         mem_mode = self.mem_mode)
         system.system_port = system.membus.slave
         system.physmem.port = system.membus.master
index 4de009d76beff1338bcb5b6429c59b1b547d43cd..35d64a7936d57bc0f4d8a437e49fd80c28d27432 100644 (file)
@@ -37,9 +37,9 @@ cpus = [ MemTest() for i in xrange(nb_cores) ]
 
 # system simulated
 system = System(cpu = cpus, funcmem = SimpleMemory(in_addr_map = False),
-                funcbus = NoncoherentBus(),
+                funcbus = NoncoherentXBar(),
                 physmem = SimpleMemory(),
-                membus = CoherentBus(width=16, snoop_filter = SnoopFilter()))
+                membus = CoherentXBar(width=16, snoop_filter = SnoopFilter()))
 # Dummy voltage domain for all our clock domains
 system.voltage_domain = VoltageDomain()
 system.clk_domain = SrcClockDomain(clock = '1GHz',
@@ -50,8 +50,8 @@ system.clk_domain = SrcClockDomain(clock = '1GHz',
 system.cpu_clk_domain = SrcClockDomain(clock = '2GHz',
                                        voltage_domain = system.voltage_domain)
 
-system.toL2Bus = CoherentBus(clk_domain = system.cpu_clk_domain, width=16,
-                             snoop_filter = SnoopFilter())
+system.toL2Bus = CoherentXBar(clk_domain = system.cpu_clk_domain, width=16,
+                              snoop_filter = SnoopFilter())
 system.l2c = L2Cache(clk_domain = system.cpu_clk_domain, size='64kB', assoc=8)
 system.l2c.cpu_side = system.toL2Bus.master
 
index 071f3a7b57e33e6d3e043acb53854ec2a9f86827..08b73cd2fd4aa025274d75879dcd99f48e889330 100644 (file)
@@ -81,7 +81,7 @@ options.num_cpus = nb_cores
 system = System(cpu = cpus,
                 funcmem = SimpleMemory(in_addr_map = False),
                 physmem = SimpleMemory(null = True),
-                funcbus = NoncoherentBus())
+                funcbus = NoncoherentXBar())
 # Dummy voltage domain for all our clock domains
 system.voltage_domain = VoltageDomain()
 system.clk_domain = SrcClockDomain(clock = '1GHz',
index fbd18b779418bec07bec3e23ae8853fff3fee545..e1bdc64fa1e83b1acf6d2bfe2c64a2c8f9a74f81 100644 (file)
@@ -37,9 +37,9 @@ cpus = [ MemTest() for i in xrange(nb_cores) ]
 
 # system simulated
 system = System(cpu = cpus, funcmem = SimpleMemory(in_addr_map = False),
-                funcbus = NoncoherentBus(),
+                funcbus = NoncoherentXBar(),
                 physmem = SimpleMemory(),
-                membus = CoherentBus(width=16))
+                membus = CoherentXBar(width=16))
 # Dummy voltage domain for all our clock domains
 system.voltage_domain = VoltageDomain()
 system.clk_domain = SrcClockDomain(clock = '1GHz',
@@ -50,7 +50,7 @@ system.clk_domain = SrcClockDomain(clock = '1GHz',
 system.cpu_clk_domain = SrcClockDomain(clock = '2GHz',
                                        voltage_domain = system.voltage_domain)
 
-system.toL2Bus = CoherentBus(clk_domain = system.cpu_clk_domain, width=16)
+system.toL2Bus = CoherentXBar(clk_domain = system.cpu_clk_domain, width=16)
 system.l2c = L2Cache(clk_domain = system.cpu_clk_domain, size='64kB', assoc=8)
 system.l2c.cpu_side = system.toL2Bus.master
 
index 292c7a42dd7f55784a2baef8967cc4f8f52d608f..3fea4ed7117861379fd8b502044c13547c54e060 100644 (file)
@@ -38,7 +38,7 @@ import ruby_config
 ruby_memory = ruby_config.generate("TwoLevel_SplitL1UnifiedL2.rb", nb_cores)
 
 # system simulated
-system = System(cpu = cpus, physmem = ruby_memory, membus = CoherentBus(),
+system = System(cpu = cpus, physmem = ruby_memory, membus = CoherentXBar(),
                 mem_mode = "timing",
                 clk_domain = SrcClockDomain(clock = '1GHz'))
 
index d1b471bacf778faaea8699fba467caf1f26529cf..68a07e702535b7c83d30d43d1882d1c78d5dcd39 100644 (file)
@@ -39,7 +39,7 @@ cpu = DerivO3CPU(cpu_id=0)
 
 system = System(cpu = cpu,
                 physmem = ruby_memory,
-                membus = CoherentBus(),
+                membus = CoherentXBar(),
                 mem_mode = "timing",
                 clk_domain = SrcClockDomain(clock = '1GHz'))
 
index 9feccb12c142d20bebf27fe8d006a1f23f146c63..321cb977fbcf1bce468c09412153fee53d1f5170 100644 (file)
@@ -38,7 +38,7 @@ import ruby_config
 ruby_memory = ruby_config.generate("TwoLevel_SplitL1UnifiedL2.rb", nb_cores)
 
 # system simulated
-system = System(cpu = cpus, physmem = ruby_memory, membus = CoherentBus(),
+system = System(cpu = cpus, physmem = ruby_memory, membus = CoherentXBar(),
                 clk_domain = SrcClockDomain(clock = '1GHz'))
 
 # Create a seperate clock domain for components that should run at
index c98b9265036b60e3e6aeb9557f6892054181a0f2..d170ac0774d406e831b34f0859a45059c6a3875e 100644 (file)
@@ -49,7 +49,7 @@ cpu = TrafficGen(config_file = "tests/quick/se/70.tgen/tgen-dram-ctrl.cfg")
 
 # system simulated
 system = System(cpu = cpu, physmem = DDR3_1600_x64(),
-                membus = NoncoherentBus(width = 16),
+                membus = NoncoherentXBar(width = 16),
                 clk_domain = SrcClockDomain(clock = '1GHz',
                                             voltage_domain =
                                             VoltageDomain()))
index 7fdeb9c1229d2386bd4b28d3de5b05d50d7aa0e8..1e07efe2c7a6857b667af91b40386d31e6ebf0c4 100644 (file)
@@ -49,7 +49,7 @@ cpu = TrafficGen(config_file = "tests/quick/se/70.tgen/tgen-simple-mem.cfg")
 
 # system simulated
 system = System(cpu = cpu, physmem = SimpleMemory(),
-                membus = NoncoherentBus(width = 16),
+                membus = NoncoherentXBar(width = 16),
                 clk_domain = SrcClockDomain(clock = '1GHz',
                                             voltage_domain =
                                             VoltageDomain()))