ruby: garnet2.0
authorTushar Krishna <tushar@ece.gatech.edu>
Thu, 6 Oct 2016 18:35:22 +0000 (14:35 -0400)
committerTushar Krishna <tushar@ece.gatech.edu>
Thu, 6 Oct 2016 18:35:22 +0000 (14:35 -0400)
Revamped version of garnet with more optimized single-cycle routers,
more configurability, and cleaner code.

44 files changed:
configs/network/Network.py
configs/topologies/Crossbar.py
configs/topologies/MeshDirCorners_XY.py
configs/topologies/Mesh_XY.py
configs/topologies/Mesh_westfirst.py
configs/topologies/Pt2Pt.py
src/base/statistics.cc
src/mem/ruby/network/BasicRouter.py
src/mem/ruby/network/garnet2.0/CommonTypes.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/Credit.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/Credit.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/CreditLink.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/CrossbarSwitch.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/CrossbarSwitch.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/GarnetLink.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/GarnetLink.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/GarnetLink.py [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/GarnetNetwork.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/GarnetNetwork.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/GarnetNetwork.py [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/InputUnit.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/InputUnit.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/NetworkInterface.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/NetworkInterface.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/NetworkLink.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/NetworkLink.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/OutVcState.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/OutVcState.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/OutputUnit.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/OutputUnit.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/README.txt [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/Router.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/Router.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/RoutingUnit.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/RoutingUnit.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/SConscript [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/SwitchAllocator.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/SwitchAllocator.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/VirtualChannel.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/VirtualChannel.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/flit.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/flit.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/flitBuffer.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/flitBuffer.hh [new file with mode: 0644]

index 871682ff15c8e44f4b4f697c9eb308faa4914985..3c15a4f79acdf961b3b3b4d474190fcea7151ea1 100644 (file)
@@ -38,25 +38,44 @@ def define_options(parser):
 
     parser.add_option("--topology", type="string", default="Crossbar",
                       help="check configs/topologies for complete set")
-    parser.add_option("--mesh-rows", type="int", default=1,
+    parser.add_option("--mesh-rows", type="int", default=0,
                       help="the number of rows in the mesh topology")
-    parser.add_option("--garnet-network", type="choice",
-                      choices=['fixed', 'flexible'], help="'fixed'|'flexible'")
-    parser.add_option("--network-fault-model", action="store_true", default=False,
-                      help="enable network fault model: see src/mem/ruby/network/fault_model/")
+    parser.add_option("--network", type="choice", default="simple",
+                      choices=['simple', 'garnet2.0'],
+                      help="'simple'|'garnet2.0'")
+    parser.add_option("--router-latency", action="store", type="int",
+                      default=1,
+                      help="""number of pipeline stages in the garnet router.
+                            Has to be >= 1.
+                            Can be over-ridden on a per router basis
+                            in the topology file.""")
+    parser.add_option("--link-latency", action="store", type="int", default=1,
+                      help="""latency of each link the simple/garnet networks.
+                            Has to be >= 1.
+                            Can be over-ridden on a per link basis
+                            in the topology file.""")
+    parser.add_option("--link-width-bits", action="store", type="int",
+                      default=128,
+                      help="width in bits for all links inside garnet.")
+    parser.add_option("--vcs-per-vnet", action="store", type="int", default=4,
+                      help="""number of virtual channels per virtual network
+                            inside garnet network.""")
+    parser.add_option("--routing-algorithm", action="store", type="int",
+                      default=0,
+                      help="""routing algorithm in network.
+                            0: weight-based table
+                            1: XY (for Mesh. see garnet2.0/RoutingUnit.cc)
+                            2: Custom (see garnet2.0/RoutingUnit.cc""")
+    parser.add_option("--network-fault-model", action="store_true",
+                      default=False,
+                      help="""enable network fault model:
+                            see src/mem/ruby/network/fault_model/""")
 
 
 def create_network(options, ruby):
 
     # Set the network classes based on the command line options
-    if options.garnet_network == "fixed":
-        NetworkClass = GarnetNetwork_d
-        IntLinkClass = GarnetIntLink_d
-        ExtLinkClass = GarnetExtLink_d
-        RouterClass = GarnetRouter_d
-        InterfaceClass = GarnetNetworkInterface_d
-
-    elif options.garnet_network == "flexible":
+    if options.network == "garnet2.0":
         NetworkClass = GarnetNetwork
         IntLinkClass = GarnetIntLink
         ExtLinkClass = GarnetExtLink
@@ -79,7 +98,13 @@ def create_network(options, ruby):
 
 def init_network(options, network, InterfaceClass):
 
-    if options.garnet_network is None:
+    if options.network == "garnet2.0":
+        network.num_rows = options.mesh_rows
+        network.vcs_per_vnet = options.vcs_per_vnet
+        network.ni_flit_size = options.link_width_bits / 8
+        network.routing_algorithm = options.routing_algorithm
+
+    if options.network == "simple":
         network.setup_buffers()
 
     if InterfaceClass != None:
@@ -88,6 +113,6 @@ def init_network(options, network, InterfaceClass):
         network.netifs = netifs
 
     if options.network_fault_model:
-        assert(options.garnet_network == "fixed")
+        assert(options.network == "garnet2.0")
         network.enable_fault_model = True
         network.fault_model = FaultModel()
index 35d20de34109c74bfdc3975c92cdb4274e4e80e3..447b1c5977fef8cba78afad1d550119d4cb62a0e 100644 (file)
@@ -35,6 +35,12 @@ class Crossbar(SimpleTopology):
     description='Crossbar'
 
     def makeTopology(self, options, network, IntLink, ExtLink, Router):
+
+        # default values for link latency and router latency.
+        # Can be over-ridden on a per link/router basis
+        link_latency = options.link_latency # used by simple and garnet
+        router_latency = options.router_latency # only used by garnet
+
         # Create an individual router for each controller plus one more for
         # the centralized crossbar.  The large numbers of routers are needed
         # because external links do not model outgoing bandwidth in the
@@ -45,7 +51,8 @@ class Crossbar(SimpleTopology):
         xbar = routers[len(self.nodes)] # the crossbar router is the last router created
         network.routers = routers
 
-        ext_links = [ExtLink(link_id=i, ext_node=n, int_node=routers[i])
+        ext_links = [ExtLink(link_id=i, ext_node=n, int_node=routers[i],
+                             latency = link_latency)
                         for (i, n) in enumerate(self.nodes)]
         network.ext_links = ext_links
 
@@ -55,13 +62,15 @@ class Crossbar(SimpleTopology):
         for i in range(len(self.nodes)):
             int_links.append(IntLink(link_id=(link_count+i),
                                      src_node=routers[i],
-                                     dst_node=xbar))
+                                     dst_node=xbar,
+                                     latency = link_latency))
 
         link_count += len(self.nodes)
 
         for i in range(len(self.nodes)):
             int_links.append(IntLink(link_id=(link_count+i),
                                      src_node=xbar,
-                                     dst_node=routers[i]))
+                                     dst_node=routers[i],
+                                     latency = link_latency))
 
         network.int_links = int_links
index 47eb48086548c07aeaad91d6e09f354b3a54a490..46f3c6fdd1b7021e432c0b9f1df638ec17e754a2 100644 (file)
@@ -47,6 +47,12 @@ class MeshDirCorners_XY(SimpleTopology):
         num_routers = options.num_cpus
         num_rows = options.mesh_rows
 
+        # default values for link latency and router latency.
+        # Can be over-ridden on a per link/router basis
+        link_latency = options.link_latency # used by simple and garnet
+        router_latency = options.router_latency # only used by garnet
+
+
         # First determine which nodes are cache cntrls vs. dirs vs. dma
         cache_nodes = []
         dir_nodes = []
@@ -64,7 +70,7 @@ class MeshDirCorners_XY(SimpleTopology):
         # and evenly divisible.  Also the number of caches must be a
         # multiple of the number of routers and the number of directories
         # must be four.
-        assert(num_rows <= num_routers)
+        assert(num_rows > 0 and num_rows <= num_routers)
         num_columns = int(num_routers / num_rows)
         assert(num_columns * num_rows == num_routers)
         caches_per_router, remainder = divmod(len(cache_nodes), num_routers)
@@ -72,7 +78,8 @@ class MeshDirCorners_XY(SimpleTopology):
         assert(len(dir_nodes) == 4)
 
         # Create the routers in the mesh
-        routers = [Router(router_id=i) for i in range(num_routers)]
+        routers = [Router(router_id=i, latency = router_latency) \
+            for i in range(num_routers)]
         network.routers = routers
 
         # link counter to set unique link ids
@@ -84,28 +91,34 @@ class MeshDirCorners_XY(SimpleTopology):
             cntrl_level, router_id = divmod(i, num_routers)
             assert(cntrl_level < caches_per_router)
             ext_links.append(ExtLink(link_id=link_count, ext_node=n,
-                                    int_node=routers[router_id]))
+                                    int_node=routers[router_id],
+                                    latency = link_latency))
             link_count += 1
 
         # Connect the dir nodes to the corners.
         ext_links.append(ExtLink(link_id=link_count, ext_node=dir_nodes[0],
-                                int_node=routers[0]))
+                                int_node=routers[0],
+                                latency = link_latency))
         link_count += 1
         ext_links.append(ExtLink(link_id=link_count, ext_node=dir_nodes[1],
-                                int_node=routers[num_columns - 1]))
+                                int_node=routers[num_columns - 1],
+                                latency = link_latency))
         link_count += 1
         ext_links.append(ExtLink(link_id=link_count, ext_node=dir_nodes[2],
-                                int_node=routers[num_routers - num_columns]))
+                                int_node=routers[num_routers - num_columns],
+                                latency = link_latency))
         link_count += 1
         ext_links.append(ExtLink(link_id=link_count, ext_node=dir_nodes[3],
-                                int_node=routers[num_routers - 1]))
+                                int_node=routers[num_routers - 1],
+                                latency = link_latency))
         link_count += 1
 
         # Connect the dma nodes to router 0.  These should only be DMA nodes.
         for (i, node) in enumerate(dma_nodes):
             assert(node.type == 'DMA_Controller')
             ext_links.append(ExtLink(link_id=link_count, ext_node=node,
-                                     int_node=routers[0]))
+                                     int_node=routers[0],
+                                     latency = link_latency))
 
         network.ext_links = ext_links
 
@@ -121,6 +134,9 @@ class MeshDirCorners_XY(SimpleTopology):
                     int_links.append(IntLink(link_id=link_count,
                                              src_node=routers[east_out],
                                              dst_node=routers[west_in],
+                                             src_outport="East",
+                                             dst_inport="West",
+                                             latency = link_latency,
                                              weight=1))
                     link_count += 1
 
@@ -133,6 +149,9 @@ class MeshDirCorners_XY(SimpleTopology):
                     int_links.append(IntLink(link_id=link_count,
                                              src_node=routers[west_out],
                                              dst_node=routers[east_in],
+                                             src_outport="West",
+                                             dst_inport="East",
+                                             latency = link_latency,
                                              weight=1))
                     link_count += 1
 
@@ -145,6 +164,9 @@ class MeshDirCorners_XY(SimpleTopology):
                     int_links.append(IntLink(link_id=link_count,
                                              src_node=routers[north_out],
                                              dst_node=routers[south_in],
+                                             src_outport="North",
+                                             dst_inport="South",
+                                             latency = link_latency,
                                              weight=2))
                     link_count += 1
 
@@ -157,6 +179,9 @@ class MeshDirCorners_XY(SimpleTopology):
                     int_links.append(IntLink(link_id=link_count,
                                              src_node=routers[south_out],
                                              dst_node=routers[north_in],
+                                             src_outport="South",
+                                             dst_inport="North",
+                                             latency = link_latency,
                                              weight=2))
                     link_count += 1
 
index 134a5c07dfc36419512c5501db536260764f37c9..652ac16d8efccf5ba4cafbf00a55f3637936c1f2 100644 (file)
@@ -53,15 +53,22 @@ class Mesh_XY(SimpleTopology):
         num_routers = options.num_cpus
         num_rows = options.mesh_rows
 
+        # default values for link latency and router latency.
+        # Can be over-ridden on a per link/router basis
+        link_latency = options.link_latency # used by simple and garnet
+        router_latency = options.router_latency # only used by garnet
+
+
         # There must be an evenly divisible number of cntrls to routers
         # Also, obviously the number or rows must be <= the number of routers
         cntrls_per_router, remainder = divmod(len(nodes), num_routers)
-        assert(num_rows <= num_routers)
+        assert(num_rows > 0 and num_rows <= num_routers)
         num_columns = int(num_routers / num_rows)
         assert(num_columns * num_rows == num_routers)
 
         # Create the routers in the mesh
-        routers = [Router(router_id=i) for i in range(num_routers)]
+        routers = [Router(router_id=i, latency = router_latency) \
+            for i in range(num_routers)]
         network.routers = routers
 
         # link counter to set unique link ids
@@ -83,7 +90,8 @@ class Mesh_XY(SimpleTopology):
             cntrl_level, router_id = divmod(i, num_routers)
             assert(cntrl_level < cntrls_per_router)
             ext_links.append(ExtLink(link_id=link_count, ext_node=n,
-                                    int_node=routers[router_id]))
+                                    int_node=routers[router_id],
+                                    latency = link_latency))
             link_count += 1
 
         # Connect the remainding nodes to router 0.  These should only be
@@ -92,7 +100,8 @@ class Mesh_XY(SimpleTopology):
             assert(node.type == 'DMA_Controller')
             assert(i < remainder)
             ext_links.append(ExtLink(link_id=link_count, ext_node=node,
-                                    int_node=routers[0]))
+                                    int_node=routers[0],
+                                    latency = link_latency))
             link_count += 1
 
         network.ext_links = ext_links
@@ -111,6 +120,7 @@ class Mesh_XY(SimpleTopology):
                                              dst_node=routers[west_in],
                                              src_outport="East",
                                              dst_inport="West",
+                                             latency = link_latency,
                                              weight=1))
                     link_count += 1
 
@@ -125,6 +135,7 @@ class Mesh_XY(SimpleTopology):
                                              dst_node=routers[east_in],
                                              src_outport="West",
                                              dst_inport="East",
+                                             latency = link_latency,
                                              weight=1))
                     link_count += 1
 
@@ -139,6 +150,7 @@ class Mesh_XY(SimpleTopology):
                                              dst_node=routers[south_in],
                                              src_outport="North",
                                              dst_inport="South",
+                                             latency = link_latency,
                                              weight=2))
                     link_count += 1
 
@@ -153,6 +165,7 @@ class Mesh_XY(SimpleTopology):
                                              dst_node=routers[north_in],
                                              src_outport="South",
                                              dst_inport="North",
+                                             latency = link_latency,
                                              weight=2))
                     link_count += 1
 
index 3af894f9306ba3dde02042e10181f271960c26aa..6139f674270ea832af66999400a5bb0b950665fe 100644 (file)
@@ -58,15 +58,21 @@ class Mesh_westfirst(SimpleTopology):
         num_routers = options.num_cpus
         num_rows = options.mesh_rows
 
+        # default values for link latency and router latency.
+        # Can be over-ridden on a per link/router basis
+        link_latency = options.link_latency # used by simple and garnet
+        router_latency = options.router_latency # only used by garnet
+
         # There must be an evenly divisible number of cntrls to routers
         # Also, obviously the number or rows must be <= the number of routers
         cntrls_per_router, remainder = divmod(len(nodes), num_routers)
-        assert(num_rows <= num_routers)
+        assert(num_rows > 0 and num_rows <= num_routers)
         num_columns = int(num_routers / num_rows)
         assert(num_columns * num_rows == num_routers)
 
         # Create the routers in the mesh
-        routers = [Router(router_id=i) for i in range(num_routers)]
+        routers = [Router(router_id=i, latency=router_latency) \
+            for i in range(num_routers)]
         network.routers = routers
 
         # link counter to set unique link ids
@@ -88,7 +94,8 @@ class Mesh_westfirst(SimpleTopology):
             cntrl_level, router_id = divmod(i, num_routers)
             assert(cntrl_level < cntrls_per_router)
             ext_links.append(ExtLink(link_id=link_count, ext_node=n,
-                                    int_node=routers[router_id]))
+                                    int_node=routers[router_id],
+                                    latency = link_latency))
             link_count += 1
 
         # Connect the remainding nodes to router 0.  These should only be
@@ -97,7 +104,8 @@ class Mesh_westfirst(SimpleTopology):
             assert(node.type == 'DMA_Controller')
             assert(i < remainder)
             ext_links.append(ExtLink(link_id=link_count, ext_node=node,
-                                    int_node=routers[0]))
+                                    int_node=routers[0],
+                                    latency = link_latency))
             link_count += 1
 
         network.ext_links = ext_links
@@ -114,6 +122,7 @@ class Mesh_westfirst(SimpleTopology):
                     int_links.append(IntLink(link_id=link_count,
                                              src_node=routers[east_out],
                                              dst_node=routers[west_in],
+                                             latency = link_latency,
                                              weight=2))
                     link_count += 1
 
@@ -126,6 +135,7 @@ class Mesh_westfirst(SimpleTopology):
                     int_links.append(IntLink(link_id=link_count,
                                              src_node=routers[west_out],
                                              dst_node=routers[east_in],
+                                             latency = link_latency,
                                              weight=1))
                     link_count += 1
 
@@ -139,6 +149,7 @@ class Mesh_westfirst(SimpleTopology):
                     int_links.append(IntLink(link_id=link_count,
                                              src_node=routers[north_out],
                                              dst_node=routers[south_in],
+                                             latency = link_latency,
                                              weight=2))
                     link_count += 1
 
@@ -151,6 +162,7 @@ class Mesh_westfirst(SimpleTopology):
                     int_links.append(IntLink(link_id=link_count,
                                              src_node=routers[south_out],
                                              dst_node=routers[north_in],
+                                             latency = link_latency,
                                              weight=2))
                     link_count += 1
 
index 006d00c2fcd1fedd3f11d1027deab038ca372710..6cbf5ad853a8b1df292a857b8e473bac093fbcdd 100644 (file)
@@ -42,11 +42,22 @@ class Pt2Pt(SimpleTopology):
     def makeTopology(self, options, network, IntLink, ExtLink, Router):
         nodes = self.nodes
 
-        # Create an individual router for each controller, and connect all to all.
-        routers = [Router(router_id=i) for i in range(len(nodes))]
+        # default values for link latency and router latency.
+        # Can be over-ridden on a per link/router basis
+        link_latency = options.link_latency # used by simple and garnet
+        router_latency = options.router_latency # only used by garnet
+
+        # Create an individual router for each controller,
+        # and connect all to all.
+        # Since this is a high-radix router, router_latency should
+        # accordingly be set to a higher value than the default
+        # (which is 1 for mesh routers)
+        routers = [Router(router_id=i, latency = router_latency) \
+            for i in range(len(nodes))]
         network.routers = routers
 
-        ext_links = [ExtLink(link_id=i, ext_node=n, int_node=routers[i])
+        ext_links = [ExtLink(link_id=i, ext_node=n, int_node=routers[i],
+                     latency = link_latency)
                     for (i, n) in enumerate(nodes)]
         network.ext_links = ext_links
 
@@ -58,6 +69,7 @@ class Pt2Pt(SimpleTopology):
                     link_count += 1
                     int_links.append(IntLink(link_id=link_count,
                                              src_node=routers[i],
-                                             dst_node=routers[j]))
+                                             dst_node=routers[j],
+                                             latency = link_latency))
 
         network.int_links = int_links
index b32dafb8c43fe3b859deb886cbd8c9cd29a6f4d1..4c14bc52229e24beeab7e864e6d8347e3aa585bc 100644 (file)
@@ -180,8 +180,8 @@ Info::setName(const string &name)
     bool result = p.second;
 
     if (!result) {
-        // using other->name instead of just name to avoid a compiler
-        // warning.  They should be the same.
+      // using other->name instead of just name to avoid a compiler
+      // warning.  They should be the same.
         panic("same statistic name used twice! name=%s\n", other->name);
     }
 
index 28fcdc47eeef8f1e91cb960173436c4510cf09dd..68a7b1d8b90fd41cea429d9a9bf2d5d5c138a4b1 100644 (file)
@@ -34,4 +34,6 @@ class BasicRouter(ClockedObject):
     type = 'BasicRouter'
     cxx_header = "mem/ruby/network/BasicRouter.hh"
     router_id = Param.Int("ID in relation to other routers")
+
+    # only used by garnet
     latency   = Param.Cycles(1, "number of cycles inside router")
diff --git a/src/mem/ruby/network/garnet2.0/CommonTypes.hh b/src/mem/ruby/network/garnet2.0/CommonTypes.hh
new file mode 100644 (file)
index 0000000..63fc464
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_COMMONTYPES_HH__
+#define __MEM_RUBY_NETWORK_GARNET_COMMONTYPES_HH__
+
+#include "mem/ruby/common/NetDest.hh"
+
+// All common enums and typedefs go here
+
+enum flit_type {HEAD_, BODY_, TAIL_, HEAD_TAIL_, NUM_FLIT_TYPE_};
+enum VC_state_type {IDLE_, VC_AB_, ACTIVE_, NUM_VC_STATE_TYPE_};
+enum VNET_type {CTRL_VNET_, DATA_VNET_, NULL_VNET_, NUM_VNET_TYPE_};
+enum flit_stage {I_, VA_, SA_, ST_, LT_, NUM_FLIT_STAGE_};
+enum link_type { EXT_IN_, EXT_OUT_, INT_, NUM_LINK_TYPES_ };
+enum RoutingAlgorithm { TABLE_ = 0, XY_ = 1, CUSTOM_ = 2,
+                        NUM_ROUTING_ALGORITHM_};
+
+struct RouteInfo
+{
+    // destination format for table-based routing
+    int vnet;
+    NetDest net_dest;
+
+    // src and dest format for topology-specific routing
+    int src_ni;
+    int src_router;
+    int dest_ni;
+    int dest_router;
+    int hops_traversed;
+};
+
+#define INFINITE_ 10000
+
+#endif // __MEM_RUBY_NETWORK_GARNET_COMMONTYPES_HH__
diff --git a/src/mem/ruby/network/garnet2.0/Credit.cc b/src/mem/ruby/network/garnet2.0/Credit.cc
new file mode 100644 (file)
index 0000000..6bc7ca2
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/Credit.hh"
+
+// Credit Signal for buffers inside VC
+// Carries m_vc (inherits from flit.hh)
+// and m_is_free_signal (whether VC is free or not)
+
+Credit::Credit(int vc, bool is_free_signal, Cycles curTime)
+{
+    m_id = 0;
+    m_vc = vc;
+    m_is_free_signal = is_free_signal;
+    m_time = curTime;
+}
diff --git a/src/mem/ruby/network/garnet2.0/Credit.hh b/src/mem/ruby/network/garnet2.0/Credit.hh
new file mode 100644 (file)
index 0000000..c2984e9
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_CREDIT_HH__
+#define __MEM_RUBY_NETWORK_GARNET_CREDIT_HH__
+
+#include <cassert>
+#include <iostream>
+
+#include "base/types.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/flit.hh"
+
+// Credit Signal for buffers inside VC
+// Carries m_vc (inherits from flit.hh)
+// and m_is_free_signal (whether VC is free or not)
+
+class Credit : public flit
+{
+  public:
+    Credit() {};
+    Credit(int vc, bool is_free_signal, Cycles curTime);
+
+    bool is_free_signal() { return m_is_free_signal; }
+
+  private:
+    bool m_is_free_signal;
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_CREDIT_HH__
diff --git a/src/mem/ruby/network/garnet2.0/CreditLink.hh b/src/mem/ruby/network/garnet2.0/CreditLink.hh
new file mode 100644 (file)
index 0000000..207fb86
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_CREDIT_LINK_HH__
+#define __MEM_RUBY_NETWORK_GARNET_CREDIT_LINK_HH__
+
+#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
+#include "params/CreditLink.hh"
+
+class CreditLink : public NetworkLink
+{
+  public:
+    typedef CreditLinkParams Params;
+    CreditLink(const Params *p) : NetworkLink(p) {}
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_CREDIT_LINK_HH__
diff --git a/src/mem/ruby/network/garnet2.0/CrossbarSwitch.cc b/src/mem/ruby/network/garnet2.0/CrossbarSwitch.cc
new file mode 100644 (file)
index 0000000..340f56d
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/CrossbarSwitch.hh"
+
+#include "base/stl_helpers.hh"
+#include "debug/RubyNetwork.hh"
+#include "mem/ruby/network/garnet2.0/OutputUnit.hh"
+#include "mem/ruby/network/garnet2.0/Router.hh"
+
+using m5::stl_helpers::deletePointers;
+
+CrossbarSwitch::CrossbarSwitch(Router *router)
+    : Consumer(router)
+{
+    m_router = router;
+    m_num_vcs = m_router->get_num_vcs();
+    m_crossbar_activity = 0;
+}
+
+CrossbarSwitch::~CrossbarSwitch()
+{
+    deletePointers(m_switch_buffer);
+}
+
+void
+CrossbarSwitch::init()
+{
+    m_output_unit = m_router->get_outputUnit_ref();
+
+    m_num_inports = m_router->get_num_inports();
+    m_switch_buffer.resize(m_num_inports);
+    for (int i = 0; i < m_num_inports; i++) {
+        m_switch_buffer[i] = new flitBuffer();
+    }
+}
+
+/*
+ * The wakeup function of the CrossbarSwitch loops through all input ports,
+ * and sends the winning flit (from SA) out of its output port on to the
+ * output link. The output link is scheduled for wakeup in the next cycle.
+ */
+
+void
+CrossbarSwitch::wakeup()
+{
+    DPRINTF(RubyNetwork, "CrossbarSwitch at Router %d woke up "
+            "at time: %lld\n",
+            m_router->get_id(), m_router->curCycle());
+
+    for (int inport = 0; inport < m_num_inports; inport++) {
+        if (!m_switch_buffer[inport]->isReady(m_router->curCycle()))
+            continue;
+
+        flit *t_flit = m_switch_buffer[inport]->peekTopFlit();
+        if (t_flit->is_stage(ST_, m_router->curCycle())) {
+            int outport = t_flit->get_outport();
+
+            // flit performs LT_ in the next cycle
+            t_flit->advance_stage(LT_, m_router->curCycle() + Cycles(1));
+            t_flit->set_time(m_router->curCycle() + Cycles(1));
+
+            // This will take care of waking up the Network Link
+            // in the next cycle
+            m_output_unit[outport]->insert_flit(t_flit);
+            m_switch_buffer[inport]->getTopFlit();
+            m_crossbar_activity++;
+        }
+    }
+}
+
+uint32_t
+CrossbarSwitch::functionalWrite(Packet *pkt)
+{
+   uint32_t num_functional_writes = 0;
+
+   for (uint32_t i = 0; i < m_switch_buffer.size(); ++i) {
+       num_functional_writes += m_switch_buffer[i]->functionalWrite(pkt);
+   }
+
+   return num_functional_writes;
+}
diff --git a/src/mem/ruby/network/garnet2.0/CrossbarSwitch.hh b/src/mem/ruby/network/garnet2.0/CrossbarSwitch.hh
new file mode 100644 (file)
index 0000000..7aaeabf
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_CROSSBAR_SWITCH_HH__
+#define __MEM_RUBY_NETWORK_GARNET_CROSSBAR_SWITCH_HH__
+
+#include <iostream>
+#include <vector>
+
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/flitBuffer.hh"
+
+class Router;
+class OutputUnit;
+
+class CrossbarSwitch : public Consumer
+{
+  public:
+    CrossbarSwitch(Router *router);
+    ~CrossbarSwitch();
+    void wakeup();
+    void init();
+    void print(std::ostream& out) const {};
+
+    inline void update_sw_winner(int inport, flit *t_flit)
+    { m_switch_buffer[inport]->insert(t_flit); }
+
+    inline double get_crossbar_activity() { return m_crossbar_activity; }
+
+    uint32_t functionalWrite(Packet *pkt);
+
+  private:
+    int m_num_vcs;
+    int m_num_inports;
+    double m_crossbar_activity;
+    Router *m_router;
+    std::vector<flitBuffer *> m_switch_buffer;
+    std::vector<OutputUnit *> m_output_unit;
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_CROSSBAR_SWITCH_HH__
diff --git a/src/mem/ruby/network/garnet2.0/GarnetLink.cc b/src/mem/ruby/network/garnet2.0/GarnetLink.cc
new file mode 100644 (file)
index 0000000..ac5386a
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/GarnetLink.hh"
+
+#include "mem/ruby/network/garnet2.0/CreditLink.hh"
+#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
+
+GarnetIntLink::GarnetIntLink(const Params *p)
+    : BasicLink(p)
+{
+    // Uni-directional
+
+    m_network_link = p->network_link;
+    m_credit_link = p->credit_link;
+}
+
+void
+GarnetIntLink::init()
+{
+}
+
+void
+GarnetIntLink::print(std::ostream& out) const
+{
+    out << name();
+}
+
+GarnetIntLink *
+GarnetIntLinkParams::create()
+{
+    return new GarnetIntLink(this);
+}
+
+GarnetExtLink::GarnetExtLink(const Params *p)
+    : BasicLink(p)
+{
+    // Bi-directional
+
+    // In
+    m_network_links[0] = p->network_links[0];
+    m_credit_links[0] = p->credit_links[0];
+
+    // Out
+    m_network_links[1] = p->network_links[1];
+    m_credit_links[1] = p->credit_links[1];
+}
+
+void
+GarnetExtLink::init()
+{
+}
+
+void
+GarnetExtLink::print(std::ostream& out) const
+{
+    out << name();
+}
+
+GarnetExtLink *
+GarnetExtLinkParams::create()
+{
+    return new GarnetExtLink(this);
+}
diff --git a/src/mem/ruby/network/garnet2.0/GarnetLink.hh b/src/mem/ruby/network/garnet2.0/GarnetLink.hh
new file mode 100644 (file)
index 0000000..d7c5829
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_LINK_HH__
+#define __MEM_RUBY_NETWORK_GARNET_LINK_HH__
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "mem/ruby/network/BasicLink.hh"
+#include "mem/ruby/network/garnet2.0/CreditLink.hh"
+#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
+#include "params/GarnetExtLink.hh"
+#include "params/GarnetIntLink.hh"
+
+class GarnetIntLink : public BasicLink
+{
+  public:
+    typedef GarnetIntLinkParams Params;
+    GarnetIntLink(const Params *p);
+
+    void init();
+
+    void print(std::ostream& out) const;
+
+    friend class GarnetNetwork;
+
+  protected:
+    NetworkLink* m_network_link;
+    CreditLink* m_credit_link;
+};
+
+inline std::ostream&
+operator<<(std::ostream& out, const GarnetIntLink& obj)
+{
+    obj.print(out);
+    out << std::flush;
+    return out;
+}
+
+class GarnetExtLink : public BasicLink
+{
+  public:
+    typedef GarnetExtLinkParams Params;
+    GarnetExtLink(const Params *p);
+
+    void init();
+
+    void print(std::ostream& out) const;
+
+    friend class GarnetNetwork;
+
+  protected:
+    NetworkLink* m_network_links[2];
+    CreditLink* m_credit_links[2];
+};
+
+inline std::ostream&
+operator<<(std::ostream& out, const GarnetExtLink& obj)
+{
+    obj.print(out);
+    out << std::flush;
+    return out;
+}
+
+#endif // __MEM_RUBY_NETWORK_GARNET_LINK_HH__
diff --git a/src/mem/ruby/network/garnet2.0/GarnetLink.py b/src/mem/ruby/network/garnet2.0/GarnetLink.py
new file mode 100644 (file)
index 0000000..fc5632d
--- /dev/null
@@ -0,0 +1,79 @@
+# Copyright (c) 2008 Princeton University
+# Copyright (c) 2009 Advanced Micro Devices, Inc.
+# 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: Steve Reinhardt
+#          Brad Beckmann
+
+from m5.params import *
+from m5.proxy import *
+from ClockedObject import ClockedObject
+from BasicLink import BasicIntLink, BasicExtLink
+
+class NetworkLink(ClockedObject):
+    type = 'NetworkLink'
+    cxx_header = "mem/ruby/network/garnet2.0/NetworkLink.hh"
+    link_id = Param.Int(Parent.link_id, "link id")
+    link_latency = Param.Cycles(Parent.latency, "link latency")
+    vcs_per_vnet = Param.Int(Parent.vcs_per_vnet,
+                              "virtual channels per virtual network")
+    virt_nets = Param.Int(Parent.number_of_virtual_networks,
+                          "number of virtual networks")
+
+class CreditLink(NetworkLink):
+    type = 'CreditLink'
+    cxx_header = "mem/ruby/network/garnet2.0/CreditLink.hh"
+
+# Interior fixed pipeline links between routers
+class GarnetIntLink(BasicIntLink):
+    type = 'GarnetIntLink'
+    cxx_header = "mem/ruby/network/garnet2.0/GarnetLink.hh"
+    # The internal link includes one forward link (for flit)
+    # and one backward flow-control link (for credit)
+    network_link = Param.NetworkLink(NetworkLink(), "forward link")
+    credit_link  = Param.CreditLink(CreditLink(), "backward flow-control link")
+
+# Exterior fixed pipeline links between a router and a controller
+class GarnetExtLink(BasicExtLink):
+    type = 'GarnetExtLink'
+    cxx_header = "mem/ruby/network/garnet2.0/GarnetLink.hh"
+    # The external link is bi-directional.
+    # It includes two forward links (for flits)
+    # and two backward flow-control links (for credits),
+    # one per direction
+    _nls = []
+    # In uni-directional link
+    _nls.append(NetworkLink());
+    # Out uni-directional link
+    _nls.append(NetworkLink());
+    network_links = VectorParam.NetworkLink(_nls, "forward links")
+
+    _cls = []
+    # In uni-directional link
+    _cls.append(CreditLink());
+    # Out uni-directional link
+    _cls.append(CreditLink());
+    credit_links = VectorParam.CreditLink(_cls, "backward flow-control links")
diff --git a/src/mem/ruby/network/garnet2.0/GarnetNetwork.cc b/src/mem/ruby/network/garnet2.0/GarnetNetwork.cc
new file mode 100644 (file)
index 0000000..5fa7644
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
+
+#include <cassert>
+
+#include "base/cast.hh"
+#include "base/stl_helpers.hh"
+#include "mem/ruby/common/NetDest.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/CreditLink.hh"
+#include "mem/ruby/network/garnet2.0/GarnetLink.hh"
+#include "mem/ruby/network/garnet2.0/NetworkInterface.hh"
+#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
+#include "mem/ruby/network/garnet2.0/Router.hh"
+#include "mem/ruby/system/RubySystem.hh"
+
+using namespace std;
+using m5::stl_helpers::deletePointers;
+
+/*
+ * GarnetNetwork sets up the routers and links and collects stats.
+ * Default parameters (GarnetNetwork.py) can be overwritten from command line
+ * (see configs/network/Network.py)
+ */
+
+GarnetNetwork::GarnetNetwork(const Params *p)
+    : Network(p)
+{
+    m_num_rows = p->num_rows;
+    m_ni_flit_size = p->ni_flit_size;
+    m_vcs_per_vnet = p->vcs_per_vnet;
+    m_buffers_per_data_vc = p->buffers_per_data_vc;
+    m_buffers_per_ctrl_vc = p->buffers_per_ctrl_vc;
+    m_routing_algorithm = p->routing_algorithm;
+
+    m_enable_fault_model = p->enable_fault_model;
+    if (m_enable_fault_model)
+        fault_model = p->fault_model;
+
+    m_vnet_type.resize(m_virtual_networks);
+
+    for (int i = 0 ; i < m_virtual_networks ; i++) {
+        if (m_vnet_type_names[i] == "response")
+            m_vnet_type[i] = DATA_VNET_; // carries data (and ctrl) packets
+        else
+            m_vnet_type[i] = CTRL_VNET_; // carries only ctrl packets
+    }
+
+    // record the routers
+    for (vector<BasicRouter*>::const_iterator i =  p->routers.begin();
+         i != p->routers.end(); ++i) {
+        Router* router = safe_cast<Router*>(*i);
+        m_routers.push_back(router);
+
+        // initialize the router's network pointers
+        router->init_net_ptr(this);
+    }
+
+    // record the network interfaces
+    for (vector<ClockedObject*>::const_iterator i = p->netifs.begin();
+         i != p->netifs.end(); ++i) {
+        NetworkInterface *ni = safe_cast<NetworkInterface *>(*i);
+        m_nis.push_back(ni);
+        ni->init_net_ptr(this);
+    }
+}
+
+void
+GarnetNetwork::init()
+{
+    Network::init();
+
+    for (int i=0; i < m_nodes; i++) {
+        m_nis[i]->addNode(m_toNetQueues[i], m_fromNetQueues[i]);
+    }
+
+    // The topology pointer should have already been initialized in the
+    // parent network constructor
+    assert(m_topology_ptr != NULL);
+    m_topology_ptr->createLinks(this);
+
+    // Initialize topology specific parameters
+    if (getNumRows() > 0) {
+        // Only for Mesh topology
+        // m_num_rows and m_num_cols are only used for
+        // implementing XY or custom routing in RoutingUnit.cc
+        m_num_rows = getNumRows();
+        m_num_cols = m_routers.size() / m_num_rows;
+        assert(m_num_rows * m_num_cols == m_routers.size());
+    } else {
+        m_num_rows = -1;
+        m_num_cols = -1;
+    }
+
+    // FaultModel: declare each router to the fault model
+    if (isFaultModelEnabled()) {
+        for (vector<Router*>::const_iterator i= m_routers.begin();
+             i != m_routers.end(); ++i) {
+            Router* router = safe_cast<Router*>(*i);
+            int router_id M5_VAR_USED =
+                fault_model->declare_router(router->get_num_inports(),
+                                            router->get_num_outports(),
+                                            router->get_vc_per_vnet(),
+                                            getBuffersPerDataVC(),
+                                            getBuffersPerCtrlVC());
+            assert(router_id == router->get_id());
+            router->printAggregateFaultProbability(cout);
+            router->printFaultVector(cout);
+        }
+    }
+}
+
+GarnetNetwork::~GarnetNetwork()
+{
+    deletePointers(m_routers);
+    deletePointers(m_nis);
+    deletePointers(m_networklinks);
+    deletePointers(m_creditlinks);
+}
+
+/*
+ * This function creates a link from the Network Interface (NI)
+ * into the Network.
+ * It creates a Network Link from the NI to a Router and a Credit Link from
+ * the Router to the NI
+*/
+
+void
+GarnetNetwork::makeExtInLink(NodeID src, SwitchID dest, BasicLink* link,
+                            const NetDest& routing_table_entry)
+{
+    assert(src < m_nodes);
+
+    GarnetExtLink* garnet_link = safe_cast<GarnetExtLink*>(link);
+
+    // GarnetExtLink is bi-directional
+    NetworkLink* net_link = garnet_link->m_network_links[LinkDirection_In];
+    net_link->setType(EXT_IN_);
+    CreditLink* credit_link = garnet_link->m_credit_links[LinkDirection_In];
+
+    m_networklinks.push_back(net_link);
+    m_creditlinks.push_back(credit_link);
+
+    PortDirection dst_inport_dirn = "Local";
+    m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
+    m_nis[src]->addOutPort(net_link, credit_link, dest);
+}
+
+/*
+ * This function creates a link from the Network to a NI.
+ * It creates a Network Link from a Router to the NI and
+ * a Credit Link from NI to the Router
+*/
+
+void
+GarnetNetwork::makeExtOutLink(SwitchID src, NodeID dest, BasicLink* link,
+                             const NetDest& routing_table_entry)
+{
+    assert(dest < m_nodes);
+    assert(src < m_routers.size());
+    assert(m_routers[src] != NULL);
+
+    GarnetExtLink* garnet_link = safe_cast<GarnetExtLink*>(link);
+
+    // GarnetExtLink is bi-directional
+    NetworkLink* net_link = garnet_link->m_network_links[LinkDirection_Out];
+    net_link->setType(EXT_OUT_);
+    CreditLink* credit_link = garnet_link->m_credit_links[LinkDirection_Out];
+
+    m_networklinks.push_back(net_link);
+    m_creditlinks.push_back(credit_link);
+
+    PortDirection src_outport_dirn = "Local";
+    m_routers[src]->addOutPort(src_outport_dirn, net_link,
+                               routing_table_entry,
+                               link->m_weight, credit_link);
+    m_nis[dest]->addInPort(net_link, credit_link);
+}
+
+/*
+ * This function creates an internal network link between two routers.
+ * It adds both the network link and an opposite credit link.
+*/
+
+void
+GarnetNetwork::makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
+                                const NetDest& routing_table_entry,
+                                PortDirection src_outport_dirn,
+                                PortDirection dst_inport_dirn)
+{
+    GarnetIntLink* garnet_link = safe_cast<GarnetIntLink*>(link);
+
+    // GarnetIntLink is unidirectional
+    NetworkLink* net_link = garnet_link->m_network_link;
+    net_link->setType(INT_);
+    CreditLink* credit_link = garnet_link->m_credit_link;
+
+    m_networklinks.push_back(net_link);
+    m_creditlinks.push_back(credit_link);
+
+    m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
+    m_routers[src]->addOutPort(src_outport_dirn, net_link,
+                               routing_table_entry,
+                               link->m_weight, credit_link);
+}
+
+// Total routers in the network
+int
+GarnetNetwork::getNumRouters()
+{
+    return m_routers.size();
+}
+
+// Get ID of router connected to a NI.
+int
+GarnetNetwork::get_router_id(int ni)
+{
+    return m_nis[ni]->get_router_id();
+}
+
+void
+GarnetNetwork::regStats()
+{
+    Network::regStats();
+
+    // Packets
+    m_packets_received
+        .init(m_virtual_networks)
+        .name(name() + ".packets_received")
+        .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
+        ;
+
+    m_packets_injected
+        .init(m_virtual_networks)
+        .name(name() + ".packets_injected")
+        .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
+        ;
+
+    m_packet_network_latency
+        .init(m_virtual_networks)
+        .name(name() + ".packet_network_latency")
+        .flags(Stats::oneline)
+        ;
+
+    m_packet_queueing_latency
+        .init(m_virtual_networks)
+        .name(name() + ".packet_queueing_latency")
+        .flags(Stats::oneline)
+        ;
+
+    for (int i = 0; i < m_virtual_networks; i++) {
+        m_packets_received.subname(i, csprintf("vnet-%i", i));
+        m_packets_injected.subname(i, csprintf("vnet-%i", i));
+        m_packet_network_latency.subname(i, csprintf("vnet-%i", i));
+        m_packet_queueing_latency.subname(i, csprintf("vnet-%i", i));
+    }
+
+    m_avg_packet_vnet_latency
+        .name(name() + ".average_packet_vnet_latency")
+        .flags(Stats::oneline);
+    m_avg_packet_vnet_latency =
+        m_packet_network_latency / m_packets_received;
+
+    m_avg_packet_vqueue_latency
+        .name(name() + ".average_packet_vqueue_latency")
+        .flags(Stats::oneline);
+    m_avg_packet_vqueue_latency =
+        m_packet_queueing_latency / m_packets_received;
+
+    m_avg_packet_network_latency
+        .name(name() + ".average_packet_network_latency");
+    m_avg_packet_network_latency =
+        sum(m_packet_network_latency) / sum(m_packets_received);
+
+    m_avg_packet_queueing_latency
+        .name(name() + ".average_packet_queueing_latency");
+    m_avg_packet_queueing_latency
+        = sum(m_packet_queueing_latency) / sum(m_packets_received);
+
+    m_avg_packet_latency
+        .name(name() + ".average_packet_latency");
+    m_avg_packet_latency
+        = m_avg_packet_network_latency + m_avg_packet_queueing_latency;
+
+    // Flits
+    m_flits_received
+        .init(m_virtual_networks)
+        .name(name() + ".flits_received")
+        .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
+        ;
+
+    m_flits_injected
+        .init(m_virtual_networks)
+        .name(name() + ".flits_injected")
+        .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
+        ;
+
+    m_flit_network_latency
+        .init(m_virtual_networks)
+        .name(name() + ".flit_network_latency")
+        .flags(Stats::oneline)
+        ;
+
+    m_flit_queueing_latency
+        .init(m_virtual_networks)
+        .name(name() + ".flit_queueing_latency")
+        .flags(Stats::oneline)
+        ;
+
+    for (int i = 0; i < m_virtual_networks; i++) {
+        m_flits_received.subname(i, csprintf("vnet-%i", i));
+        m_flits_injected.subname(i, csprintf("vnet-%i", i));
+        m_flit_network_latency.subname(i, csprintf("vnet-%i", i));
+        m_flit_queueing_latency.subname(i, csprintf("vnet-%i", i));
+    }
+
+    m_avg_flit_vnet_latency
+        .name(name() + ".average_flit_vnet_latency")
+        .flags(Stats::oneline);
+    m_avg_flit_vnet_latency = m_flit_network_latency / m_flits_received;
+
+    m_avg_flit_vqueue_latency
+        .name(name() + ".average_flit_vqueue_latency")
+        .flags(Stats::oneline);
+    m_avg_flit_vqueue_latency =
+        m_flit_queueing_latency / m_flits_received;
+
+    m_avg_flit_network_latency
+        .name(name() + ".average_flit_network_latency");
+    m_avg_flit_network_latency =
+        sum(m_flit_network_latency) / sum(m_flits_received);
+
+    m_avg_flit_queueing_latency
+        .name(name() + ".average_flit_queueing_latency");
+    m_avg_flit_queueing_latency =
+        sum(m_flit_queueing_latency) / sum(m_flits_received);
+
+    m_avg_flit_latency
+        .name(name() + ".average_flit_latency");
+    m_avg_flit_latency =
+        m_avg_flit_network_latency + m_avg_flit_queueing_latency;
+
+
+    // Hops
+    m_avg_hops.name(name() + ".average_hops");
+    m_avg_hops = m_total_hops / sum(m_flits_received);
+
+    // Links
+    m_total_ext_in_link_utilization
+        .name(name() + ".ext_in_link_utilization");
+    m_total_ext_out_link_utilization
+        .name(name() + ".ext_out_link_utilization");
+    m_total_int_link_utilization
+        .name(name() + ".int_link_utilization");
+    m_average_link_utilization
+        .name(name() + ".avg_link_utilization");
+
+    m_average_vc_load
+        .init(m_virtual_networks * m_vcs_per_vnet)
+        .name(name() + ".avg_vc_load")
+        .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
+        ;
+}
+
+void
+GarnetNetwork::collateStats()
+{
+    RubySystem *rs = params()->ruby_system;
+    double time_delta = double(curCycle() - rs->getStartCycle());
+
+    for (int i = 0; i < m_networklinks.size(); i++) {
+        link_type type = m_networklinks[i]->getType();
+        int activity = m_networklinks[i]->getLinkUtilization();
+
+        if (type == EXT_IN_)
+            m_total_ext_in_link_utilization += activity;
+        else if (type == EXT_OUT_)
+            m_total_ext_out_link_utilization += activity;
+        else if (type == INT_)
+            m_total_int_link_utilization += activity;
+
+        m_average_link_utilization +=
+            (double(activity) / time_delta);
+
+        vector<unsigned int> vc_load = m_networklinks[i]->getVcLoad();
+        for (int j = 0; j < vc_load.size(); j++) {
+            m_average_vc_load[j] += ((double)vc_load[j] / time_delta);
+        }
+    }
+
+    // Ask the routers to collate their statistics
+    for (int i = 0; i < m_routers.size(); i++) {
+        m_routers[i]->collateStats();
+    }
+}
+
+void
+GarnetNetwork::print(ostream& out) const
+{
+    out << "[GarnetNetwork]";
+}
+
+GarnetNetwork *
+GarnetNetworkParams::create()
+{
+    return new GarnetNetwork(this);
+}
+
+uint32_t
+GarnetNetwork::functionalWrite(Packet *pkt)
+{
+    uint32_t num_functional_writes = 0;
+
+    for (unsigned int i = 0; i < m_routers.size(); i++) {
+        num_functional_writes += m_routers[i]->functionalWrite(pkt);
+    }
+
+    for (unsigned int i = 0; i < m_nis.size(); ++i) {
+        num_functional_writes += m_nis[i]->functionalWrite(pkt);
+    }
+
+    for (unsigned int i = 0; i < m_networklinks.size(); ++i) {
+        num_functional_writes += m_networklinks[i]->functionalWrite(pkt);
+    }
+
+    return num_functional_writes;
+}
diff --git a/src/mem/ruby/network/garnet2.0/GarnetNetwork.hh b/src/mem/ruby/network/garnet2.0/GarnetNetwork.hh
new file mode 100644 (file)
index 0000000..3ced887
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_NETWORK_HH__
+#define __MEM_RUBY_NETWORK_GARNET_NETWORK_HH__
+
+#include <iostream>
+#include <vector>
+
+#include "mem/ruby/network/Network.hh"
+#include "mem/ruby/network/fault_model/FaultModel.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "params/GarnetNetwork.hh"
+
+class FaultModel;
+class NetworkInterface;
+class Router;
+class NetDest;
+class NetworkLink;
+class CreditLink;
+
+class GarnetNetwork : public Network
+{
+  public:
+    typedef GarnetNetworkParams Params;
+    GarnetNetwork(const Params *p);
+
+    ~GarnetNetwork();
+    void init();
+
+    // Configuration (set externally)
+
+    // for 2D topology
+    int getNumRows() const { return m_num_rows; }
+    int getNumCols() { return m_num_cols; }
+
+    // for network
+    uint32_t getNiFlitSize() const { return m_ni_flit_size; }
+    uint32_t getVCsPerVnet() const { return m_vcs_per_vnet; }
+    uint32_t getBuffersPerDataVC() { return m_buffers_per_data_vc; }
+    uint32_t getBuffersPerCtrlVC() { return m_buffers_per_ctrl_vc; }
+    int getRoutingAlgorithm() const { return m_routing_algorithm; }
+
+    bool isFaultModelEnabled() const { return m_enable_fault_model; }
+    FaultModel* fault_model;
+
+
+    // Internal configuration
+    bool isVNetOrdered(int vnet) const { return m_ordered[vnet]; }
+    VNET_type
+    get_vnet_type(int vc)
+    {
+        int vnet = vc/getVCsPerVnet();
+        return m_vnet_type[vnet];
+    }
+    int getNumRouters();
+    int get_router_id(int ni);
+
+
+    // Methods used by Topology to setup the network
+    void makeExtOutLink(SwitchID src, NodeID dest, BasicLink* link,
+                     const NetDest& routing_table_entry);
+    void makeExtInLink(NodeID src, SwitchID dest, BasicLink* link,
+                    const NetDest& routing_table_entry);
+    void makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
+                          const NetDest& routing_table_entry,
+                          PortDirection src_outport_dirn,
+                          PortDirection dest_inport_dirn);
+
+    //! Function for performing a functional write. The return value
+    //! indicates the number of messages that were written.
+    uint32_t functionalWrite(Packet *pkt);
+
+    // Stats
+    void collateStats();
+    void regStats();
+    void print(std::ostream& out) const;
+
+    // increment counters
+    void increment_injected_packets(int vnet) { m_packets_injected[vnet]++; }
+    void increment_received_packets(int vnet) { m_packets_received[vnet]++; }
+
+    void
+    increment_packet_network_latency(Cycles latency, int vnet)
+    {
+        m_packet_network_latency[vnet] += latency;
+    }
+
+    void
+    increment_packet_queueing_latency(Cycles latency, int vnet)
+    {
+        m_packet_queueing_latency[vnet] += latency;
+    }
+
+    void increment_injected_flits(int vnet) { m_flits_injected[vnet]++; }
+    void increment_received_flits(int vnet) { m_flits_received[vnet]++; }
+
+    void
+    increment_flit_network_latency(Cycles latency, int vnet)
+    {
+        m_flit_network_latency[vnet] += latency;
+    }
+
+    void
+    increment_flit_queueing_latency(Cycles latency, int vnet)
+    {
+        m_flit_queueing_latency[vnet] += latency;
+    }
+
+    void
+    increment_total_hops(int hops)
+    {
+        m_total_hops += hops;
+    }
+
+  protected:
+    // Configuration
+    int m_num_rows;
+    int m_num_cols;
+    uint32_t m_ni_flit_size;
+    uint32_t m_vcs_per_vnet;
+    uint32_t m_buffers_per_ctrl_vc;
+    uint32_t m_buffers_per_data_vc;
+    int m_routing_algorithm;
+    bool m_enable_fault_model;
+
+    // Statistical variables
+    Stats::Vector m_packets_received;
+    Stats::Vector m_packets_injected;
+    Stats::Vector m_packet_network_latency;
+    Stats::Vector m_packet_queueing_latency;
+
+    Stats::Formula m_avg_packet_vnet_latency;
+    Stats::Formula m_avg_packet_vqueue_latency;
+    Stats::Formula m_avg_packet_network_latency;
+    Stats::Formula m_avg_packet_queueing_latency;
+    Stats::Formula m_avg_packet_latency;
+
+    Stats::Vector m_flits_received;
+    Stats::Vector m_flits_injected;
+    Stats::Vector m_flit_network_latency;
+    Stats::Vector m_flit_queueing_latency;
+
+    Stats::Formula m_avg_flit_vnet_latency;
+    Stats::Formula m_avg_flit_vqueue_latency;
+    Stats::Formula m_avg_flit_network_latency;
+    Stats::Formula m_avg_flit_queueing_latency;
+    Stats::Formula m_avg_flit_latency;
+
+    Stats::Scalar m_total_ext_in_link_utilization;
+    Stats::Scalar m_total_ext_out_link_utilization;
+    Stats::Scalar m_total_int_link_utilization;
+    Stats::Scalar m_average_link_utilization;
+    Stats::Vector m_average_vc_load;
+
+    Stats::Scalar  m_total_hops;
+    Stats::Formula m_avg_hops;
+
+  private:
+    GarnetNetwork(const GarnetNetwork& obj);
+    GarnetNetwork& operator=(const GarnetNetwork& obj);
+
+    std::vector<VNET_type > m_vnet_type;
+    std::vector<Router *> m_routers;   // All Routers in Network
+    std::vector<NetworkLink *> m_networklinks; // All flit links in the network
+    std::vector<CreditLink *> m_creditlinks; // All credit links in the network
+    std::vector<NetworkInterface *> m_nis;   // All NI's in Network
+};
+
+inline std::ostream&
+operator<<(std::ostream& out, const GarnetNetwork& obj)
+{
+    obj.print(out);
+    out << std::flush;
+    return out;
+}
+
+#endif // __MEM_RUBY_NETWORK_GARNET_NETWORK_HH__
diff --git a/src/mem/ruby/network/garnet2.0/GarnetNetwork.py b/src/mem/ruby/network/garnet2.0/GarnetNetwork.py
new file mode 100644 (file)
index 0000000..7045327
--- /dev/null
@@ -0,0 +1,68 @@
+# Copyright (c) 2008 Princeton University
+# Copyright (c) 2009 Advanced Micro Devices, Inc.
+# 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.
+#
+# Author: Tushar Krishna
+#
+
+from m5.params import *
+from m5.proxy import *
+from Network import RubyNetwork
+from BasicRouter import BasicRouter
+from ClockedObject import ClockedObject
+
+class GarnetNetwork(RubyNetwork):
+    type = 'GarnetNetwork'
+    cxx_header = "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
+    num_rows = Param.Int(0, "number of rows if 2D (mesh/torus/..) topology");
+    ni_flit_size = Param.UInt32(16, "network interface flit size in bytes")
+    vcs_per_vnet = Param.UInt32(4, "virtual channels per virtual network");
+    buffers_per_data_vc = Param.UInt32(4, "buffers per data virtual channel");
+    buffers_per_ctrl_vc = Param.UInt32(1, "buffers per ctrl virtual channel");
+    routing_algorithm = Param.Int(0,
+        "0: Weight-based Table, 1: XY, 2: Custom");
+    enable_fault_model = Param.Bool(False, "enable network fault model");
+    fault_model = Param.FaultModel(NULL, "network fault model");
+
+class GarnetNetworkInterface(ClockedObject):
+    type = 'GarnetNetworkInterface'
+    cxx_class = 'NetworkInterface'
+    cxx_header = "mem/ruby/network/garnet2.0/NetworkInterface.hh"
+
+    id = Param.UInt32("ID in relation to other network interfaces")
+    vcs_per_vnet = Param.UInt32(Parent.vcs_per_vnet,
+                             "virtual channels per virtual network")
+    virt_nets = Param.UInt32(Parent.number_of_virtual_networks,
+                          "number of virtual networks")
+
+class GarnetRouter(BasicRouter):
+    type = 'GarnetRouter'
+    cxx_class = 'Router'
+    cxx_header = "mem/ruby/network/garnet2.0/Router.hh"
+    vcs_per_vnet = Param.UInt32(Parent.vcs_per_vnet,
+                              "virtual channels per virtual network")
+    virt_nets = Param.UInt32(Parent.number_of_virtual_networks,
+                          "number of virtual networks")
diff --git a/src/mem/ruby/network/garnet2.0/InputUnit.cc b/src/mem/ruby/network/garnet2.0/InputUnit.cc
new file mode 100644 (file)
index 0000000..c03bf2a
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/InputUnit.hh"
+
+#include "base/stl_helpers.hh"
+#include "debug/RubyNetwork.hh"
+#include "mem/ruby/network/garnet2.0/Credit.hh"
+#include "mem/ruby/network/garnet2.0/Router.hh"
+
+using namespace std;
+using m5::stl_helpers::deletePointers;
+
+InputUnit::InputUnit(int id, PortDirection direction, Router *router)
+            : Consumer(router)
+{
+    m_id = id;
+    m_direction = direction;
+    m_router = router;
+    m_num_vcs = m_router->get_num_vcs();
+    m_vc_per_vnet = m_router->get_vc_per_vnet();
+
+    m_num_buffer_reads.resize(m_num_vcs/m_vc_per_vnet);
+    m_num_buffer_writes.resize(m_num_vcs/m_vc_per_vnet);
+    for (int i = 0; i < m_num_buffer_reads.size(); i++) {
+        m_num_buffer_reads[i] = 0;
+        m_num_buffer_writes[i] = 0;
+    }
+
+    creditQueue = new flitBuffer();
+    // Instantiating the virtual channels
+    m_vcs.resize(m_num_vcs);
+    for (int i=0; i < m_num_vcs; i++) {
+        m_vcs[i] = new VirtualChannel(i);
+    }
+}
+
+InputUnit::~InputUnit()
+{
+    delete creditQueue;
+    deletePointers(m_vcs);
+}
+
+/*
+ * The InputUnit wakeup function reads the input flit from its input link.
+ * Each flit arrives with an input VC.
+ * For HEAD/HEAD_TAIL flits, performs route computation,
+ * and updates route in the input VC.
+ * The flit is buffered for (m_latency - 1) cycles in the input VC
+ * and marked as valid for SwitchAllocation starting that cycle.
+ *
+ */
+
+void
+InputUnit::wakeup()
+{
+    flit *t_flit;
+    if (m_in_link->isReady(m_router->curCycle())) {
+
+        t_flit = m_in_link->consumeLink();
+        int vc = t_flit->get_vc();
+        t_flit->increment_hops(); // for stats
+
+        if ((t_flit->get_type() == HEAD_) ||
+            (t_flit->get_type() == HEAD_TAIL_)) {
+
+            assert(m_vcs[vc]->get_state() == IDLE_);
+            set_vc_active(vc, m_router->curCycle());
+
+            // Route computation for this vc
+            int outport = m_router->route_compute(t_flit->get_route(),
+                m_id, m_direction);
+
+            // Update output port in VC
+            // All flits in this packet will use this output port
+            // The output port field in the flit is updated after it wins SA
+            grant_outport(vc, outport);
+
+        } else {
+            assert(m_vcs[vc]->get_state() == ACTIVE_);
+        }
+
+
+        // Buffer the flit
+        m_vcs[vc]->insertFlit(t_flit);
+
+        int vnet = vc/m_vc_per_vnet;
+        // number of writes same as reads
+        // any flit that is written will be read only once
+        m_num_buffer_writes[vnet]++;
+        m_num_buffer_reads[vnet]++;
+
+        Cycles pipe_stages = m_router->get_pipe_stages();
+        if (pipe_stages == 1) {
+            // 1-cycle router
+            // Flit goes for SA directly
+            t_flit->advance_stage(SA_, m_router->curCycle());
+        } else {
+            assert(pipe_stages > 1);
+            // Router delay is modeled by making flit wait in buffer for
+            // (pipe_stages cycles - 1) cycles before going for SA
+
+            Cycles wait_time = pipe_stages - Cycles(1);
+            t_flit->advance_stage(SA_, m_router->curCycle() + wait_time);
+
+            // Wakeup the router in that cycle to perform SA
+            m_router->schedule_wakeup(Cycles(wait_time));
+        }
+    }
+}
+
+// Send a credit back to upstream router for this VC.
+// Called by SwitchAllocator when the flit in this VC wins the Switch.
+void
+InputUnit::increment_credit(int in_vc, bool free_signal, Cycles curTime)
+{
+    Credit *t_credit = new Credit(in_vc, free_signal, curTime);
+    creditQueue->insert(t_credit);
+    m_credit_link->scheduleEventAbsolute(m_router->clockEdge(Cycles(1)));
+}
+
+
+uint32_t
+InputUnit::functionalWrite(Packet *pkt)
+{
+    uint32_t num_functional_writes = 0;
+    for (int i=0; i < m_num_vcs; i++) {
+        num_functional_writes += m_vcs[i]->functionalWrite(pkt);
+    }
+
+    return num_functional_writes;
+}
+
+void
+InputUnit::resetStats()
+{
+    for (int j = 0; j < m_num_buffer_reads.size(); j++) {
+        m_num_buffer_reads[j] = 0;
+        m_num_buffer_writes[j] = 0;
+    }
+}
diff --git a/src/mem/ruby/network/garnet2.0/InputUnit.hh b/src/mem/ruby/network/garnet2.0/InputUnit.hh
new file mode 100644 (file)
index 0000000..26803ed
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_INPUT_UNIT_HH__
+#define __MEM_RUBY_NETWORK_GARNET_INPUT_UNIT_HH__
+
+#include <iostream>
+#include <vector>
+
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/CreditLink.hh"
+#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
+#include "mem/ruby/network/garnet2.0/Router.hh"
+#include "mem/ruby/network/garnet2.0/VirtualChannel.hh"
+#include "mem/ruby/network/garnet2.0/flitBuffer.hh"
+
+class InputUnit : public Consumer
+{
+  public:
+    InputUnit(int id, PortDirection direction, Router *router);
+    ~InputUnit();
+
+    void wakeup();
+    void print(std::ostream& out) const {};
+
+    inline PortDirection get_direction() { return m_direction; }
+
+    inline void
+    set_vc_idle(int vc, Cycles curTime)
+    {
+        m_vcs[vc]->set_idle(curTime);
+    }
+
+    inline void
+    set_vc_active(int vc, Cycles curTime)
+    {
+        m_vcs[vc]->set_active(curTime);
+    }
+
+    inline void
+    grant_outport(int vc, int outport)
+    {
+        m_vcs[vc]->set_outport(outport);
+    }
+
+    inline void
+    grant_outvc(int vc, int outvc)
+    {
+        m_vcs[vc]->set_outvc(outvc);
+    }
+
+    inline int
+    get_outport(int invc)
+    {
+        return m_vcs[invc]->get_outport();
+    }
+
+    inline int
+    get_outvc(int invc)
+    {
+        return m_vcs[invc]->get_outvc();
+    }
+
+    inline Cycles
+    get_enqueue_time(int invc)
+    {
+        return m_vcs[invc]->get_enqueue_time();
+    }
+
+    void increment_credit(int in_vc, bool free_signal, Cycles curTime);
+
+    inline flit*
+    peekTopFlit(int vc)
+    {
+        return m_vcs[vc]->peekTopFlit();
+    }
+
+    inline flit*
+    getTopFlit(int vc)
+    {
+        return m_vcs[vc]->getTopFlit();
+    }
+
+    inline bool
+    need_stage(int vc, flit_stage stage, Cycles time)
+    {
+        return m_vcs[vc]->need_stage(stage, time);
+    }
+
+    inline bool
+    isReady(int invc, Cycles curTime)
+    {
+        return m_vcs[invc]->isReady(curTime);
+    }
+
+    flitBuffer* getCreditQueue() { return creditQueue; }
+
+    inline void
+    set_in_link(NetworkLink *link)
+    {
+        m_in_link = link;
+    }
+
+    inline int get_inlink_id() { return m_in_link->get_id(); }
+
+    inline void
+    set_credit_link(CreditLink *credit_link)
+    {
+        m_credit_link = credit_link;
+    }
+
+    double get_buf_read_activity(unsigned int vnet) const
+    { return m_num_buffer_reads[vnet]; }
+    double get_buf_write_activity(unsigned int vnet) const
+    { return m_num_buffer_writes[vnet]; }
+
+    uint32_t functionalWrite(Packet *pkt);
+    void resetStats();
+
+  private:
+    int m_id;
+    PortDirection m_direction;
+    int m_num_vcs;
+    int m_vc_per_vnet;
+
+    Router *m_router;
+    NetworkLink *m_in_link;
+    CreditLink *m_credit_link;
+    flitBuffer *creditQueue;
+
+    // Input Virtual channels
+    std::vector<VirtualChannel *> m_vcs;
+
+    // Statistical variables
+    std::vector<double> m_num_buffer_writes;
+    std::vector<double> m_num_buffer_reads;
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_INPUT_UNIT_HH__
diff --git a/src/mem/ruby/network/garnet2.0/NetworkInterface.cc b/src/mem/ruby/network/garnet2.0/NetworkInterface.cc
new file mode 100644 (file)
index 0000000..6bdaf39
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/NetworkInterface.hh"
+
+#include <cassert>
+#include <cmath>
+
+#include "base/cast.hh"
+#include "base/stl_helpers.hh"
+#include "debug/RubyNetwork.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
+#include "mem/ruby/network/garnet2.0/Credit.hh"
+#include "mem/ruby/network/garnet2.0/flitBuffer.hh"
+#include "mem/ruby/slicc_interface/Message.hh"
+
+using namespace std;
+using m5::stl_helpers::deletePointers;
+
+NetworkInterface::NetworkInterface(const Params *p)
+    : ClockedObject(p), Consumer(this), m_id(p->id),
+      m_virtual_networks(p->virt_nets), m_vc_per_vnet(p->vcs_per_vnet),
+      m_num_vcs(m_vc_per_vnet * m_virtual_networks)
+{
+    m_router_id = -1;
+    m_vc_round_robin = 0;
+    m_ni_out_vcs.resize(m_num_vcs);
+    m_ni_out_vcs_enqueue_time.resize(m_num_vcs);
+    outCreditQueue = new flitBuffer();
+
+    // instantiating the NI flit buffers
+    for (int i = 0; i < m_num_vcs; i++) {
+        m_ni_out_vcs[i] = new flitBuffer();
+        m_ni_out_vcs_enqueue_time[i] = Cycles(INFINITE_);
+    }
+
+    m_vc_allocator.resize(m_virtual_networks); // 1 allocator per vnet
+    for (int i = 0; i < m_virtual_networks; i++) {
+        m_vc_allocator[i] = 0;
+    }
+}
+
+void
+NetworkInterface::init()
+{
+    for (int i = 0; i < m_num_vcs; i++) {
+        m_out_vc_state.push_back(new OutVcState(i, m_net_ptr));
+    }
+}
+
+NetworkInterface::~NetworkInterface()
+{
+    deletePointers(m_out_vc_state);
+    deletePointers(m_ni_out_vcs);
+    delete outCreditQueue;
+    delete outFlitQueue;
+}
+
+void
+NetworkInterface::addInPort(NetworkLink *in_link,
+                              CreditLink *credit_link)
+{
+    inNetLink = in_link;
+    in_link->setLinkConsumer(this);
+    outCreditLink = credit_link;
+    credit_link->setSourceQueue(outCreditQueue);
+}
+
+void
+NetworkInterface::addOutPort(NetworkLink *out_link,
+                             CreditLink *credit_link,
+                             SwitchID router_id)
+{
+    inCreditLink = credit_link;
+    credit_link->setLinkConsumer(this);
+
+    outNetLink = out_link;
+    outFlitQueue = new flitBuffer();
+    out_link->setSourceQueue(outFlitQueue);
+
+    m_router_id = router_id;
+}
+
+void
+NetworkInterface::addNode(vector<MessageBuffer *>& in,
+                            vector<MessageBuffer *>& out)
+{
+    inNode_ptr = in;
+    outNode_ptr = out;
+
+    for (auto& it : in) {
+        if (it != nullptr) {
+            it->setConsumer(this);
+        }
+    }
+}
+
+
+/*
+ * The NI wakeup checks whether there are any ready messages in the protocol
+ * buffer. If yes, it picks that up, flitisizes it into a number of flits and
+ * puts it into an output buffer and schedules the output link. On a wakeup
+ * it also checks whether there are flits in the input link. If yes, it picks
+ * them up and if the flit is a tail, the NI inserts the corresponding message
+ * into the protocol buffer. It also checks for credits being sent by the
+ * downstream router.
+ */
+
+void
+NetworkInterface::wakeup()
+{
+    DPRINTF(RubyNetwork, "Network Interface %d connected to router %d "
+            "woke up at time: %lld\n", m_id, m_router_id, curCycle());
+
+    MsgPtr msg_ptr;
+    Tick curTime = clockEdge();
+
+    // Checking for messages coming from the protocol
+    // can pick up a message/cycle for each virtual net
+    for (int vnet = 0; vnet < inNode_ptr.size(); ++vnet) {
+        MessageBuffer *b = inNode_ptr[vnet];
+        if (b == nullptr) {
+            continue;
+        }
+
+        if (b->isReady(curTime)) { // Is there a message waiting
+            msg_ptr = b->peekMsgPtr();
+            if (flitisizeMessage(msg_ptr, vnet)) {
+                b->dequeue(curTime);
+            } else {
+                break;
+            }
+        }
+    }
+
+    scheduleOutputLink();
+    checkReschedule();
+
+    /*********** Check the incoming flit link **********/
+
+    if (inNetLink->isReady(curCycle())) {
+        flit *t_flit = inNetLink->consumeLink();
+        bool free_signal = false;
+        if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) {
+            free_signal = true;
+
+            // enqueue into the protocol buffers
+            outNode_ptr[t_flit->get_vnet()]->enqueue(
+                t_flit->get_msg_ptr(), curTime, cyclesToTicks(Cycles(1)));
+        }
+        // Simply send a credit back since we are not buffering
+        // this flit in the NI
+        Credit *t_credit = new Credit(t_flit->get_vc(), free_signal,
+                                         curCycle());
+        outCreditQueue->insert(t_credit);
+        outCreditLink->
+            scheduleEventAbsolute(clockEdge(Cycles(1)));
+
+        int vnet = t_flit->get_vnet();
+
+        // Update Stats
+
+        // Latency
+        m_net_ptr->increment_received_flits(vnet);
+        Cycles network_delay = curCycle() - t_flit->get_enqueue_time();
+        Cycles queueing_delay = t_flit->get_src_delay();
+
+        m_net_ptr->increment_flit_network_latency(network_delay, vnet);
+        m_net_ptr->increment_flit_queueing_latency(queueing_delay, vnet);
+
+        if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) {
+            m_net_ptr->increment_received_packets(vnet);
+            m_net_ptr->increment_packet_network_latency(network_delay, vnet);
+            m_net_ptr->increment_packet_queueing_latency(queueing_delay, vnet);
+        }
+
+        // Hops
+        m_net_ptr->increment_total_hops(t_flit->get_route().hops_traversed);
+
+        delete t_flit;
+    }
+
+    /****************** Check the incoming credit link *******/
+
+    if (inCreditLink->isReady(curCycle())) {
+        Credit *t_credit = (Credit*) inCreditLink->consumeLink();
+        m_out_vc_state[t_credit->get_vc()]->increment_credit();
+        if (t_credit->is_free_signal()) {
+            m_out_vc_state[t_credit->get_vc()]->setState(IDLE_, curCycle());
+        }
+        delete t_credit;
+    }
+}
+
+
+// Embed the protocol message into flits
+bool
+NetworkInterface::flitisizeMessage(MsgPtr msg_ptr, int vnet)
+{
+    Message *net_msg_ptr = msg_ptr.get();
+    NetDest net_msg_dest = net_msg_ptr->getDestination();
+
+    // gets all the destinations associated with this message.
+    vector<NodeID> dest_nodes = net_msg_dest.getAllDest();
+
+    // Number of flits is dependent on the link bandwidth available.
+    // This is expressed in terms of bytes/cycle or the flit size
+    int num_flits = (int) ceil((double) m_net_ptr->MessageSizeType_to_int(
+        net_msg_ptr->getMessageSize())/m_net_ptr->getNiFlitSize());
+
+    // loop to convert all multicast messages into unicast messages
+    for (int ctr = 0; ctr < dest_nodes.size(); ctr++) {
+
+        // this will return a free output virtual channel
+        int vc = calculateVC(vnet);
+
+        if (vc == -1) {
+            return false ;
+        }
+        MsgPtr new_msg_ptr = msg_ptr->clone();
+        NodeID destID = dest_nodes[ctr];
+
+        Message *new_net_msg_ptr = new_msg_ptr.get();
+        if (dest_nodes.size() > 1) {
+            NetDest personal_dest;
+            for (int m = 0; m < (int) MachineType_NUM; m++) {
+                if ((destID >= MachineType_base_number((MachineType) m)) &&
+                    destID < MachineType_base_number((MachineType) (m+1))) {
+                    // calculating the NetDest associated with this destID
+                    personal_dest.clear();
+                    personal_dest.add((MachineID) {(MachineType) m, (destID -
+                        MachineType_base_number((MachineType) m))});
+                    new_net_msg_ptr->getDestination() = personal_dest;
+                    break;
+                }
+            }
+            net_msg_dest.removeNetDest(personal_dest);
+            // removing the destination from the original message to reflect
+            // that a message with this particular destination has been
+            // flitisized and an output vc is acquired
+            net_msg_ptr->getDestination().removeNetDest(personal_dest);
+        }
+
+        // Embed Route into the flits
+        // NetDest format is used by the routing table
+        // Custom routing algorithms just need destID
+        RouteInfo route;
+        route.vnet = vnet;
+        route.net_dest = new_net_msg_ptr->getDestination();
+        route.src_ni = m_id;
+        route.src_router = m_router_id;
+        route.dest_ni = destID;
+        route.dest_router = m_net_ptr->get_router_id(destID);
+
+        // initialize hops_traversed to -1
+        // so that the first router increments it to 0
+        route.hops_traversed = -1;
+
+        m_net_ptr->increment_injected_packets(vnet);
+        for (int i = 0; i < num_flits; i++) {
+            m_net_ptr->increment_injected_flits(vnet);
+            flit *fl = new flit(i, vc, vnet, route, num_flits, new_msg_ptr,
+                curCycle());
+
+            fl->set_src_delay(curCycle() - ticksToCycles(msg_ptr->getTime()));
+            m_ni_out_vcs[vc]->insert(fl);
+        }
+
+        m_ni_out_vcs_enqueue_time[vc] = curCycle();
+        m_out_vc_state[vc]->setState(ACTIVE_, curCycle());
+    }
+    return true ;
+}
+
+// Looking for a free output vc
+int
+NetworkInterface::calculateVC(int vnet)
+{
+    for (int i = 0; i < m_vc_per_vnet; i++) {
+        int delta = m_vc_allocator[vnet];
+        m_vc_allocator[vnet]++;
+        if (m_vc_allocator[vnet] == m_vc_per_vnet)
+            m_vc_allocator[vnet] = 0;
+
+        if (m_out_vc_state[(vnet*m_vc_per_vnet) + delta]->isInState(
+                    IDLE_, curCycle())) {
+            return ((vnet*m_vc_per_vnet) + delta);
+        }
+    }
+    return -1;
+}
+
+
+/** This function looks at the NI buffers
+ *  if some buffer has flits which are ready to traverse the link in the next
+ *  cycle, and the downstream output vc associated with this flit has buffers
+ *  left, the link is scheduled for the next cycle
+ */
+
+void
+NetworkInterface::scheduleOutputLink()
+{
+    int vc = m_vc_round_robin;
+    m_vc_round_robin++;
+    if (m_vc_round_robin == m_num_vcs)
+        m_vc_round_robin = 0;
+
+    for (int i = 0; i < m_num_vcs; i++) {
+        vc++;
+        if (vc == m_num_vcs)
+            vc = 0;
+
+        // model buffer backpressure
+        if (m_ni_out_vcs[vc]->isReady(curCycle()) &&
+            m_out_vc_state[vc]->has_credit()) {
+
+            bool is_candidate_vc = true;
+            int t_vnet = get_vnet(vc);
+            int vc_base = t_vnet * m_vc_per_vnet;
+
+            if (m_net_ptr->isVNetOrdered(t_vnet)) {
+                for (int vc_offset = 0; vc_offset < m_vc_per_vnet;
+                     vc_offset++) {
+                    int t_vc = vc_base + vc_offset;
+                    if (m_ni_out_vcs[t_vc]->isReady(curCycle())) {
+                        if (m_ni_out_vcs_enqueue_time[t_vc] <
+                            m_ni_out_vcs_enqueue_time[vc]) {
+                            is_candidate_vc = false;
+                            break;
+                        }
+                    }
+                }
+            }
+            if (!is_candidate_vc)
+                continue;
+
+            m_out_vc_state[vc]->decrement_credit();
+            // Just removing the flit
+            flit *t_flit = m_ni_out_vcs[vc]->getTopFlit();
+            t_flit->set_time(curCycle() + Cycles(1));
+            outFlitQueue->insert(t_flit);
+            // schedule the out link
+            outNetLink->scheduleEventAbsolute(clockEdge(Cycles(1)));
+
+            if (t_flit->get_type() == TAIL_ ||
+               t_flit->get_type() == HEAD_TAIL_) {
+                m_ni_out_vcs_enqueue_time[vc] = Cycles(INFINITE_);
+            }
+            return;
+        }
+    }
+}
+
+int
+NetworkInterface::get_vnet(int vc)
+{
+    for (int i = 0; i < m_virtual_networks; i++) {
+        if (vc >= (i*m_vc_per_vnet) && vc < ((i+1)*m_vc_per_vnet)) {
+            return i;
+        }
+    }
+    fatal("Could not determine vc");
+}
+
+
+// Wakeup the NI in the next cycle if there are waiting
+// messages in the protocol buffer, or waiting flits in the
+// output VC buffer
+void
+NetworkInterface::checkReschedule()
+{
+    for (const auto& it : inNode_ptr) {
+        if (it == nullptr) {
+            continue;
+        }
+
+        while (it->isReady(clockEdge())) { // Is there a message waiting
+            scheduleEvent(Cycles(1));
+            return;
+        }
+    }
+
+    for (int vc = 0; vc < m_num_vcs; vc++) {
+        if (m_ni_out_vcs[vc]->isReady(curCycle() + Cycles(1))) {
+            scheduleEvent(Cycles(1));
+            return;
+        }
+    }
+}
+
+void
+NetworkInterface::print(std::ostream& out) const
+{
+    out << "[Network Interface]";
+}
+
+uint32_t
+NetworkInterface::functionalWrite(Packet *pkt)
+{
+    uint32_t num_functional_writes = 0;
+    for (unsigned int i  = 0; i < m_num_vcs; ++i) {
+        num_functional_writes += m_ni_out_vcs[i]->functionalWrite(pkt);
+    }
+
+    num_functional_writes += outFlitQueue->functionalWrite(pkt);
+    return num_functional_writes;
+}
+
+NetworkInterface *
+GarnetNetworkInterfaceParams::create()
+{
+    return new NetworkInterface(this);
+}
diff --git a/src/mem/ruby/network/garnet2.0/NetworkInterface.hh b/src/mem/ruby/network/garnet2.0/NetworkInterface.hh
new file mode 100644 (file)
index 0000000..85e0145
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_NETWORK_INTERFACE_HH__
+#define __MEM_RUBY_NETWORK_GARNET_NETWORK_INTERFACE_HH__
+
+#include <iostream>
+#include <vector>
+
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/CreditLink.hh"
+#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
+#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
+#include "mem/ruby/network/garnet2.0/OutVcState.hh"
+#include "mem/ruby/slicc_interface/Message.hh"
+#include "params/GarnetNetworkInterface.hh"
+
+class MessageBuffer;
+class flitBuffer;
+
+class NetworkInterface : public ClockedObject, public Consumer
+{
+  public:
+    typedef GarnetNetworkInterfaceParams Params;
+    NetworkInterface(const Params *p);
+    ~NetworkInterface();
+
+    void init();
+
+    void addInPort(NetworkLink *in_link, CreditLink *credit_link);
+    void addOutPort(NetworkLink *out_link, CreditLink *credit_link,
+        SwitchID router_id);
+
+    void wakeup();
+    void addNode(std::vector<MessageBuffer *> &inNode,
+                 std::vector<MessageBuffer *> &outNode);
+
+    void print(std::ostream& out) const;
+    int get_vnet(int vc);
+    int get_router_id() { return m_router_id; }
+    void init_net_ptr(GarnetNetwork *net_ptr) { m_net_ptr = net_ptr; }
+
+    uint32_t functionalWrite(Packet *);
+
+  private:
+    GarnetNetwork *m_net_ptr;
+    const NodeID m_id;
+    const int m_virtual_networks, m_vc_per_vnet, m_num_vcs;
+    int m_router_id; // id of my router
+    std::vector<OutVcState *> m_out_vc_state;
+    std::vector<int> m_vc_allocator;
+    int m_vc_round_robin; // For round robin scheduling
+    flitBuffer *outFlitQueue; // For modeling link contention
+    flitBuffer *outCreditQueue;
+
+    NetworkLink *inNetLink;
+    NetworkLink *outNetLink;
+    CreditLink *inCreditLink;
+    CreditLink *outCreditLink;
+
+    // Input Flit Buffers
+    // The flit buffers which will serve the Consumer
+    std::vector<flitBuffer *>  m_ni_out_vcs;
+    std::vector<Cycles> m_ni_out_vcs_enqueue_time;
+
+    // The Message buffers that takes messages from the protocol
+    std::vector<MessageBuffer *> inNode_ptr;
+    // The Message buffers that provides messages to the protocol
+    std::vector<MessageBuffer *> outNode_ptr;
+
+    bool flitisizeMessage(MsgPtr msg_ptr, int vnet);
+    int calculateVC(int vnet);
+    void scheduleOutputLink();
+    void checkReschedule();
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_NETWORK_INTERFACE_HH__
diff --git a/src/mem/ruby/network/garnet2.0/NetworkLink.cc b/src/mem/ruby/network/garnet2.0/NetworkLink.cc
new file mode 100644 (file)
index 0000000..6010071
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
+
+#include "mem/ruby/network/garnet2.0/CreditLink.hh"
+
+NetworkLink::NetworkLink(const Params *p)
+    : ClockedObject(p), Consumer(this), m_id(p->link_id),
+      m_type(NUM_LINK_TYPES_),
+      m_latency(p->link_latency),
+      linkBuffer(new flitBuffer()), link_consumer(nullptr),
+      link_srcQueue(nullptr), m_link_utilized(0),
+      m_vc_load(p->vcs_per_vnet * p->virt_nets)
+{
+}
+
+NetworkLink::~NetworkLink()
+{
+    delete linkBuffer;
+}
+
+void
+NetworkLink::setLinkConsumer(Consumer *consumer)
+{
+    link_consumer = consumer;
+}
+
+void
+NetworkLink::setSourceQueue(flitBuffer *srcQueue)
+{
+    link_srcQueue = srcQueue;
+}
+
+void
+NetworkLink::wakeup()
+{
+    if (link_srcQueue->isReady(curCycle())) {
+        flit *t_flit = link_srcQueue->getTopFlit();
+        t_flit->set_time(curCycle() + m_latency);
+        linkBuffer->insert(t_flit);
+        link_consumer->scheduleEventAbsolute(clockEdge(m_latency));
+        m_link_utilized++;
+        m_vc_load[t_flit->get_vc()]++;
+    }
+}
+
+NetworkLink *
+NetworkLinkParams::create()
+{
+    return new NetworkLink(this);
+}
+
+CreditLink *
+CreditLinkParams::create()
+{
+    return new CreditLink(this);
+}
+
+uint32_t
+NetworkLink::functionalWrite(Packet *pkt)
+{
+    return linkBuffer->functionalWrite(pkt);
+}
diff --git a/src/mem/ruby/network/garnet2.0/NetworkLink.hh b/src/mem/ruby/network/garnet2.0/NetworkLink.hh
new file mode 100644 (file)
index 0000000..cb69b39
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_NETWORK_LINK_HH__
+#define __MEM_RUBY_NETWORK_GARNET_NETWORK_LINK_HH__
+
+#include <iostream>
+#include <vector>
+
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/flitBuffer.hh"
+#include "params/NetworkLink.hh"
+#include "sim/clocked_object.hh"
+
+class GarnetNetwork;
+
+class NetworkLink : public ClockedObject, public Consumer
+{
+  public:
+    typedef NetworkLinkParams Params;
+    NetworkLink(const Params *p);
+    ~NetworkLink();
+
+    void setLinkConsumer(Consumer *consumer);
+    void setSourceQueue(flitBuffer *srcQueue);
+    void setType(link_type type) { m_type = type; }
+    link_type getType() { return m_type; }
+    void print(std::ostream& out) const {}
+    int get_id() const { return m_id; }
+    void wakeup();
+
+    unsigned int getLinkUtilization() const { return m_link_utilized; }
+    const std::vector<unsigned int> & getVcLoad() const { return m_vc_load; }
+
+    inline bool isReady(Cycles curTime)
+    { return linkBuffer->isReady(curTime); }
+
+    inline flit* peekLink()       { return linkBuffer->peekTopFlit(); }
+    inline flit* consumeLink()    { return linkBuffer->getTopFlit(); }
+
+    uint32_t functionalWrite(Packet *);
+
+  private:
+    const int m_id;
+    link_type m_type;
+    const Cycles m_latency;
+
+    flitBuffer *linkBuffer;
+    Consumer *link_consumer;
+    flitBuffer *link_srcQueue;
+
+    // Statistical variables
+    unsigned int m_link_utilized;
+    std::vector<unsigned int> m_vc_load;
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_NETWORK_LINK_HH__
diff --git a/src/mem/ruby/network/garnet2.0/OutVcState.cc b/src/mem/ruby/network/garnet2.0/OutVcState.cc
new file mode 100644 (file)
index 0000000..1ad65ec
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/OutVcState.hh"
+
+#include "mem/ruby/system/RubySystem.hh"
+
+OutVcState::OutVcState(int id, GarnetNetwork *network_ptr)
+    : m_time(0)
+{
+    m_id = id;
+    m_vc_state = IDLE_;
+
+    if (network_ptr->get_vnet_type(id) == DATA_VNET_)
+        m_max_credit_count = network_ptr->getBuffersPerDataVC();
+    else
+        m_max_credit_count = network_ptr->getBuffersPerCtrlVC();
+
+    m_credit_count = m_max_credit_count;
+    assert(m_credit_count >= 1);
+}
+
+void
+OutVcState::increment_credit()
+{
+    m_credit_count++;
+    assert(m_credit_count <= m_max_credit_count);
+}
+
+void
+OutVcState::decrement_credit()
+{
+    m_credit_count--;
+    assert(m_credit_count >= 0);
+}
diff --git a/src/mem/ruby/network/garnet2.0/OutVcState.hh b/src/mem/ruby/network/garnet2.0/OutVcState.hh
new file mode 100644 (file)
index 0000000..b9c008d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_OUTVC_STATE_HH__
+#define __MEM_RUBY_NETWORK_GARNET_OUTVC_STATE_HH__
+
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
+
+class OutVcState
+{
+  public:
+    OutVcState(int id, GarnetNetwork *network_ptr);
+
+    int get_credit_count()          { return m_credit_count; }
+    inline bool has_credit()       { return (m_credit_count > 0); }
+    void increment_credit();
+    void decrement_credit();
+
+    inline bool
+    isInState(VC_state_type state, Cycles request_time)
+    {
+        return ((m_vc_state == state) && (request_time >= m_time) );
+    }
+    inline void
+    setState(VC_state_type state, Cycles time)
+    {
+        m_vc_state = state;
+        m_time = time;
+    }
+
+  private:
+    int m_id ;
+    Cycles m_time;
+    VC_state_type m_vc_state;
+    int m_credit_count;
+    int m_max_credit_count;
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_OUTVC_STATE_HH__
diff --git a/src/mem/ruby/network/garnet2.0/OutputUnit.cc b/src/mem/ruby/network/garnet2.0/OutputUnit.cc
new file mode 100644 (file)
index 0000000..85fef5e
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/OutputUnit.hh"
+
+#include "base/stl_helpers.hh"
+#include "debug/RubyNetwork.hh"
+#include "mem/ruby/network/garnet2.0/Credit.hh"
+#include "mem/ruby/network/garnet2.0/Router.hh"
+
+using namespace std;
+using m5::stl_helpers::deletePointers;
+
+OutputUnit::OutputUnit(int id, PortDirection direction, Router *router)
+    : Consumer(router)
+{
+    m_id = id;
+    m_direction = direction;
+    m_router = router;
+    m_num_vcs = m_router->get_num_vcs();
+    m_vc_per_vnet = m_router->get_vc_per_vnet();
+    m_out_buffer = new flitBuffer();
+
+    for (int i = 0; i < m_num_vcs; i++) {
+        m_outvc_state.push_back(new OutVcState(i, m_router->get_net_ptr()));
+    }
+}
+
+OutputUnit::~OutputUnit()
+{
+    delete m_out_buffer;
+    deletePointers(m_outvc_state);
+}
+
+void
+OutputUnit::decrement_credit(int out_vc)
+{
+    DPRINTF(RubyNetwork, "Router %d OutputUnit %d decrementing credit for "
+            "outvc %d at time: %lld\n",
+            m_router->get_id(), m_id, out_vc, m_router->curCycle());
+
+    m_outvc_state[out_vc]->decrement_credit();
+}
+
+void
+OutputUnit::increment_credit(int out_vc)
+{
+    DPRINTF(RubyNetwork, "Router %d OutputUnit %d incrementing credit for "
+            "outvc %d at time: %lld\n",
+            m_router->get_id(), m_id, out_vc, m_router->curCycle());
+
+    m_outvc_state[out_vc]->increment_credit();
+}
+
+// Check if the output VC (i.e., input VC at next router)
+// has free credits (i..e, buffer slots).
+// This is tracked by OutVcState
+bool
+OutputUnit::has_credit(int out_vc)
+{
+    assert(m_outvc_state[out_vc]->isInState(ACTIVE_, m_router->curCycle()));
+    return m_outvc_state[out_vc]->has_credit();
+}
+
+
+// Check if the output port (i.e., input port at next router) has free VCs.
+bool
+OutputUnit::has_free_vc(int vnet)
+{
+    int vc_base = vnet*m_vc_per_vnet;
+    for (int vc = vc_base; vc < vc_base + m_vc_per_vnet; vc++) {
+        if (is_vc_idle(vc, m_router->curCycle()))
+            return true;
+    }
+
+    return false;
+}
+
+// Assign a free output VC to the winner of Switch Allocation
+int
+OutputUnit::select_free_vc(int vnet)
+{
+    int vc_base = vnet*m_vc_per_vnet;
+    for (int vc = vc_base; vc < vc_base + m_vc_per_vnet; vc++) {
+        if (is_vc_idle(vc, m_router->curCycle())) {
+            m_outvc_state[vc]->setState(ACTIVE_, m_router->curCycle());
+            return vc;
+        }
+    }
+
+    return -1;
+}
+
+/*
+ * The wakeup function of the OutputUnit reads the credit signal from the
+ * downstream router for the output VC (i.e., input VC at downstream router).
+ * It increments the credit count in the appropriate output VC state.
+ * If the credit carries is_free_signal as true,
+ * the output VC is marked IDLE.
+ */
+
+void
+OutputUnit::wakeup()
+{
+    if (m_credit_link->isReady(m_router->curCycle())) {
+        Credit *t_credit = (Credit*) m_credit_link->consumeLink();
+        increment_credit(t_credit->get_vc());
+
+        if (t_credit->is_free_signal())
+            set_vc_state(IDLE_, t_credit->get_vc(), m_router->curCycle());
+
+        delete t_credit;
+    }
+}
+
+flitBuffer*
+OutputUnit::getOutQueue()
+{
+    return m_out_buffer;
+}
+
+void
+OutputUnit::set_out_link(NetworkLink *link)
+{
+    m_out_link = link;
+}
+
+void
+OutputUnit::set_credit_link(CreditLink *credit_link)
+{
+    m_credit_link = credit_link;
+}
+
+uint32_t
+OutputUnit::functionalWrite(Packet *pkt)
+{
+    return m_out_buffer->functionalWrite(pkt);
+}
diff --git a/src/mem/ruby/network/garnet2.0/OutputUnit.hh b/src/mem/ruby/network/garnet2.0/OutputUnit.hh
new file mode 100644 (file)
index 0000000..7b6d549
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_OUTPUT_UNIT_HH__
+#define __MEM_RUBY_NETWORK_GARNET_OUTPUT_UNIT_HH__
+
+#include <iostream>
+#include <vector>
+
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/CreditLink.hh"
+#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
+#include "mem/ruby/network/garnet2.0/OutVcState.hh"
+#include "mem/ruby/network/garnet2.0/Router.hh"
+#include "mem/ruby/network/garnet2.0/flitBuffer.hh"
+
+class OutputUnit : public Consumer
+{
+  public:
+    OutputUnit(int id, PortDirection direction, Router *router);
+    ~OutputUnit();
+    void set_out_link(NetworkLink *link);
+    void set_credit_link(CreditLink *credit_link);
+    void wakeup();
+    flitBuffer* getOutQueue();
+    void print(std::ostream& out) const {};
+    void decrement_credit(int out_vc);
+    void increment_credit(int out_vc);
+    bool has_credit(int out_vc);
+    bool has_free_vc(int vnet);
+    int select_free_vc(int vnet);
+
+    inline PortDirection get_direction() { return m_direction; }
+
+    int
+    get_credit_count(int vc)
+    {
+        return m_outvc_state[vc]->get_credit_count();
+    }
+
+    inline int
+    get_outlink_id()
+    {
+        return m_out_link->get_id();
+    }
+
+    inline void
+    set_vc_state(VC_state_type state, int vc, Cycles curTime)
+    {
+      m_outvc_state[vc]->setState(state, curTime);
+    }
+
+    inline bool
+    is_vc_idle(int vc, Cycles curTime)
+    {
+        return (m_outvc_state[vc]->isInState(IDLE_, curTime));
+    }
+
+    inline void
+    insert_flit(flit *t_flit)
+    {
+        m_out_buffer->insert(t_flit);
+        m_out_link->scheduleEventAbsolute(m_router->clockEdge(Cycles(1)));
+    }
+
+    uint32_t functionalWrite(Packet *pkt);
+
+  private:
+    int m_id;
+    PortDirection m_direction;
+    int m_num_vcs;
+    int m_vc_per_vnet;
+    Router *m_router;
+    NetworkLink *m_out_link;
+    CreditLink *m_credit_link;
+
+    flitBuffer *m_out_buffer; // This is for the network link to consume
+    std::vector<OutVcState *> m_outvc_state; // vc state of downstream router
+
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_OUTPUT_UNIT_HH__
diff --git a/src/mem/ruby/network/garnet2.0/README.txt b/src/mem/ruby/network/garnet2.0/README.txt
new file mode 100644 (file)
index 0000000..817b1d4
--- /dev/null
@@ -0,0 +1,71 @@
+README for Garnet2.0
+Written By: Tushar Krishna (tushar@ece.gatech.edu)
+Last Updated: Jul 9, 2016
+-------------------------------------------------------
+
+Garnet Network Parameters and Setup:
+- GarnetNetwork.py
+    * defaults can be overwritten from command line (see configs/network/Network.py)
+- GarnetNetwork.hh/cc
+    * sets up the routers and links
+    * collects stats
+
+
+CODE FLOW
+- NetworkInterface.cc::wakeup()
+    * Every NI connected to one coherence protocol controller on one end, and one router on the other.
+    * receives messages from coherence protocol buffer in appropriate vnet and converts them into network packets and sends them into the network.
+        * garnet2.0 adds the ability to capture a network trace at this point.
+    * receives flits from the network, extracts the protocol message and sends it to the coherence protocol buffer in appropriate vnet.
+    * manages flow-control (i.e., credits) with its attached router.
+    * The consuming flit/credit output link of the NI is put in the global event queue with a timestamp set to next cycle.
+      The eventqueue calls the wakeup function in the consumer.
+
+- NetworkLink.cc::wakeup()
+    * receives flits from NI/router and sends it to NI/router after m_latency cycles delay
+        * Default latency value for every link can be set from command line (see configs/network/Network.py)
+        * Per link latency can be overwritten in the topology file
+    * The consumer of the link (NI/router) is put in the global event queue with a timestamp set after m_latency cycles.
+      The eventqueue calls the wakeup function in the consumer.
+
+- Router.cc::wakeup()
+    * Loop through all InputUnits and call their wakeup()
+    * Loop through all OutputUnits and call their wakeup()
+    * Call SwitchAllocator's wakeup()
+    * Call CrossbarSwitch's wakeup()
+    * The router's wakeup function is called whenever any of its modules (InputUnit, OutputUnit, SwitchAllocator, CrossbarSwitch) have
+      a ready flit/credit to act upon this cycle.
+
+- InputUnit.cc::wakeup()
+    * Read input flit from upstream router if it is ready for this cycle
+    * For HEAD/HEAD_TAIL flits, perform route computation, and update route in the VC.
+    * Buffer the flit for (m_latency - 1) cycles and mark it valid for SwitchAllocation starting that cycle.
+        * Default latency for every router can be set from command line (see configs/network/Network.py)
+        * Per router latency (i.e., num pipeline stages) can be set in the topology file
+
+- OutputUnit.cc::wakeup()
+    * Read input credit from downstream router if it is ready for this cycle
+    * Increment the credit in the appropriate output VC state.
+    * Mark output VC as free if the credit carries is_free_signal as true
+
+- SwitchAllocator.cc::wakeup()
+    * Note: SwitchAllocator performs VC arbitration and selection within it.
+    * SA-I (or SA-i): Loop through all input VCs at every input port, and select one in a round robin manner.
+        * For HEAD/HEAD_TAIL flits only select an input VC whose output port has at least one free output VC.
+        * For BODY/TAIL flits, only select an input VC that has credits in its output VC.
+    * Place a request for the output port from this VC.
+    * SA-II (or SA-o): Loop through all output ports, and select one input VC (that placed a request during SA-I) as the winner for this output port in a round robin manner.
+        * For HEAD/HEAD_TAIL flits, perform outvc allocation (i.e., select a free VC from the output port).
+        * For BODY/TAIL flits, decrement a credit in the output vc.
+    * Read the flit out from the input VC, and send it to the CrossbarSwitch
+    * Send a increment_credit signal to the upstream router for this input VC.
+        * for HEAD_TAIL/TAIL flits, mark is_free_signal as true in the credit.
+        * The input unit sends the credit out on the credit link to the upstream router.
+    * Reschedule the Router to wakeup next cycle for any flits ready for SA next cycle.
+
+- CrossbarSwitch.cc::wakeup()
+    * Loop through all input ports, and send the winning flit out of its output port onto the output link.
+    * The consuming flit output link of the router is put in the global event queue with a timestamp set to next cycle.
+      The eventqueue calls the wakeup function in the consumer.
+
+
diff --git a/src/mem/ruby/network/garnet2.0/Router.cc b/src/mem/ruby/network/garnet2.0/Router.cc
new file mode 100644 (file)
index 0000000..65a7300
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/Router.hh"
+
+#include "base/stl_helpers.hh"
+#include "debug/RubyNetwork.hh"
+#include "mem/ruby/network/garnet2.0/CreditLink.hh"
+#include "mem/ruby/network/garnet2.0/CrossbarSwitch.hh"
+#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
+#include "mem/ruby/network/garnet2.0/InputUnit.hh"
+#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
+#include "mem/ruby/network/garnet2.0/OutputUnit.hh"
+#include "mem/ruby/network/garnet2.0/RoutingUnit.hh"
+#include "mem/ruby/network/garnet2.0/SwitchAllocator.hh"
+
+using namespace std;
+using m5::stl_helpers::deletePointers;
+
+Router::Router(const Params *p)
+    : BasicRouter(p), Consumer(this)
+{
+    m_latency = p->latency;
+    m_virtual_networks = p->virt_nets;
+    m_vc_per_vnet = p->vcs_per_vnet;
+    m_num_vcs = m_virtual_networks * m_vc_per_vnet;
+
+    m_routing_unit = new RoutingUnit(this);
+    m_sw_alloc = new SwitchAllocator(this);
+    m_switch = new CrossbarSwitch(this);
+
+    m_input_unit.clear();
+    m_output_unit.clear();
+}
+
+Router::~Router()
+{
+    deletePointers(m_input_unit);
+    deletePointers(m_output_unit);
+    delete m_routing_unit;
+    delete m_sw_alloc;
+    delete m_switch;
+}
+
+void
+Router::init()
+{
+    BasicRouter::init();
+
+    m_sw_alloc->init();
+    m_switch->init();
+}
+
+void
+Router::wakeup()
+{
+    DPRINTF(RubyNetwork, "Router %d woke up\n", m_id);
+
+    // check for incoming flits
+    for (int inport = 0; inport < m_input_unit.size(); inport++) {
+        m_input_unit[inport]->wakeup();
+    }
+
+    // check for incoming credits
+    // Note: the credit update is happening before SA
+    // buffer turnaround time =
+    //     credit traversal (1-cycle) + SA (1-cycle) + Link Traversal (1-cycle)
+    // if we want the credit update to take place after SA, this loop should
+    // be moved after the SA request
+    for (int outport = 0; outport < m_output_unit.size(); outport++) {
+        m_output_unit[outport]->wakeup();
+    }
+
+    // Switch Allocation
+    m_sw_alloc->wakeup();
+
+    // Switch Traversal
+    m_switch->wakeup();
+}
+
+void
+Router::addInPort(PortDirection inport_dirn,
+                  NetworkLink *in_link, CreditLink *credit_link)
+{
+    int port_num = m_input_unit.size();
+    InputUnit *input_unit = new InputUnit(port_num, inport_dirn, this);
+
+    input_unit->set_in_link(in_link);
+    input_unit->set_credit_link(credit_link);
+    in_link->setLinkConsumer(this);
+    credit_link->setSourceQueue(input_unit->getCreditQueue());
+
+    m_input_unit.push_back(input_unit);
+
+    m_routing_unit->addInDirection(inport_dirn, port_num);
+}
+
+void
+Router::addOutPort(PortDirection outport_dirn,
+                   NetworkLink *out_link,
+                   const NetDest& routing_table_entry, int link_weight,
+                   CreditLink *credit_link)
+{
+    int port_num = m_output_unit.size();
+    OutputUnit *output_unit = new OutputUnit(port_num, outport_dirn, this);
+
+    output_unit->set_out_link(out_link);
+    output_unit->set_credit_link(credit_link);
+    credit_link->setLinkConsumer(this);
+    out_link->setSourceQueue(output_unit->getOutQueue());
+
+    m_output_unit.push_back(output_unit);
+
+    m_routing_unit->addRoute(routing_table_entry);
+    m_routing_unit->addWeight(link_weight);
+    m_routing_unit->addOutDirection(outport_dirn, port_num);
+}
+
+PortDirection
+Router::getOutportDirection(int outport)
+{
+    return m_output_unit[outport]->get_direction();
+}
+
+PortDirection
+Router::getInportDirection(int inport)
+{
+    return m_input_unit[inport]->get_direction();
+}
+
+int
+Router::route_compute(RouteInfo route, int inport, PortDirection inport_dirn)
+{
+    return m_routing_unit->outportCompute(route, inport, inport_dirn);
+}
+
+void
+Router::grant_switch(int inport, flit *t_flit)
+{
+    m_switch->update_sw_winner(inport, t_flit);
+}
+
+void
+Router::schedule_wakeup(Cycles time)
+{
+    // wake up after time cycles
+    scheduleEvent(time);
+}
+
+std::string
+Router::getPortDirectionName(PortDirection direction)
+{
+    // PortDirection is actually a string
+    // If not, then this function should add a switch
+    // statement to convert direction to a string
+    // that can be printed out
+    return direction;
+}
+
+void
+Router::regStats()
+{
+    BasicRouter::regStats();
+
+    m_buffer_reads
+        .name(name() + ".buffer_reads")
+        .flags(Stats::nozero)
+    ;
+
+    m_buffer_writes
+        .name(name() + ".buffer_writes")
+        .flags(Stats::nozero)
+    ;
+
+    m_crossbar_activity
+        .name(name() + ".crossbar_activity")
+        .flags(Stats::nozero)
+    ;
+
+    m_sw_input_arbiter_activity
+        .name(name() + ".sw_input_arbiter_activity")
+        .flags(Stats::nozero)
+    ;
+
+    m_sw_output_arbiter_activity
+        .name(name() + ".sw_output_arbiter_activity")
+        .flags(Stats::nozero)
+    ;
+}
+
+void
+Router::collateStats()
+{
+    for (int j = 0; j < m_virtual_networks; j++) {
+        for (int i = 0; i < m_input_unit.size(); i++) {
+            m_buffer_reads += m_input_unit[i]->get_buf_read_activity(j);
+            m_buffer_writes += m_input_unit[i]->get_buf_write_activity(j);
+        }
+    }
+
+    m_sw_input_arbiter_activity = m_sw_alloc->get_input_arbiter_activity();
+    m_sw_output_arbiter_activity = m_sw_alloc->get_output_arbiter_activity();
+    m_crossbar_activity = m_switch->get_crossbar_activity();
+}
+
+void
+Router::resetStats()
+{
+    for (int j = 0; j < m_virtual_networks; j++) {
+        for (int i = 0; i < m_input_unit.size(); i++) {
+            m_input_unit[i]->resetStats();
+        }
+    }
+}
+
+void
+Router::printFaultVector(ostream& out)
+{
+    int temperature_celcius = BASELINE_TEMPERATURE_CELCIUS;
+    int num_fault_types = m_network_ptr->fault_model->number_of_fault_types;
+    float fault_vector[num_fault_types];
+    get_fault_vector(temperature_celcius, fault_vector);
+    out << "Router-" << m_id << " fault vector: " << endl;
+    for (int fault_type_index = 0; fault_type_index < num_fault_types;
+         fault_type_index++) {
+        out << " - probability of (";
+        out <<
+        m_network_ptr->fault_model->fault_type_to_string(fault_type_index);
+        out << ") = ";
+        out << fault_vector[fault_type_index] << endl;
+    }
+}
+
+void
+Router::printAggregateFaultProbability(std::ostream& out)
+{
+    int temperature_celcius = BASELINE_TEMPERATURE_CELCIUS;
+    float aggregate_fault_prob;
+    get_aggregate_fault_probability(temperature_celcius,
+                                    &aggregate_fault_prob);
+    out << "Router-" << m_id << " fault probability: ";
+    out << aggregate_fault_prob << endl;
+}
+
+uint32_t
+Router::functionalWrite(Packet *pkt)
+{
+    uint32_t num_functional_writes = 0;
+    num_functional_writes += m_switch->functionalWrite(pkt);
+
+    for (uint32_t i = 0; i < m_input_unit.size(); i++) {
+        num_functional_writes += m_input_unit[i]->functionalWrite(pkt);
+    }
+
+    for (uint32_t i = 0; i < m_output_unit.size(); i++) {
+        num_functional_writes += m_output_unit[i]->functionalWrite(pkt);
+    }
+
+    return num_functional_writes;
+}
+
+Router *
+GarnetRouterParams::create()
+{
+    return new Router(this);
+}
diff --git a/src/mem/ruby/network/garnet2.0/Router.hh b/src/mem/ruby/network/garnet2.0/Router.hh
new file mode 100644 (file)
index 0000000..a9ce5f8
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_ROUTER_HH__
+#define __MEM_RUBY_NETWORK_GARNET_ROUTER_HH__
+
+#include <iostream>
+#include <vector>
+
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/ruby/common/NetDest.hh"
+#include "mem/ruby/network/BasicRouter.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
+#include "mem/ruby/network/garnet2.0/flit.hh"
+#include "params/GarnetRouter.hh"
+
+class NetworkLink;
+class CreditLink;
+class InputUnit;
+class OutputUnit;
+class RoutingUnit;
+class SwitchAllocator;
+class CrossbarSwitch;
+class FaultModel;
+
+class Router : public BasicRouter, public Consumer
+{
+  public:
+    typedef GarnetRouterParams Params;
+    Router(const Params *p);
+
+    ~Router();
+
+    void wakeup();
+    void print(std::ostream& out) const {};
+
+    void init();
+    void addInPort(PortDirection inport_dirn, NetworkLink *link,
+                   CreditLink *credit_link);
+    void addOutPort(PortDirection outport_dirn, NetworkLink *link,
+                    const NetDest& routing_table_entry,
+                    int link_weight, CreditLink *credit_link);
+
+    Cycles get_pipe_stages(){ return m_latency; }
+    int get_num_vcs()       { return m_num_vcs; }
+    int get_num_vnets()     { return m_virtual_networks; }
+    int get_vc_per_vnet()   { return m_vc_per_vnet; }
+    int get_num_inports()   { return m_input_unit.size(); }
+    int get_num_outports()  { return m_output_unit.size(); }
+    int get_id()            { return m_id; }
+
+    void init_net_ptr(GarnetNetwork* net_ptr)
+    {
+        m_network_ptr = net_ptr;
+    }
+
+    GarnetNetwork* get_net_ptr()                    { return m_network_ptr; }
+    std::vector<InputUnit *>& get_inputUnit_ref()   { return m_input_unit; }
+    std::vector<OutputUnit *>& get_outputUnit_ref() { return m_output_unit; }
+    PortDirection getOutportDirection(int outport);
+    PortDirection getInportDirection(int inport);
+
+    int route_compute(RouteInfo route, int inport, PortDirection direction);
+    void grant_switch(int inport, flit *t_flit);
+    void schedule_wakeup(Cycles time);
+
+    std::string getPortDirectionName(PortDirection direction);
+    void printFaultVector(std::ostream& out);
+    void printAggregateFaultProbability(std::ostream& out);
+
+    void regStats();
+    void collateStats();
+    void resetStats();
+
+    // For Fault Model:
+    bool get_fault_vector(int temperature, float fault_vector[]) {
+        return m_network_ptr->fault_model->fault_vector(m_id, temperature,
+                                                        fault_vector);
+    }
+    bool get_aggregate_fault_probability(int temperature,
+                                         float *aggregate_fault_prob) {
+        return m_network_ptr->fault_model->fault_prob(m_id, temperature,
+                                                      aggregate_fault_prob);
+    }
+
+    uint32_t functionalWrite(Packet *);
+
+  private:
+    Cycles m_latency;
+    int m_virtual_networks, m_num_vcs, m_vc_per_vnet;
+    GarnetNetwork *m_network_ptr;
+
+    std::vector<InputUnit *> m_input_unit;
+    std::vector<OutputUnit *> m_output_unit;
+    RoutingUnit *m_routing_unit;
+    SwitchAllocator *m_sw_alloc;
+    CrossbarSwitch *m_switch;
+
+    // Statistical variables required for power computations
+    Stats::Scalar m_buffer_reads;
+    Stats::Scalar m_buffer_writes;
+
+    Stats::Scalar m_sw_input_arbiter_activity;
+    Stats::Scalar m_sw_output_arbiter_activity;
+
+    Stats::Scalar m_crossbar_activity;
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_ROUTER_HH__
diff --git a/src/mem/ruby/network/garnet2.0/RoutingUnit.cc b/src/mem/ruby/network/garnet2.0/RoutingUnit.cc
new file mode 100644 (file)
index 0000000..aa5ff53
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/RoutingUnit.hh"
+
+#include "base/cast.hh"
+#include "mem/ruby/network/garnet2.0/InputUnit.hh"
+#include "mem/ruby/network/garnet2.0/Router.hh"
+#include "mem/ruby/slicc_interface/Message.hh"
+
+RoutingUnit::RoutingUnit(Router *router)
+{
+    m_router = router;
+    m_routing_table.clear();
+    m_weight_table.clear();
+}
+
+void
+RoutingUnit::addRoute(const NetDest& routing_table_entry)
+{
+    m_routing_table.push_back(routing_table_entry);
+}
+
+void
+RoutingUnit::addWeight(int link_weight)
+{
+    m_weight_table.push_back(link_weight);
+}
+
+/*
+ * This is the default routing algorithm in garnet.
+ * The routing table is populated during topology creation.
+ * Routes can be biased via weight assignments in the topology file.
+ * Correct weight assignments are critical to provide deadlock avoidance.
+ */
+
+int
+RoutingUnit::lookupRoutingTable(int vnet, NetDest msg_destination)
+{
+    // First find all possible output link candidates
+    // For ordered vnet, just choose the first
+    // (to make sure different packets don't choose different routes)
+    // For unordered vnet, randomly choose any of the links
+    // To have a strict ordering between links, they should be given
+    // different weights in the topology file
+
+    int output_link = -1;
+    int min_weight = INFINITE_;
+    std::vector<int> output_link_candidates;
+    int num_candidates = 0;
+
+    // Identify the minimum weight among the candidate output links
+    for (int link = 0; link < m_routing_table.size(); link++) {
+        if (msg_destination.intersectionIsNotEmpty(m_routing_table[link])) {
+
+        if (m_weight_table[link] <= min_weight)
+            min_weight = m_weight_table[link];
+        }
+    }
+
+    // Collect all candidate output links with this minimum weight
+    for (int link = 0; link < m_routing_table.size(); link++) {
+        if (msg_destination.intersectionIsNotEmpty(m_routing_table[link])) {
+
+            if (m_weight_table[link] == min_weight) {
+
+                num_candidates++;
+                output_link_candidates.push_back(link);
+            }
+        }
+    }
+
+    if (output_link_candidates.size() == 0) {
+        fatal("Fatal Error:: No Route exists from this Router.");
+        exit(0);
+    }
+
+    // Randomly select any candidate output link
+    int candidate = 0;
+    if (!(m_router->get_net_ptr())->isVNetOrdered(vnet))
+        candidate = rand() % num_candidates;
+
+    output_link = output_link_candidates.at(candidate);
+    return output_link;
+}
+
+
+void
+RoutingUnit::addInDirection(PortDirection inport_dirn, int inport_idx)
+{
+    m_inports_dirn2idx[inport_dirn] = inport_idx;
+    m_inports_idx2dirn[inport_idx]  = inport_dirn;
+}
+
+void
+RoutingUnit::addOutDirection(PortDirection outport_dirn, int outport_idx)
+{
+    m_outports_dirn2idx[outport_dirn] = outport_idx;
+    m_outports_idx2dirn[outport_idx]  = outport_dirn;
+}
+
+// outportCompute() is called by the InputUnit
+// It calls the routing table by default.
+// A template for adaptive topology-specific routing algorithm
+// implementations using port directions rather than a static routing
+// table is provided here.
+
+int
+RoutingUnit::outportCompute(RouteInfo route, int inport,
+                            PortDirection inport_dirn)
+{
+    int outport = -1;
+
+    if (route.dest_router == m_router->get_id()) {
+
+        // Multiple NIs may be connected to this router,
+        // all with output port direction = "Local"
+        // Get exact outport id from table
+        outport = lookupRoutingTable(route.vnet, route.net_dest);
+        return outport;
+    }
+
+    // Routing Algorithm set in GarnetNetwork.py
+    // Can be over-ridden from command line using --routing-algorithm = 1
+    RoutingAlgorithm routing_algorithm =
+        (RoutingAlgorithm) m_router->get_net_ptr()->getRoutingAlgorithm();
+
+    switch (routing_algorithm) {
+        case TABLE_:  outport =
+            lookupRoutingTable(route.vnet, route.net_dest); break;
+        case XY_:     outport =
+            outportComputeXY(route, inport, inport_dirn); break;
+        // any custom algorithm
+        case CUSTOM_: outport =
+            outportComputeCustom(route, inport, inport_dirn); break;
+        default: outport =
+            lookupRoutingTable(route.vnet, route.net_dest); break;
+    }
+
+    assert(outport != -1);
+    return outport;
+}
+
+// XY routing implemented using port directions
+// Only for reference purpose in a Mesh
+// By default Garnet uses the routing table
+int
+RoutingUnit::outportComputeXY(RouteInfo route,
+                              int inport,
+                              PortDirection inport_dirn)
+{
+    PortDirection outport_dirn = "Unknown";
+
+    int num_rows = m_router->get_net_ptr()->getNumRows();
+    int num_cols = m_router->get_net_ptr()->getNumCols();
+    assert(num_rows > 0 && num_cols > 0);
+
+    int my_id = m_router->get_id();
+    int my_x = my_id % num_cols;
+    int my_y = my_id / num_cols;
+
+    int dest_id = route.dest_router;
+    int dest_x = dest_id % num_cols;
+    int dest_y = dest_id / num_cols;
+
+    int x_hops = abs(dest_x - my_x);
+    int y_hops = abs(dest_y - my_y);
+
+    bool x_dirn = (dest_x >= my_x);
+    bool y_dirn = (dest_y >= my_y);
+
+    // already checked that in outportCompute() function
+    assert(!(x_hops == 0 && y_hops == 0));
+
+    if (x_hops > 0) {
+        if (x_dirn) {
+            assert(inport_dirn == "Local" || inport_dirn == "West");
+            outport_dirn = "East";
+        } else {
+            assert(inport_dirn == "Local" || inport_dirn == "East");
+            outport_dirn = "West";
+        }
+    } else if (y_hops > 0) {
+        if (y_dirn) {
+            // "Local" or "South" or "West" or "East"
+            assert(inport_dirn != "North");
+            outport_dirn = "North";
+        } else {
+            // "Local" or "North" or "West" or "East"
+            assert(inport_dirn != "South");
+            outport_dirn = "South";
+        }
+    } else {
+        // x_hops == 0 and y_hops == 0
+        // this is not possible
+        // already checked that in outportCompute() function
+        assert(0);
+    }
+
+    return m_outports_dirn2idx[outport_dirn];
+}
+
+// Template for implementing custom routing algorithm
+// using port directions. (Example adaptive)
+int
+RoutingUnit::outportComputeCustom(RouteInfo route,
+                                 int inport,
+                                 PortDirection inport_dirn)
+{
+    assert(0);
+}
diff --git a/src/mem/ruby/network/garnet2.0/RoutingUnit.hh b/src/mem/ruby/network/garnet2.0/RoutingUnit.hh
new file mode 100644 (file)
index 0000000..46b0969
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_ROUTING_UNIT_HH__
+#define __MEM_RUBY_NETWORK_GARNET_ROUTING_UNIT_HH__
+
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/ruby/common/NetDest.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
+#include "mem/ruby/network/garnet2.0/flit.hh"
+
+class InputUnit;
+class Router;
+
+class RoutingUnit
+{
+  public:
+    RoutingUnit(Router *router);
+    int outportCompute(RouteInfo route,
+                      int inport,
+                      PortDirection inport_dirn);
+
+    // Topology-agnostic Routing Table based routing (default)
+    void addRoute(const NetDest& routing_table_entry);
+    void addWeight(int link_weight);
+
+    // get output port from routing table
+    int  lookupRoutingTable(int vnet, NetDest net_dest);
+
+    // Topology-specific direction based routing
+    void addInDirection(PortDirection inport_dirn, int inport);
+    void addOutDirection(PortDirection outport_dirn, int outport);
+
+    // Routing for Mesh
+    int outportComputeXY(RouteInfo route,
+                         int inport,
+                         PortDirection inport_dirn);
+
+    // Custom Routing Algorithm using Port Directions
+    int outportComputeCustom(RouteInfo route,
+                             int inport,
+                             PortDirection inport_dirn);
+
+  private:
+    Router *m_router;
+
+    // Routing Table
+    std::vector<NetDest> m_routing_table;
+    std::vector<int> m_weight_table;
+
+    // Inport and Outport direction to idx maps
+    std::map<PortDirection, int> m_inports_dirn2idx;
+    std::map<int, PortDirection> m_inports_idx2dirn;
+    std::map<int, PortDirection> m_outports_idx2dirn;
+    std::map<PortDirection, int> m_outports_dirn2idx;
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_ROUTING_UNIT_HH__
diff --git a/src/mem/ruby/network/garnet2.0/SConscript b/src/mem/ruby/network/garnet2.0/SConscript
new file mode 100644 (file)
index 0000000..866bab9
--- /dev/null
@@ -0,0 +1,53 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2016 Georgia Institute of Technology
+# 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: Tushar Krishna
+
+Import('*')
+
+if env['PROTOCOL'] == 'None':
+    Return()
+
+SimObject('GarnetLink.py')
+SimObject('GarnetNetwork.py')
+
+Source('GarnetLink.cc')
+Source('GarnetNetwork.cc')
+Source('InputUnit.cc')
+Source('NetworkInterface.cc')
+Source('NetworkLink.cc')
+Source('OutVcState.cc')
+Source('OutputUnit.cc')
+Source('Router.cc')
+Source('RoutingUnit.cc')
+Source('SwitchAllocator.cc')
+Source('CrossbarSwitch.cc')
+Source('VirtualChannel.cc')
+Source('flitBuffer.cc')
+Source('flit.cc')
+Source('Credit.cc')
diff --git a/src/mem/ruby/network/garnet2.0/SwitchAllocator.cc b/src/mem/ruby/network/garnet2.0/SwitchAllocator.cc
new file mode 100644 (file)
index 0000000..7916802
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/SwitchAllocator.hh"
+
+#include "debug/RubyNetwork.hh"
+#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
+#include "mem/ruby/network/garnet2.0/InputUnit.hh"
+#include "mem/ruby/network/garnet2.0/OutputUnit.hh"
+#include "mem/ruby/network/garnet2.0/Router.hh"
+
+SwitchAllocator::SwitchAllocator(Router *router)
+    : Consumer(router)
+{
+    m_router = router;
+    m_num_vcs = m_router->get_num_vcs();
+    m_vc_per_vnet = m_router->get_vc_per_vnet();
+
+    m_input_arbiter_activity = 0;
+    m_output_arbiter_activity = 0;
+}
+
+void
+SwitchAllocator::init()
+{
+    m_input_unit = m_router->get_inputUnit_ref();
+    m_output_unit = m_router->get_outputUnit_ref();
+
+    m_num_inports = m_router->get_num_inports();
+    m_num_outports = m_router->get_num_outports();
+    m_round_robin_inport.resize(m_num_outports);
+    m_round_robin_invc.resize(m_num_inports);
+    m_port_requests.resize(m_num_outports);
+    m_vc_winners.resize(m_num_outports);
+
+    for (int i = 0; i < m_num_inports; i++) {
+        m_round_robin_invc[i] = 0;
+    }
+
+    for (int i = 0; i < m_num_outports; i++) {
+        m_port_requests[i].resize(m_num_inports);
+        m_vc_winners[i].resize(m_num_inports);
+
+        m_round_robin_inport[i] = 0;
+
+        for (int j = 0; j < m_num_inports; j++) {
+            m_port_requests[i][j] = false; // [outport][inport]
+        }
+    }
+}
+
+/*
+ * The wakeup function of the SwitchAllocator performs a 2-stage
+ * seperable switch allocation. At the end of the 2nd stage, a free
+ * output VC is assigned to the winning flits of each output port.
+ * There is no separate VCAllocator stage like the one in garnet1.0.
+ * At the end of this function, the router is rescheduled to wakeup
+ * next cycle for peforming SA for any flits ready next cycle.
+ */
+
+void
+SwitchAllocator::wakeup()
+{
+    arbitrate_inports(); // First stage of allocation
+    arbitrate_outports(); // Second stage of allocation
+
+    clear_request_vector();
+    check_for_wakeup();
+}
+
+/*
+ * SA-I (or SA-i) loops through all input VCs at every input port,
+ * and selects one in a round robin manner.
+ *    - For HEAD/HEAD_TAIL flits only selects an input VC whose output port
+ *     has at least one free output VC.
+ *    - For BODY/TAIL flits, only selects an input VC that has credits
+ *      in its output VC.
+ * Places a request for the output port from this input VC.
+ */
+
+void
+SwitchAllocator::arbitrate_inports()
+{
+    // Select a VC from each input in a round robin manner
+    // Independent arbiter at each input port
+    for (int inport = 0; inport < m_num_inports; inport++) {
+        int invc = m_round_robin_invc[inport];
+
+        // Select next round robin vc candidate within valid vnet
+        int next_round_robin_invc = invc;
+        next_round_robin_invc++;
+        if (next_round_robin_invc >= m_num_vcs)
+            next_round_robin_invc = 0;
+        m_round_robin_invc[inport] = next_round_robin_invc;
+
+        for (int invc_iter = 0; invc_iter < m_num_vcs; invc_iter++) {
+
+            if (m_input_unit[inport]->need_stage(invc, SA_,
+                m_router->curCycle())) {
+
+                // This flit is in SA stage
+
+                int  outport = m_input_unit[inport]->get_outport(invc);
+                int  outvc   = m_input_unit[inport]->get_outvc(invc);
+
+                // check if the flit in this InputVC is allowed to be sent
+                // send_allowed conditions described in that function.
+                bool make_request =
+                    send_allowed(inport, invc, outport, outvc);
+
+                if (make_request) {
+                    m_input_arbiter_activity++;
+                    m_port_requests[outport][inport] = true;
+                    m_vc_winners[outport][inport]= invc;
+                    break; // got one vc winner for this port
+                }
+            }
+
+            invc++;
+            if (invc >= m_num_vcs)
+                invc = 0;
+        }
+    }
+}
+
+/*
+ * SA-II (or SA-o) loops through all output ports,
+ * and selects one input VC (that placed a request during SA-I)
+ * as the winner for this output port in a round robin manner.
+ *      - For HEAD/HEAD_TAIL flits, performs simplified outvc allocation.
+ *        (i.e., select a free VC from the output port).
+ *      - For BODY/TAIL flits, decrement a credit in the output vc.
+ * The winning flit is read out from the input VC and sent to the
+ * CrossbarSwitch.
+ * An increment_credit signal is sent from the InputUnit
+ * to the upstream router. For HEAD_TAIL/TAIL flits, is_free_signal in the
+ * credit is set to true.
+ */
+
+void
+SwitchAllocator::arbitrate_outports()
+{
+    // Now there are a set of input vc requests for output vcs.
+    // Again do round robin arbitration on these requests
+    // Independent arbiter at each output port
+    for (int outport = 0; outport < m_num_outports; outport++) {
+        int inport = m_round_robin_inport[outport];
+        m_round_robin_inport[outport]++;
+
+        if (m_round_robin_inport[outport] >= m_num_inports)
+            m_round_robin_inport[outport] = 0;
+
+        for (int inport_iter = 0; inport_iter < m_num_inports;
+                 inport_iter++) {
+
+            // inport has a request this cycle for outport
+            if (m_port_requests[outport][inport]) {
+
+                // grant this outport to this inport
+                int invc = m_vc_winners[outport][inport];
+
+                int outvc = m_input_unit[inport]->get_outvc(invc);
+                if (outvc == -1) {
+                    // VC Allocation - select any free VC from outport
+                    outvc = vc_allocate(outport, inport, invc);
+                }
+
+                // remove flit from Input VC
+                flit *t_flit = m_input_unit[inport]->getTopFlit(invc);
+
+                DPRINTF(RubyNetwork, "SwitchAllocator at Router %d "
+                                     "granted outvc %d at outport %d "
+                                     "to invc %d at inport %d to flit %s at "
+                                     "time: %lld\n",
+                        m_router->get_id(), outvc,
+                        m_router->getPortDirectionName(
+                            m_output_unit[outport]->get_direction()),
+                        invc,
+                        m_router->getPortDirectionName(
+                            m_input_unit[inport]->get_direction()),
+                            *t_flit,
+                        m_router->curCycle());
+
+
+                // Update outport field in the flit since this is
+                // used by CrossbarSwitch code to send it out of
+                // correct outport.
+                // Note: post route compute in InputUnit,
+                // outport is updated in VC, but not in flit
+                t_flit->set_outport(outport);
+
+                // set outvc (i.e., invc for next hop) in flit
+                // (This was updated in VC by vc_allocate, but not in flit)
+                t_flit->set_vc(outvc);
+
+                // decrement credit in outvc
+                m_output_unit[outport]->decrement_credit(outvc);
+
+                // flit ready for Switch Traversal
+                t_flit->advance_stage(ST_, m_router->curCycle());
+                m_router->grant_switch(inport, t_flit);
+                m_output_arbiter_activity++;
+
+                if ((t_flit->get_type() == TAIL_) ||
+                    t_flit->get_type() == HEAD_TAIL_) {
+
+                    // This Input VC should now be empty
+                    assert(!(m_input_unit[inport]->isReady(invc,
+                        m_router->curCycle())));
+
+                    // Free this VC
+                    m_input_unit[inport]->set_vc_idle(invc,
+                        m_router->curCycle());
+
+                    // Send a credit back
+                    // along with the information that this VC is now idle
+                    m_input_unit[inport]->increment_credit(invc, true,
+                        m_router->curCycle());
+                } else {
+                    // Send a credit back
+                    // but do not indicate that the VC is idle
+                    m_input_unit[inport]->increment_credit(invc, false,
+                        m_router->curCycle());
+                }
+
+                // remove this request
+                m_port_requests[outport][inport] = false;
+
+                break; // got a input winner for this outport
+            }
+
+            inport++;
+            if (inport >= m_num_inports)
+                inport = 0;
+        }
+    }
+}
+
+/*
+ * A flit can be sent only if
+ * (1) there is at least one free output VC at the
+ *     output port (for HEAD/HEAD_TAIL),
+ *  or
+ * (2) if there is at least one credit (i.e., buffer slot)
+ *     within the VC for BODY/TAIL flits of multi-flit packets.
+ * and
+ * (3) pt-to-pt ordering is not violated in ordered vnets, i.e.,
+ *     there should be no other flit in this input port
+ *     within an ordered vnet
+ *     that arrived before this flit and is requesting the same output port.
+ */
+
+bool
+SwitchAllocator::send_allowed(int inport, int invc, int outport, int outvc)
+{
+    // Check if outvc needed
+    // Check if credit needed (for multi-flit packet)
+    // Check if ordering violated (in ordered vnet)
+
+    int vnet = get_vnet(invc);
+    bool has_outvc = (outvc != -1);
+    bool has_credit = false;
+
+    if (!has_outvc) {
+
+        // needs outvc
+        // this is only true for HEAD and HEAD_TAIL flits.
+
+        if (m_output_unit[outport]->has_free_vc(vnet)) {
+
+            has_outvc = true;
+
+            // each VC has at least one buffer,
+            // so no need for additional credit check
+            has_credit = true;
+        }
+    } else {
+        has_credit = m_output_unit[outport]->has_credit(outvc);
+    }
+
+    // cannot send if no outvc or no credit.
+    if (!has_outvc || !has_credit)
+        return false;
+
+
+    // protocol ordering check
+    if ((m_router->get_net_ptr())->isVNetOrdered(vnet)) {
+
+        // enqueue time of this flit
+        Cycles t_enqueue_time = m_input_unit[inport]->get_enqueue_time(invc);
+
+        // check if any other flit is ready for SA and for same output port
+        // and was enqueued before this flit
+        int vc_base = vnet*m_vc_per_vnet;
+        for (int vc_offset = 0; vc_offset < m_vc_per_vnet; vc_offset++) {
+            int temp_vc = vc_base + vc_offset;
+            if (m_input_unit[inport]->need_stage(temp_vc, SA_,
+                                                 m_router->curCycle()) &&
+               (m_input_unit[inport]->get_outport(temp_vc) == outport) &&
+               (m_input_unit[inport]->get_enqueue_time(temp_vc) <
+                    t_enqueue_time)) {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+// Assign a free VC to the winner of the output port.
+int
+SwitchAllocator::vc_allocate(int outport, int inport, int invc)
+{
+    // Select a free VC from the output port
+    int outvc = m_output_unit[outport]->select_free_vc(get_vnet(invc));
+
+    // has to get a valid VC since it checked before performing SA
+    assert(outvc != -1);
+    m_input_unit[inport]->grant_outvc(invc, outvc);
+    return outvc;
+}
+
+// Wakeup the router next cycle to perform SA again
+// if there are flits ready.
+void
+SwitchAllocator::check_for_wakeup()
+{
+    Cycles nextCycle = m_router->curCycle() + Cycles(1);
+
+    for (int i = 0; i < m_num_inports; i++) {
+        for (int j = 0; j < m_num_vcs; j++) {
+            if (m_input_unit[i]->need_stage(j, SA_, nextCycle)) {
+                m_router->schedule_wakeup(Cycles(1));
+                return;
+            }
+        }
+    }
+}
+
+int
+SwitchAllocator::get_vnet(int invc)
+{
+    int vnet = invc/m_vc_per_vnet;
+    assert(vnet < m_router->get_num_vnets());
+    return vnet;
+}
+
+
+// Clear the request vector within the allocator at end of SA-II.
+// Was populated by SA-I.
+void
+SwitchAllocator::clear_request_vector()
+{
+    for (int i = 0; i < m_num_outports; i++) {
+        for (int j = 0; j < m_num_inports; j++) {
+            m_port_requests[i][j] = false;
+        }
+    }
+}
diff --git a/src/mem/ruby/network/garnet2.0/SwitchAllocator.hh b/src/mem/ruby/network/garnet2.0/SwitchAllocator.hh
new file mode 100644 (file)
index 0000000..162264e
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_SWITCH_ALLOCATOR_HH__
+#define __MEM_RUBY_NETWORK_GARNET_SWITCH_ALLOCATOR_HH__
+
+#include <iostream>
+#include <vector>
+
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+
+class Router;
+class InputUnit;
+class OutputUnit;
+
+class SwitchAllocator : public Consumer
+{
+  public:
+    SwitchAllocator(Router *router);
+    void wakeup();
+    void init();
+    void clear_request_vector();
+    void check_for_wakeup();
+    int get_vnet (int invc);
+    void print(std::ostream& out) const {};
+    void arbitrate_inports();
+    void arbitrate_outports();
+    bool send_allowed(int inport, int invc, int outport, int outvc);
+    int vc_allocate(int outport, int inport, int invc);
+
+    inline double
+    get_input_arbiter_activity()
+    {
+        return m_input_arbiter_activity;
+    }
+    inline double
+    get_output_arbiter_activity()
+    {
+        return m_output_arbiter_activity;
+    }
+
+  private:
+    int m_num_inports, m_num_outports;
+    int m_num_vcs, m_vc_per_vnet;
+
+    double m_input_arbiter_activity, m_output_arbiter_activity;
+
+    Router *m_router;
+    std::vector<int> m_round_robin_invc;
+    std::vector<int> m_round_robin_inport;
+    std::vector<std::vector<bool>> m_port_requests;
+    std::vector<std::vector<int>> m_vc_winners; // a list for each outport
+    std::vector<InputUnit *> m_input_unit;
+    std::vector<OutputUnit *> m_output_unit;
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_SWITCH_ALLOCATOR_HH__
diff --git a/src/mem/ruby/network/garnet2.0/VirtualChannel.cc b/src/mem/ruby/network/garnet2.0/VirtualChannel.cc
new file mode 100644 (file)
index 0000000..55f2a87
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/VirtualChannel.hh"
+
+VirtualChannel::VirtualChannel(int id)
+    : m_enqueue_time(INFINITE_)
+{
+    m_id = id;
+    m_input_buffer = new flitBuffer();
+    m_vc_state.first = IDLE_;
+    m_vc_state.second = Cycles(0);
+    m_output_vc = -1;
+    m_output_port = -1;
+}
+
+VirtualChannel::~VirtualChannel()
+{
+    delete m_input_buffer;
+}
+
+void
+VirtualChannel::set_idle(Cycles curTime)
+{
+    m_vc_state.first = IDLE_;
+    m_vc_state.second = curTime;
+    m_enqueue_time = Cycles(INFINITE_);
+    m_output_port = -1;
+    m_output_vc = -1;
+}
+
+void
+VirtualChannel::set_active(Cycles curTime)
+{
+    m_vc_state.first = ACTIVE_;
+    m_vc_state.second = curTime;
+    m_enqueue_time = curTime;
+}
+
+bool
+VirtualChannel::need_stage(flit_stage stage, Cycles time)
+{
+    if (m_input_buffer->isReady(time)) {
+        assert(m_vc_state.first == ACTIVE_ && m_vc_state.second <= time);
+        flit *t_flit = m_input_buffer->peekTopFlit();
+        return(t_flit->is_stage(stage, time));
+    }
+    return false;
+}
+
+uint32_t
+VirtualChannel::functionalWrite(Packet *pkt)
+{
+    return m_input_buffer->functionalWrite(pkt);
+}
diff --git a/src/mem/ruby/network/garnet2.0/VirtualChannel.hh b/src/mem/ruby/network/garnet2.0/VirtualChannel.hh
new file mode 100644 (file)
index 0000000..d5f7687
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_VIRTUAL_CHANNEL_HH__
+#define __MEM_RUBY_NETWORK_GARNET_VIRTUAL_CHANNEL_HH__
+
+#include <utility>
+
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/flitBuffer.hh"
+
+class VirtualChannel
+{
+  public:
+    VirtualChannel(int id);
+    ~VirtualChannel();
+
+    bool need_stage(flit_stage stage, Cycles time);
+    void set_idle(Cycles curTime);
+    void set_active(Cycles curTime);
+    void set_outvc(int outvc)               { m_output_vc = outvc; }
+    inline int get_outvc()                  { return m_output_vc; }
+    void set_outport(int outport)           { m_output_port = outport; };
+    inline int get_outport()                  { return m_output_port; }
+
+    inline Cycles get_enqueue_time()          { return m_enqueue_time; }
+    inline void set_enqueue_time(Cycles time) { m_enqueue_time = time; }
+    inline VC_state_type get_state()        { return m_vc_state.first; }
+
+    inline bool isReady(Cycles curTime)
+    {
+        return m_input_buffer->isReady(curTime);
+    }
+
+    inline void
+    insertFlit(flit *t_flit)
+    {
+        m_input_buffer->insert(t_flit);
+    }
+
+    inline void
+    set_state(VC_state_type m_state, Cycles curTime)
+    {
+        m_vc_state.first = m_state;
+        m_vc_state.second = curTime;
+    }
+
+    inline flit*
+    peekTopFlit()
+    {
+        return m_input_buffer->peekTopFlit();
+    }
+
+    inline flit*
+    getTopFlit()
+    {
+        return m_input_buffer->getTopFlit();
+    }
+
+    uint32_t functionalWrite(Packet *pkt);
+
+  private:
+    int m_id;
+    flitBuffer *m_input_buffer;
+    std::pair<VC_state_type, Cycles> m_vc_state;
+    int m_output_port;
+    Cycles m_enqueue_time;
+    int m_output_vc;
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET_VIRTUAL_CHANNEL_HH__
diff --git a/src/mem/ruby/network/garnet2.0/flit.cc b/src/mem/ruby/network/garnet2.0/flit.cc
new file mode 100644 (file)
index 0000000..e507ea4
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/flit.hh"
+
+// Constructor for the flit
+flit::flit(int id, int  vc, int vnet, RouteInfo route, int size,
+    MsgPtr msg_ptr, Cycles curTime)
+{
+    m_size = size;
+    m_msg_ptr = msg_ptr;
+    m_enqueue_time = curTime;
+    m_time = curTime;
+    m_id = id;
+    m_vnet = vnet;
+    m_vc = vc;
+    m_route = route;
+    m_stage.first = I_;
+    m_stage.second = m_time;
+
+    if (size == 1) {
+        m_type = HEAD_TAIL_;
+        return;
+    }
+    if (id == 0)
+        m_type = HEAD_;
+    else if (id == (size - 1))
+        m_type = TAIL_;
+    else
+        m_type = BODY_;
+}
+
+// Flit can be printed out for debugging purposes
+void
+flit::print(std::ostream& out) const
+{
+    out << "[flit:: ";
+    out << "Id=" << m_id << " ";
+    out << "Type=" << m_type << " ";
+    out << "Vnet=" << m_vnet << " ";
+    out << "VC=" << m_vc << " ";
+    out << "Src NI=" << m_route.src_ni << " ";
+    out << "Src Router=" << m_route.src_router << " ";
+    out << "Dest NI=" << m_route.dest_ni << " ";
+    out << "Dest Router=" << m_route.dest_router << " ";
+    out << "Enqueue Time=" << m_enqueue_time << " ";
+    out << "]";
+}
+
+bool
+flit::functionalWrite(Packet *pkt)
+{
+    Message *msg = m_msg_ptr.get();
+    return msg->functionalWrite(pkt);
+}
diff --git a/src/mem/ruby/network/garnet2.0/flit.hh b/src/mem/ruby/network/garnet2.0/flit.hh
new file mode 100644 (file)
index 0000000..3e30ec9
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_FLIT_HH__
+#define __MEM_RUBY_NETWORK_GARNET_FLIT_HH__
+
+#include <cassert>
+#include <iostream>
+
+#include "base/types.hh"
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/slicc_interface/Message.hh"
+
+class flit
+{
+  public:
+    flit() {}
+    flit(int id, int vc, int vnet, RouteInfo route, int size,
+         MsgPtr msg_ptr, Cycles curTime);
+
+    int get_outport() {return m_outport; }
+    int get_size() { return m_size; }
+    Cycles get_enqueue_time() { return m_enqueue_time; }
+    int get_id() { return m_id; }
+    Cycles get_time() { return m_time; }
+    int get_vnet() { return m_vnet; }
+    int get_vc() { return m_vc; }
+    RouteInfo get_route() { return m_route; }
+    MsgPtr& get_msg_ptr() { return m_msg_ptr; }
+    flit_type get_type() { return m_type; }
+    std::pair<flit_stage, Cycles> get_stage() { return m_stage; }
+    Cycles get_src_delay() { return src_delay; }
+
+    void set_outport(int port) { m_outport = port; }
+    void set_time(Cycles time) { m_time = time; }
+    void set_vc(int vc) { m_vc = vc; }
+    void set_route(RouteInfo route) { m_route = route; }
+    void set_src_delay(Cycles delay) { src_delay = delay; }
+
+    void increment_hops() { m_route.hops_traversed++; }
+    void print(std::ostream& out) const;
+
+    bool
+    is_stage(flit_stage stage, Cycles time)
+    {
+        return (stage == m_stage.first &&
+                time >= m_stage.second);
+    }
+
+    void
+    advance_stage(flit_stage t_stage, Cycles newTime)
+    {
+        m_stage.first = t_stage;
+        m_stage.second = newTime;
+    }
+
+    static bool
+    greater(flit* n1, flit* n2)
+    {
+        if (n1->get_time() == n2->get_time()) {
+            //assert(n1->flit_id != n2->flit_id);
+            return (n1->get_id() > n2->get_id());
+        } else {
+            return (n1->get_time() > n2->get_time());
+        }
+    }
+
+    bool functionalWrite(Packet *pkt);
+
+  protected:
+    int m_id;
+    int m_vnet;
+    int m_vc;
+    RouteInfo m_route;
+    int m_size;
+    Cycles m_enqueue_time, m_time;
+    flit_type m_type;
+    MsgPtr m_msg_ptr;
+    int m_outport;
+    Cycles src_delay;
+    std::pair<flit_stage, Cycles> m_stage;
+};
+
+inline std::ostream&
+operator<<(std::ostream& out, const flit& obj)
+{
+    obj.print(out);
+    out << std::flush;
+    return out;
+}
+
+#endif // __MEM_RUBY_NETWORK_GARNET_FLIT_HH__
diff --git a/src/mem/ruby/network/garnet2.0/flitBuffer.cc b/src/mem/ruby/network/garnet2.0/flitBuffer.cc
new file mode 100644 (file)
index 0000000..1a08993
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#include "mem/ruby/network/garnet2.0/flitBuffer.hh"
+
+flitBuffer::flitBuffer()
+{
+    max_size = INFINITE_;
+}
+
+flitBuffer::flitBuffer(int maximum_size)
+{
+    max_size = maximum_size;
+}
+
+bool
+flitBuffer::isEmpty()
+{
+    return (m_buffer.size() == 0);
+}
+
+bool
+flitBuffer::isReady(Cycles curTime)
+{
+    if (m_buffer.size() != 0 ) {
+        flit *t_flit = peekTopFlit();
+        if (t_flit->get_time() <= curTime)
+            return true;
+    }
+    return false;
+}
+
+void
+flitBuffer::print(std::ostream& out) const
+{
+    out << "[flitBuffer: " << m_buffer.size() << "] " << std::endl;
+}
+
+bool
+flitBuffer::isFull()
+{
+    return (m_buffer.size() >= max_size);
+}
+
+void
+flitBuffer::setMaxSize(int maximum)
+{
+    max_size = maximum;
+}
+
+uint32_t
+flitBuffer::functionalWrite(Packet *pkt)
+{
+    uint32_t num_functional_writes = 0;
+
+    for (unsigned int i = 0; i < m_buffer.size(); ++i) {
+        if (m_buffer[i]->functionalWrite(pkt)) {
+            num_functional_writes++;
+        }
+    }
+
+    return num_functional_writes;
+}
diff --git a/src/mem/ruby/network/garnet2.0/flitBuffer.hh b/src/mem/ruby/network/garnet2.0/flitBuffer.hh
new file mode 100644 (file)
index 0000000..eb6ad61
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2008 Princeton University
+ * Copyright (c) 2016 Georgia Institute of Technology
+ * 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: Niket Agarwal
+ *          Tushar Krishna
+ */
+
+
+#ifndef __MEM_RUBY_NETWORK_GARNET_FLIT_BUFFER_HH__
+#define __MEM_RUBY_NETWORK_GARNET_FLIT_BUFFER_HH__
+
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/flit.hh"
+
+class flitBuffer
+{
+  public:
+    flitBuffer();
+    flitBuffer(int maximum_size);
+
+    bool isReady(Cycles curTime);
+    bool isEmpty();
+    void print(std::ostream& out) const;
+    bool isFull();
+    void setMaxSize(int maximum);
+
+    flit *
+    getTopFlit()
+    {
+        flit *f = m_buffer.front();
+        std::pop_heap(m_buffer.begin(), m_buffer.end(), flit::greater);
+        m_buffer.pop_back();
+        return f;
+    }
+
+    flit *
+    peekTopFlit()
+    {
+        return m_buffer.front();
+    }
+
+    void
+    insert(flit *flt)
+    {
+        m_buffer.push_back(flt);
+        std::push_heap(m_buffer.begin(), m_buffer.end(), flit::greater);
+    }
+
+    uint32_t functionalWrite(Packet *pkt);
+
+  private:
+    std::vector<flit *> m_buffer;
+    int max_size;
+};
+
+inline std::ostream&
+operator<<(std::ostream& out, const flitBuffer& obj)
+{
+    obj.print(out);
+    out << std::flush;
+    return out;
+}
+
+#endif // __MEM_RUBY_NETWORK_GARNET_FLIT_BUFFER_HH__