mem-garnet: Integration of HeteroGarnet
authorSrikant Bharadwaj <srikant.bharadwaj@amd.com>
Thu, 19 Jul 2018 17:34:24 +0000 (13:34 -0400)
committerSrikant Bharadwaj <srikant.bharadwaj@amd.com>
Fri, 4 Sep 2020 22:17:36 +0000 (22:17 +0000)
This upgrades the garnet model to support HeteroGarnet
1) Static and dynamic multi-freq domains in network
2) Support for CDC
3) Separate links for each message class
4) Separate linkwidth for each message class
5) Support for SerDes

Change-Id: I6d00e3b5cb3745e849d221066cb46b2138c47871
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/32597
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
45 files changed:
configs/example/garnet_synth_traffic.py
configs/network/Network.py
src/mem/ruby/common/Consumer.hh
src/mem/ruby/network/BasicLink.cc
src/mem/ruby/network/BasicLink.hh
src/mem/ruby/network/BasicLink.py
src/mem/ruby/network/Network.cc
src/mem/ruby/network/Network.hh
src/mem/ruby/network/Topology.cc
src/mem/ruby/network/Topology.hh
src/mem/ruby/network/garnet2.0/CommonTypes.hh
src/mem/ruby/network/garnet2.0/Credit.cc
src/mem/ruby/network/garnet2.0/Credit.hh
src/mem/ruby/network/garnet2.0/CrossbarSwitch.cc
src/mem/ruby/network/garnet2.0/GarnetLink.cc
src/mem/ruby/network/garnet2.0/GarnetLink.hh
src/mem/ruby/network/garnet2.0/GarnetLink.py
src/mem/ruby/network/garnet2.0/GarnetNetwork.cc
src/mem/ruby/network/garnet2.0/GarnetNetwork.hh
src/mem/ruby/network/garnet2.0/GarnetNetwork.py
src/mem/ruby/network/garnet2.0/InputUnit.cc
src/mem/ruby/network/garnet2.0/InputUnit.hh
src/mem/ruby/network/garnet2.0/NetworkBridge.cc [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/NetworkBridge.hh [new file with mode: 0644]
src/mem/ruby/network/garnet2.0/NetworkInterface.cc
src/mem/ruby/network/garnet2.0/NetworkInterface.hh
src/mem/ruby/network/garnet2.0/NetworkLink.cc
src/mem/ruby/network/garnet2.0/NetworkLink.hh
src/mem/ruby/network/garnet2.0/OutVcState.hh
src/mem/ruby/network/garnet2.0/OutputUnit.cc
src/mem/ruby/network/garnet2.0/OutputUnit.hh
src/mem/ruby/network/garnet2.0/Router.cc
src/mem/ruby/network/garnet2.0/Router.hh
src/mem/ruby/network/garnet2.0/RoutingUnit.cc
src/mem/ruby/network/garnet2.0/RoutingUnit.hh
src/mem/ruby/network/garnet2.0/SConscript
src/mem/ruby/network/garnet2.0/SwitchAllocator.cc
src/mem/ruby/network/garnet2.0/VirtualChannel.cc
src/mem/ruby/network/garnet2.0/VirtualChannel.hh
src/mem/ruby/network/garnet2.0/flit.cc
src/mem/ruby/network/garnet2.0/flit.hh
src/mem/ruby/network/garnet2.0/flitBuffer.cc
src/mem/ruby/network/garnet2.0/flitBuffer.hh
src/mem/ruby/network/simple/SimpleNetwork.cc
src/mem/ruby/network/simple/SimpleNetwork.hh

index 9878c23f1cf153691b953d9dc60ad49872b6fa58..c56e1a80010402a2f4aeaa00b3ba73c5126c7765 100644 (file)
@@ -145,7 +145,7 @@ root = Root(full_system = False, system = system)
 root.system.mem_mode = 'timing'
 
 # Not much point in this being higher than the L1 latency
-m5.ticks.setGlobalFrequency('1ns')
+m5.ticks.setGlobalFrequency('1ps')
 
 # instantiate configuration
 m5.instantiate()
index 96cc91358d2902dfb8c2079212c46778f7611da2..20d68c0ae9b549e69556d98b05ecedd6e3bb767c 100644 (file)
@@ -75,7 +75,6 @@ def define_options(parser):
                       type="int", default=50000,
                       help="network-level deadlock threshold.")
 
-
 def create_network(options, ruby):
 
     # Set the network classes based on the command line options
@@ -109,6 +108,70 @@ def init_network(options, network, InterfaceClass):
         network.routing_algorithm = options.routing_algorithm
         network.garnet_deadlock_threshold = options.garnet_deadlock_threshold
 
+        # Create Bridges and connect them to the corresponding links
+        for intLink in network.int_links:
+            intLink.src_net_bridge = NetworkBridge(
+                                     link = intLink.network_link,
+                                     vtype = 'OBJECT_LINK',
+                                     width = intLink.src_node.width)
+            intLink.src_cred_bridge = NetworkBridge(
+                                    link = intLink.credit_link,
+                                    vtype = 'LINK_OBJECT',
+                                    width = intLink.src_node.width)
+            intLink.dst_net_bridge = NetworkBridge(
+                                   link = intLink.network_link,
+                                   vtype = 'LINK_OBJECT',
+                                     width = intLink.dst_node.width)
+            intLink.dst_cred_bridge = NetworkBridge(
+                                    link = intLink.credit_link,
+                                    vtype = 'OBJECT_LINK',
+                                    width = intLink.dst_node.width)
+
+        for extLink in network.ext_links:
+            ext_net_bridges = []
+            ext_net_bridges.append(NetworkBridge(link =
+                                 extLink.network_links[0],
+                                 vtype = 'OBJECT_LINK',
+                                 width = extLink.width))
+            ext_net_bridges.append(NetworkBridge(link =
+                                 extLink.network_links[1],
+                                 vtype = 'LINK_OBJECT',
+                                 width = extLink.width))
+            extLink.ext_net_bridge = ext_net_bridges
+
+            ext_credit_bridges = []
+            ext_credit_bridges.append(NetworkBridge(link =
+                                    extLink.credit_links[0],
+                                    vtype = 'LINK_OBJECT',
+                                    width = extLink.width))
+            ext_credit_bridges.append(NetworkBridge(link =
+                                    extLink.credit_links[1],
+                                    vtype = 'OBJECT_LINK',
+                                    width = extLink.width))
+            extLink.ext_cred_bridge = ext_credit_bridges
+
+            int_net_bridges = []
+            int_net_bridges.append(NetworkBridge(link =
+                                 extLink.network_links[0],
+                                 vtype = 'LINK_OBJECT',
+                                 width = extLink.int_node.width))
+            int_net_bridges.append(NetworkBridge(link =
+                                 extLink.network_links[1],
+                                 vtype = 'OBJECT_LINK',
+                                 width = extLink.int_node.width))
+            extLink.int_net_bridge = int_net_bridges
+
+            int_cred_bridges = []
+            int_cred_bridges.append(NetworkBridge(link =
+                                  extLink.credit_links[0],
+                                  vtype = 'OBJECT_LINK',
+                                  width = extLink.int_node.width))
+            int_cred_bridges.append(NetworkBridge(link =
+                                  extLink.credit_links[1],
+                                  vtype = 'LINK_OBJECT',
+                                  width = extLink.int_node.width))
+            extLink.int_cred_bridge = int_cred_bridges
+
     if options.network == "simple":
         network.setup_buffers()
 
index b0d35bf70c1262167d188fb143de5caab1763816..2e18684031e28dcbd8eef1c282fcc72eae1e32ab 100644 (file)
@@ -68,9 +68,14 @@ class Consumer
         m_scheduled_wakeups.insert(time);
     }
 
-    void scheduleEventAbsolute(Tick timeAbs);
+    ClockedObject *
+    getObject()
+    {
+        return em;
+    }
 
-  protected:
+
+    void scheduleEventAbsolute(Tick timeAbs);
     void scheduleEvent(Cycles timeDelta);
 
   private:
index 2b55e7ec8367edf98a7fce843d20fd08d0128a01..b1691cd55208b87e9848e0b4a7a97b8a49f1c7ba 100644 (file)
@@ -34,6 +34,7 @@ BasicLink::BasicLink(const Params *p)
     m_latency = p->latency;
     m_bandwidth_factor = p->bandwidth_factor;
     m_weight = p->weight;
+    mVnets = p->supported_vnets;
 }
 
 void
index 755e5c7a7aa500a862fcc36fdede353827d64fb5..dfa94b8500afcbe50857730a77748f4273556ae8 100644 (file)
@@ -56,6 +56,7 @@ class BasicLink : public SimObject
     Cycles m_latency;
     int m_bandwidth_factor;
     int m_weight;
+    std::vector<int> mVnets;
 };
 
 inline std::ostream&
index ff3e03a098cfc75203ddc5f626a88645697a73c3..9d6a7bb158fa057a202d925dca7255d327806cf2 100644 (file)
@@ -37,6 +37,7 @@ class BasicLink(SimObject):
     # Garnet models this by flit size
     bandwidth_factor = Param.Int("generic bandwidth factor, usually in bytes")
     weight = Param.Int(1, "used to restrict routing in shortest path analysis")
+    supported_vnets = VectorParam.Int([], "Vnets supported Default:All([])")
 
 class BasicExtLink(BasicLink):
     type = 'BasicExtLink'
index bf3b637c355a886cf37dec824b1bae1e2cf87bc1..cda99b19636590c91cd4ff00d5b9e8ce115fc487 100644 (file)
@@ -90,8 +90,9 @@ Network::Network(const Params *p)
     assert(m_nodes != 0);
     assert(m_virtual_networks != 0);
 
-    m_topology_ptr = new Topology(p->routers.size(), p->ext_links,
-                                  p->int_links);
+    m_topology_ptr = new Topology(m_nodes, p->routers.size(),
+                                  m_virtual_networks,
+                                  p->ext_links, p->int_links);
 
     // Allocate to and from queues
     // Queues that are getting messages from protocol
index 6348f6c47f22170cdf0bfb1eab5f8fb380639eec..f151aed9423455dd9ffae517f13569898a4f6b97 100644 (file)
@@ -99,11 +99,11 @@ class Network : public ClockedObject
                                        int network_num, std::string vnet_type);
 
     virtual void makeExtOutLink(SwitchID src, NodeID dest, BasicLink* link,
-                             const NetDest& routing_table_entry) = 0;
+                             std::vector<NetDest>& routing_table_entry) = 0;
     virtual void makeExtInLink(NodeID src, SwitchID dest, BasicLink* link,
-                            const NetDest& routing_table_entry) = 0;
+                            std::vector<NetDest>& routing_table_entry) = 0;
     virtual void makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
-                                  const NetDest& routing_table_entry,
+                                  std::vector<NetDest>& routing_table_entry,
                                   PortDirection src_outport,
                                   PortDirection dst_inport) = 0;
 
index 6da251e0bf71bab2bc98c78834603afa79e6ea9e..13219a54762945f223e446b6af79d7bf138299c5 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
  * All rights reserved.
  *
@@ -48,11 +49,12 @@ const int INFINITE_LATENCY = 10000; // Yes, this is a big hack
 // the second m_nodes set of SwitchIDs represent the the output queues
 // of the network.
 
-Topology::Topology(uint32_t num_routers,
+Topology::Topology(uint32_t num_nodes, uint32_t num_routers,
+                   uint32_t num_vnets,
                    const vector<BasicExtLink *> &ext_links,
                    const vector<BasicIntLink *> &int_links)
     : m_nodes(MachineType_base_number(MachineType_NUM)),
-      m_number_of_switches(num_routers),
+      m_number_of_switches(num_routers), m_vnets(num_vnets),
       m_ext_link_vector(ext_links), m_int_link_vector(int_links)
 {
     // Total nodes/controllers in network
@@ -119,40 +121,88 @@ Topology::createLinks(Network *net)
 
     // Initialize weight, latency, and inter switched vectors
     int num_switches = max_switch_id+1;
-    Matrix topology_weights(num_switches,
-            vector<int>(num_switches, INFINITE_LATENCY));
+    Matrix topology_weights(m_vnets,
+            vector<vector<int>>(num_switches,
+            vector<int>(num_switches, INFINITE_LATENCY)));
     Matrix component_latencies(num_switches,
-            vector<int>(num_switches, -1));
+            vector<vector<int>>(num_switches,
+            vector<int>(m_vnets, -1)));
     Matrix component_inter_switches(num_switches,
-            vector<int>(num_switches, 0));
+            vector<vector<int>>(num_switches,
+            vector<int>(m_vnets, 0)));
 
     // Set identity weights to zero
-    for (int i = 0; i < topology_weights.size(); i++) {
-        topology_weights[i][i] = 0;
+    for (int i = 0; i < topology_weights[0].size(); i++) {
+        for (int v = 0; v < m_vnets; v++) {
+            topology_weights[v][i][i] = 0;
+        }
     }
 
     // Fill in the topology weights and bandwidth multipliers
-    for (LinkMap::const_iterator i = m_link_map.begin();
-         i != m_link_map.end(); ++i) {
-        std::pair<int, int> src_dest = (*i).first;
-        BasicLink* link = (*i).second.link;
+    for (auto link_group : m_link_map) {
+        std::pair<int, int> src_dest = link_group.first;
+        vector<bool> vnet_done(m_vnets, 0);
         int src = src_dest.first;
         int dst = src_dest.second;
-        component_latencies[src][dst] = link->m_latency;
-        topology_weights[src][dst] = link->m_weight;
+
+        // Iterate over all links for this source and destination
+        std::vector<LinkEntry> link_entries = link_group.second;
+        for (int l = 0; l < link_entries.size(); l++) {
+            BasicLink* link = link_entries[l].link;
+            if (link->mVnets.size() == 0) {
+                for (int v = 0; v < m_vnets; v++) {
+                    // Two links connecting same src and destination
+                    // cannot carry same vnets.
+                    fatal_if(vnet_done[v], "Two links connecting same src"
+                    " and destination cannot support same vnets");
+
+                    component_latencies[src][dst][v] = link->m_latency;
+                    topology_weights[v][src][dst] = link->m_weight;
+                    vnet_done[v] = true;
+                }
+            } else {
+                for (int v = 0; v < link->mVnets.size(); v++) {
+                    int vnet = link->mVnets[v];
+                    // Two links connecting same src and destination
+                    // cannot carry same vnets.
+                    fatal_if(vnet_done[vnet], "Two links connecting same src"
+                    " and destination cannot support same vnets");
+
+                    component_latencies[src][dst][vnet] = link->m_latency;
+                    topology_weights[vnet][src][dst] = link->m_weight;
+                    vnet_done[vnet] = true;
+                }
+            }
+        }
     }
 
     // Walk topology and hookup the links
     Matrix dist = shortest_path(topology_weights, component_latencies,
                                 component_inter_switches);
 
-    for (int i = 0; i < topology_weights.size(); i++) {
-        for (int j = 0; j < topology_weights[i].size(); j++) {
-            int weight = topology_weights[i][j];
-            if (weight > 0 && weight != INFINITE_LATENCY) {
-                NetDest destination_set =
-                        shortest_path_to_node(i, j, topology_weights, dist);
-                makeLink(net, i, j, destination_set);
+    for (int i = 0; i < topology_weights[0].size(); i++) {
+        for (int j = 0; j < topology_weights[0][i].size(); j++) {
+            std::vector<NetDest> routingMap;
+            routingMap.resize(m_vnets);
+
+            // Not all sources and destinations are connected
+            // by direct links. We only construct the links
+            // which have been configured in topology.
+            bool realLink = false;
+
+            for (int v = 0; v < m_vnets; v++) {
+                int weight = topology_weights[v][i][j];
+                if (weight > 0 && weight != INFINITE_LATENCY) {
+                    realLink = true;
+                    routingMap[v] =
+                        shortest_path_to_node(i, j, topology_weights, dist, v);
+                }
+            }
+            // Make one link for each set of vnets between
+            // a given source and destination. We do not
+            // want to create one link for each vnet.
+            if (realLink) {
+                makeLink(net, i, j, routingMap);
             }
         }
     }
@@ -167,19 +217,32 @@ Topology::addLink(SwitchID src, SwitchID dest, BasicLink* link,
     assert(dest <= m_number_of_switches+m_nodes+m_nodes);
 
     std::pair<int, int> src_dest_pair;
-    LinkEntry link_entry;
-
     src_dest_pair.first = src;
     src_dest_pair.second = dest;
+    LinkEntry link_entry;
+
     link_entry.link = link;
     link_entry.src_outport_dirn = src_outport_dirn;
     link_entry.dst_inport_dirn  = dst_inport_dirn;
-    m_link_map[src_dest_pair] = link_entry;
+
+    auto lit = m_link_map.find(src_dest_pair);
+    if (lit != m_link_map.end()) {
+        // HeteroGarnet allows multiple links between
+        // same source-destination pair supporting
+        // different vnets. If there is a link already
+        // between a given pair of source and destination
+        // add this new link to it.
+        lit->second.push_back(link_entry);
+    } else {
+        std::vector<LinkEntry> links;
+        links.push_back(link_entry);
+        m_link_map[src_dest_pair] = links;
+    }
 }
 
 void
 Topology::makeLink(Network *net, SwitchID src, SwitchID dest,
-                   const NetDest& routing_table_entry)
+                   std::vector<NetDest>& routing_table_entry)
 {
     // Make sure we're not trying to connect two end-point nodes
     // directly together
@@ -191,27 +254,73 @@ Topology::makeLink(Network *net, SwitchID src, SwitchID dest,
     if (src < m_nodes) {
         src_dest.first = src;
         src_dest.second = dest;
-        link_entry = m_link_map[src_dest];
-        net->makeExtInLink(src, dest - (2 * m_nodes), link_entry.link,
-                        routing_table_entry);
+        std::vector<LinkEntry> links = m_link_map[src_dest];
+        for (int l = 0; l < links.size(); l++) {
+            link_entry = links[l];
+            std::vector<NetDest> linkRoute;
+            linkRoute.resize(m_vnets);
+            BasicLink *link = link_entry.link;
+            if (link->mVnets.size() == 0) {
+                net->makeExtInLink(src, dest - (2 * m_nodes), link,
+                                routing_table_entry);
+            } else {
+                for (int v = 0; v< link->mVnets.size(); v++) {
+                    int vnet = link->mVnets[v];
+                    linkRoute[vnet] = routing_table_entry[vnet];
+                }
+                net->makeExtInLink(src, dest - (2 * m_nodes), link,
+                                linkRoute);
+            }
+        }
     } else if (dest < 2*m_nodes) {
         assert(dest >= m_nodes);
         NodeID node = dest - m_nodes;
         src_dest.first = src;
         src_dest.second = dest;
-        link_entry = m_link_map[src_dest];
-        net->makeExtOutLink(src - (2 * m_nodes), node, link_entry.link,
-                         routing_table_entry);
+        std::vector<LinkEntry> links = m_link_map[src_dest];
+        for (int l = 0; l < links.size(); l++) {
+            link_entry = links[l];
+            std::vector<NetDest> linkRoute;
+            linkRoute.resize(m_vnets);
+            BasicLink *link = link_entry.link;
+            if (link->mVnets.size() == 0) {
+                net->makeExtOutLink(src - (2 * m_nodes), node, link,
+                                 routing_table_entry);
+            } else {
+                for (int v = 0; v< link->mVnets.size(); v++) {
+                    int vnet = link->mVnets[v];
+                    linkRoute[vnet] = routing_table_entry[vnet];
+                }
+                net->makeExtOutLink(src - (2 * m_nodes), node, link,
+                                linkRoute);
+            }
+        }
     } else {
         assert((src >= 2 * m_nodes) && (dest >= 2 * m_nodes));
         src_dest.first = src;
         src_dest.second = dest;
-        link_entry = m_link_map[src_dest];
-        net->makeInternalLink(src - (2 * m_nodes), dest - (2 * m_nodes),
-                              link_entry.link,
-                              routing_table_entry,
+        std::vector<LinkEntry> links = m_link_map[src_dest];
+        for (int l = 0; l < links.size(); l++) {
+            link_entry = links[l];
+            std::vector<NetDest> linkRoute;
+            linkRoute.resize(m_vnets);
+            BasicLink *link = link_entry.link;
+            if (link->mVnets.size() == 0) {
+                net->makeInternalLink(src - (2 * m_nodes),
+                              dest - (2 * m_nodes), link, routing_table_entry,
                               link_entry.src_outport_dirn,
                               link_entry.dst_inport_dirn);
+            } else {
+                for (int v = 0; v< link->mVnets.size(); v++) {
+                    int vnet = link->mVnets[v];
+                    linkRoute[vnet] = routing_table_entry[vnet];
+                }
+                net->makeInternalLink(src - (2 * m_nodes),
+                              dest - (2 * m_nodes), link, linkRoute,
+                              link_entry.src_outport_dirn,
+                              link_entry.dst_inport_dirn);
+            }
+        }
     }
 }
 
@@ -221,34 +330,54 @@ void
 Topology::extend_shortest_path(Matrix &current_dist, Matrix &latencies,
     Matrix &inter_switches)
 {
-    bool change = true;
-    int nodes = current_dist.size();
-
-    while (change) {
-        change = false;
-        for (int i = 0; i < nodes; i++) {
-            for (int j = 0; j < nodes; j++) {
-                int minimum = current_dist[i][j];
-                int previous_minimum = minimum;
-                int intermediate_switch = -1;
-                for (int k = 0; k < nodes; k++) {
-                    minimum = min(minimum,
-                        current_dist[i][k] + current_dist[k][j]);
-                    if (previous_minimum != minimum) {
-                        intermediate_switch = k;
-                        inter_switches[i][j] =
-                            inter_switches[i][k] +
-                            inter_switches[k][j] + 1;
+    int nodes = current_dist[0].size();
+
+    // We find the shortest path for each vnet for a given pair of
+    // source and destinations. This is done simply by traversing via
+    // all other nodes and finding the minimum distance.
+    for (int v = 0; v < m_vnets; v++) {
+        // There is a different topology for each vnet. Here we try to
+        // build a topology by finding the minimum number of intermediate
+        // switches needed to reach the destination
+        bool change = true;
+        while (change) {
+            change = false;
+            for (int i = 0; i < nodes; i++) {
+                for (int j = 0; j < nodes; j++) {
+                    // We follow an iterative process to build the shortest
+                    // path tree:
+                    // 1. Start from the direct connection (if there is one,
+                    // otherwise assume a hypothetical infinite weight link).
+                    // 2. Then we iterate through all other nodes considering
+                    // new potential intermediate switches. If we find any
+                    // lesser weight combination, we set(update) that as the
+                    // new weight between the source and destination.
+                    // 3. Repeat for all pairs of nodes.
+                    // 4. Go to step 1 if there was any new update done in
+                    // Step 2.
+                    int minimum = current_dist[v][i][j];
+                    int previous_minimum = minimum;
+                    int intermediate_switch = -1;
+                    for (int k = 0; k < nodes; k++) {
+                        minimum = min(minimum,
+                            current_dist[v][i][k] + current_dist[v][k][j]);
+                        if (previous_minimum != minimum) {
+                            intermediate_switch = k;
+                            inter_switches[i][j][v] =
+                                inter_switches[i][k][v] +
+                                inter_switches[k][j][v] + 1;
+                        }
+                        previous_minimum = minimum;
+                    }
+                    if (current_dist[v][i][j] != minimum) {
+                        change = true;
+                        current_dist[v][i][j] = minimum;
+                        assert(intermediate_switch >= 0);
+                        assert(intermediate_switch < latencies[i].size());
+                        latencies[i][j][v] =
+                            latencies[i][intermediate_switch][v] +
+                            latencies[intermediate_switch][j][v];
                     }
-                    previous_minimum = minimum;
-                }
-                if (current_dist[i][j] != minimum) {
-                    change = true;
-                    current_dist[i][j] = minimum;
-                    assert(intermediate_switch >= 0);
-                    assert(intermediate_switch < latencies[i].size());
-                    latencies[i][j] = latencies[i][intermediate_switch] +
-                        latencies[intermediate_switch][j];
                 }
             }
         }
@@ -267,14 +396,16 @@ Topology::shortest_path(const Matrix &weights, Matrix &latencies,
 bool
 Topology::link_is_shortest_path_to_node(SwitchID src, SwitchID next,
                                         SwitchID final, const Matrix &weights,
-                                        const Matrix &dist)
+                                        const Matrix &dist, int vnet)
 {
-    return weights[src][next] + dist[next][final] == dist[src][final];
+    return weights[vnet][src][next] + dist[vnet][next][final] ==
+        dist[vnet][src][final];
 }
 
 NetDest
 Topology::shortest_path_to_node(SwitchID src, SwitchID next,
-                                const Matrix &weights, const Matrix &dist)
+                                const Matrix &weights, const Matrix &dist,
+                                int vnet)
 {
     NetDest result;
     int d = 0;
@@ -292,7 +423,7 @@ Topology::shortest_path_to_node(SwitchID src, SwitchID next,
             //  2*MachineType_base_number(MachineType_NUM)-1] for the
             // component network
             if (link_is_shortest_path_to_node(src, next, d + max_machines,
-                    weights, dist)) {
+                    weights, dist, vnet)) {
                 MachineID mach = {(MachineType)m, i};
                 result.add(mach);
             }
@@ -302,9 +433,9 @@ Topology::shortest_path_to_node(SwitchID src, SwitchID next,
 
     DPRINTF(RubyNetwork, "Returning shortest path\n"
             "(src-(2*max_machines)): %d, (next-(2*max_machines)): %d, "
-            "src: %d, next: %d, result: %s\n",
+            "src: %d, next: %d, vnet:%d result: %s\n",
             (src-(2*max_machines)), (next-(2*max_machines)),
-            src, next, result);
+            src, next, vnet, result);
 
     return result;
 }
index ef8104ad52d787647d0e8ecbfd83fdea827891e8..40b8a86df1fc63215dac2cfd43164d3160882f4b 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
  * All rights reserved.
  *
 class NetDest;
 class Network;
 
-typedef std::vector<std::vector<int> > Matrix;
+/*
+ * We use a three-dimensional vector matrix for calculating
+ * the shortest paths for each pair of source and destination
+ * and for each type of virtual network. The three dimensions
+ * represent the source ID, destination ID, and vnet number.
+ */
+typedef std::vector<std::vector<std::vector<int>>> Matrix;
 typedef std::string PortDirection;
 
 struct LinkEntry
@@ -61,12 +68,14 @@ struct LinkEntry
     PortDirection dst_inport_dirn;
 };
 
-typedef std::map<std::pair<SwitchID, SwitchID>, LinkEntry> LinkMap;
+typedef std::map<std::pair<SwitchID, SwitchID>,
+             std::vector<LinkEntry>> LinkMap;
 
 class Topology
 {
   public:
-    Topology(uint32_t num_routers, const std::vector<BasicExtLink *> &ext_links,
+    Topology(uint32_t num_nodes, uint32_t num_routers, uint32_t num_vnets,
+             const std::vector<BasicExtLink *> &ext_links,
              const std::vector<BasicIntLink *> &int_links);
 
     uint32_t numSwitches() const { return m_number_of_switches; }
@@ -78,23 +87,26 @@ class Topology
                  PortDirection src_outport_dirn = "",
                  PortDirection dest_inport_dirn = "");
     void makeLink(Network *net, SwitchID src, SwitchID dest,
-                  const NetDest& routing_table_entry);
+                  std::vector<NetDest>& routing_table_entry);
 
     // Helper functions based on chapter 29 of Cormen et al.
     void extend_shortest_path(Matrix &current_dist, Matrix &latencies,
                               Matrix &inter_switches);
 
-    std::vector<std::vector<int>> shortest_path(const Matrix &weights,
+    Matrix shortest_path(const Matrix &weights,
             Matrix &latencies, Matrix &inter_switches);
 
     bool link_is_shortest_path_to_node(SwitchID src, SwitchID next,
-            SwitchID final, const Matrix &weights, const Matrix &dist);
+            SwitchID final, const Matrix &weights, const Matrix &dist,
+            int vnet);
 
     NetDest shortest_path_to_node(SwitchID src, SwitchID next,
-                                  const Matrix &weights, const Matrix &dist);
+                                  const Matrix &weights, const Matrix &dist,
+                                  int vnet);
 
     const uint32_t m_nodes;
     const uint32_t m_number_of_switches;
+    int m_vnets;
 
     std::vector<BasicExtLink*> m_ext_link_vector;
     std::vector<BasicIntLink*> m_int_link_vector;
index 9862e728852c63f2e5d866850325af83ca621d38..94aa600964bed69085b050965c3b3c19dc72da36 100644 (file)
@@ -35,7 +35,8 @@
 
 // All common enums and typedefs go here
 
-enum flit_type {HEAD_, BODY_, TAIL_, HEAD_TAIL_, NUM_FLIT_TYPE_};
+enum flit_type {HEAD_, BODY_, TAIL_, HEAD_TAIL_,
+                CREDIT_, 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_};
index eb286ec4992e4fc21cce19f5dec862f63a15d2d2..3e56b4ed52ea913194b563cd075b0ff32e7a8f83 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-
 #include "mem/ruby/network/garnet2.0/Credit.hh"
 
+#include "base/trace.hh"
+#include "debug/RubyNetwork.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)
+Credit::Credit(int vc, bool is_free_signal, Tick curTime)
 {
     m_id = 0;
     m_vc = vc;
     m_is_free_signal = is_free_signal;
     m_time = curTime;
+    m_type = CREDIT_;
+}
+
+flit *
+Credit::serialize(int ser_id, int parts, uint32_t bWidth)
+{
+    DPRINTF(RubyNetwork, "Serializing a credit\n");
+    bool new_free = false;
+    if ((ser_id+1 == parts) && m_is_free_signal) {
+        new_free = true;
+    }
+    Credit *new_credit_flit = new Credit(m_vc, new_free, m_time);
+    return new_credit_flit;
 }
+
+flit *
+Credit::deserialize(int des_id, int num_flits, uint32_t bWidth)
+{
+    DPRINTF(RubyNetwork, "DeSerializing a credit vc:%d free:%d\n",
+    m_vc, m_is_free_signal);
+    if (m_is_free_signal) {
+        // We are not going to get anymore credits for this vc
+        // So send a credit in any case
+        return new Credit(m_vc, true, m_time);
+    }
+
+    return new Credit(m_vc, false, m_time);
+}
+
+void
+Credit::print(std::ostream& out) const
+{
+    out << "[Credit:: ";
+    out << "Type=" << m_type << " ";
+    out << "VC=" << m_vc << " ";
+    out << "FreeVC=" << m_is_free_signal << " ";
+    out << "Set Time=" << m_time << " ";
+    out << "]";
+}
+
+
+
index bd0c3c8ba7d67bcf045d4133a74f22a180d22b4b..bcfd76f249674ced2c7cfb3e874859166c5d2d06 100644 (file)
@@ -46,7 +46,14 @@ class Credit : public flit
 {
   public:
     Credit() {};
-    Credit(int vc, bool is_free_signal, Cycles curTime);
+    Credit(int vc, bool is_free_signal, Tick curTime);
+
+    // Functions used by SerDes
+    flit* serialize(int ser_id, int parts, uint32_t bWidth);
+    flit* deserialize(int des_id, int num_flits, uint32_t bWidth);
+    void print(std::ostream& out) const;
+
+    ~Credit() {};
 
     bool is_free_signal() { return m_is_free_signal; }
 
index eda9e9edb02f41d8946add9f02e66e1d8e380f40..3148446aabbc1cc5c8880462e4ac987f15020896 100644 (file)
@@ -61,17 +61,17 @@ CrossbarSwitch::wakeup()
             m_router->get_id(), m_router->curCycle());
 
     for (auto& switch_buffer : switchBuffers) {
-        if (!switch_buffer.isReady(m_router->curCycle())) {
+        if (!switch_buffer.isReady(curTick())) {
             continue;
         }
 
         flit *t_flit = switch_buffer.peekTopFlit();
-        if (t_flit->is_stage(ST_, m_router->curCycle())) {
+        if (t_flit->is_stage(ST_, curTick())) {
             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));
+            t_flit->advance_stage(LT_, m_router->clockEdge(Cycles(1)));
+            t_flit->set_time(m_router->clockEdge(Cycles(1)));
 
             // This will take care of waking up the Network Link
             // in the next cycle
index b14553003c5490bfa751b99d1c4380659d921369..99d891f958b2c4cc24527178fc6215419ae038cf 100644 (file)
@@ -30,7 +30,9 @@
 
 #include "mem/ruby/network/garnet2.0/GarnetLink.hh"
 
+#include "debug/RubyNetwork.hh"
 #include "mem/ruby/network/garnet2.0/CreditLink.hh"
+#include "mem/ruby/network/garnet2.0/NetworkBridge.hh"
 #include "mem/ruby/network/garnet2.0/NetworkLink.hh"
 
 GarnetIntLink::GarnetIntLink(const Params *p)
@@ -40,11 +42,43 @@ GarnetIntLink::GarnetIntLink(const Params *p)
 
     m_network_link = p->network_link;
     m_credit_link = p->credit_link;
+
+    srcCdcEn = p->src_cdc;
+    dstCdcEn = p->dst_cdc;
+
+    srcSerdesEn = p->src_serdes;
+    dstSerdesEn = p->dst_serdes;
+
+    srcBridgeEn = false;
+    dstBridgeEn = false;
+
+    if (srcCdcEn || srcSerdesEn) {
+        srcBridgeEn = true;
+        srcNetBridge = p->src_net_bridge;
+        srcCredBridge = p->src_cred_bridge;
+    }
+    if (dstCdcEn || dstSerdesEn) {
+        dstBridgeEn = true;
+        dstNetBridge = p->dst_net_bridge;
+        dstCredBridge = p->dst_cred_bridge;
+    }
+
 }
 
 void
 GarnetIntLink::init()
 {
+    if (srcBridgeEn) {
+        assert(srcNetBridge && srcCredBridge);
+        srcNetBridge->initBridge(srcCredBridge, srcCdcEn, srcSerdesEn);
+        srcCredBridge->initBridge(srcNetBridge, srcCdcEn, srcSerdesEn);
+    }
+
+    if (dstBridgeEn) {
+        assert(dstNetBridge && dstCredBridge);
+        dstNetBridge->initBridge(dstCredBridge, dstCdcEn, dstSerdesEn);
+        dstCredBridge->initBridge(dstNetBridge, dstCdcEn, dstSerdesEn);
+    }
 }
 
 void
@@ -71,11 +105,55 @@ GarnetExtLink::GarnetExtLink(const Params *p)
     // Out
     m_network_links[1] = p->network_links[1];
     m_credit_links[1] = p->credit_links[1];
+
+
+    extCdcEn = p->ext_cdc;
+    intCdcEn = p->int_cdc;
+
+    extSerdesEn = p->ext_serdes;
+    intSerdesEn = p->int_serdes;
+
+    extBridgeEn = false;
+    intBridgeEn = false;
+
+    if (extCdcEn || extSerdesEn) {
+        extBridgeEn = true;
+        extNetBridge[0] = p->ext_net_bridge[0];
+        extCredBridge[0] = p->ext_cred_bridge[0];
+        extNetBridge[1] = p->ext_net_bridge[1];
+        extCredBridge[1] = p->ext_cred_bridge[1];
+    }
+
+    if (intCdcEn || intSerdesEn) {
+        intBridgeEn = true;
+        intNetBridge[0] = p->int_net_bridge[0];
+        intNetBridge[1] = p->int_net_bridge[1];
+        intCredBridge[0] = p->int_cred_bridge[0];
+        intCredBridge[1] = p->int_cred_bridge[1];
+    }
+
 }
 
 void
 GarnetExtLink::init()
 {
+    if (extBridgeEn) {
+        assert(extNetBridge[0] && extCredBridge[0] &&
+           extNetBridge[1] && extCredBridge[1]);
+        extNetBridge[0]->initBridge(extCredBridge[0], extCdcEn, extSerdesEn);
+        extCredBridge[0]->initBridge(extNetBridge[0], extCdcEn, extSerdesEn);
+        extNetBridge[1]->initBridge(extCredBridge[1], extCdcEn, extSerdesEn);
+        extCredBridge[1]->initBridge(extNetBridge[1], extCdcEn, extSerdesEn);
+    }
+
+    if (intBridgeEn) {
+        assert(intNetBridge[0] && intCredBridge[0] &&
+           intNetBridge[1] && intCredBridge[1]);
+        intNetBridge[0]->initBridge(intCredBridge[0], intCdcEn, intSerdesEn);
+        intCredBridge[0]->initBridge(intNetBridge[0], intCdcEn, intSerdesEn);
+        intNetBridge[1]->initBridge(intCredBridge[1], intCdcEn, intSerdesEn);
+        intCredBridge[1]->initBridge(intNetBridge[1], intCdcEn, intSerdesEn);
+    }
 }
 
 void
index 1c7e743273fb2528ce2c3b21feb0ea2fe8d5f445..089bcce45e809f67eec1f8c8ab1c6d94f6f654b1 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "mem/ruby/network/BasicLink.hh"
 #include "mem/ruby/network/garnet2.0/CreditLink.hh"
+#include "mem/ruby/network/garnet2.0/NetworkBridge.hh"
 #include "mem/ruby/network/garnet2.0/NetworkLink.hh"
 #include "params/GarnetExtLink.hh"
 #include "params/GarnetIntLink.hh"
@@ -56,6 +57,21 @@ class GarnetIntLink : public BasicIntLink
   protected:
     NetworkLink* m_network_link;
     CreditLink* m_credit_link;
+
+    bool srcBridgeEn;
+    bool dstBridgeEn;
+
+    bool srcSerdesEn;
+    bool dstSerdesEn;
+
+    bool srcCdcEn;
+    bool dstCdcEn;
+
+    NetworkBridge* srcNetBridge;
+    NetworkBridge* dstNetBridge;
+
+    NetworkBridge* srcCredBridge;
+    NetworkBridge* dstCredBridge;
 };
 
 inline std::ostream&
@@ -79,8 +95,24 @@ class GarnetExtLink : public BasicExtLink
     friend class GarnetNetwork;
 
   protected:
+    bool extBridgeEn;
+    bool intBridgeEn;
+
+    bool extSerdesEn;
+    bool intSerdesEn;
+
+    bool extCdcEn;
+    bool intCdcEn;
+
     NetworkLink* m_network_links[2];
     CreditLink* m_credit_links[2];
+
+    NetworkBridge* extNetBridge[2];
+    NetworkBridge* intNetBridge[2];
+
+    NetworkBridge* extCredBridge[2];
+    NetworkBridge* intCredBridge[2];
+
 };
 
 inline std::ostream&
index 3f1bba696cc076053c9b573e255beb00fa312eb7..33a3d3149afe8ca7b4234e338328acd2da4e2143 100644 (file)
@@ -30,6 +30,11 @@ from m5.proxy import *
 from m5.objects.ClockedObject import ClockedObject
 from m5.objects.BasicLink import BasicIntLink, BasicExtLink
 
+class CDCType(Enum): vals = [
+    'LINK_OBJECT',
+    'OBJECT_LINK',
+    ]
+
 class NetworkLink(ClockedObject):
     type = 'NetworkLink'
     cxx_header = "mem/ruby/network/garnet2.0/NetworkLink.hh"
@@ -39,11 +44,23 @@ class NetworkLink(ClockedObject):
                               "virtual channels per virtual network")
     virt_nets = Param.Int(Parent.number_of_virtual_networks,
                           "number of virtual networks")
+    supported_vnets = VectorParam.Int(Parent.supported_vnets,
+                                      "Vnets supported")
+    width = Param.UInt32(Parent.width, "bit-width of the link")
 
 class CreditLink(NetworkLink):
     type = 'CreditLink'
     cxx_header = "mem/ruby/network/garnet2.0/CreditLink.hh"
 
+class NetworkBridge(CreditLink):
+    type = 'NetworkBridge'
+    cxx_header = "mem/ruby/network/garnet2.0/NetworkBridge.hh"
+    link = Param.NetworkLink("Associated Network Link")
+    vtype = Param.CDCType('LINK_OBJECT',
+              "Direction of CDC LINK->OBJECT or OBJECT->LINK")
+    serdes_latency = Param.Cycles(1, "Latency of SerDes Unit")
+    cdc_latency = Param.Cycles(1, "Latency of CDC Unit")
+
 # Interior fixed pipeline links between routers
 class GarnetIntLink(BasicIntLink):
     type = 'GarnetIntLink'
@@ -53,6 +70,34 @@ class GarnetIntLink(BasicIntLink):
     network_link = Param.NetworkLink(NetworkLink(), "forward link")
     credit_link  = Param.CreditLink(CreditLink(), "backward flow-control link")
 
+    # The src_cdc and dst_cdc flags are used to enable the
+    # clock domain crossing(CDC) at the source and destination
+    # end of the link respectively. This is required when the
+    # link and the objected connected to the link are operating
+    # at different clock domains. These flags should be set
+    # in the network topology files.
+    src_cdc = Param.Bool(False, "Enable Clock Domain Crossing")
+    dst_cdc = Param.Bool(False, "Enable Clock Domain Crossing")
+
+    # The src_serdes and dst_serdes flags are used to enable
+    # the Serializer-Deserializer units at the source and
+    # destination end of the link respectively. Enabling
+    # these flags is necessary when the connecting object
+    # supports a different flit width.
+    src_serdes = Param.Bool(False, "Enable Serializer-Deserializer")
+    dst_serdes = Param.Bool(False, "Enable Serializer-Deserializer")
+
+    # The network bridge encapsulates both the CDC and Ser-Des
+    # units in HeteroGarnet. This is automatically enabled when
+    # either CDC or Ser-Des is enabled.
+    src_net_bridge = Param.NetworkBridge(NULL, "Network Bridge at source")
+    dst_net_bridge = Param.NetworkBridge(NULL, "Network Bridge at dest")
+    src_cred_bridge = Param.NetworkBridge(NULL, "Credit Bridge at source")
+    dst_cred_bridge = Param.NetworkBridge(NULL, "Credit Bridge at dest")
+
+    width = Param.UInt32(Parent.ni_flit_size,
+                          "bit width supported by the router")
+
 # Exterior fixed pipeline links between a router and a controller
 class GarnetExtLink(BasicExtLink):
     type = 'GarnetExtLink'
@@ -74,3 +119,36 @@ class GarnetExtLink(BasicExtLink):
     # Out uni-directional link
     _cls.append(CreditLink());
     credit_links = VectorParam.CreditLink(_cls, "backward flow-control links")
+
+    # The ext_cdc and intt_cdc flags are used to enable the
+    # clock domain crossing(CDC) at the external and internal
+    # end of the link respectively. This is required when the
+    # link and the objected connected to the link are operating
+    # at different clock domains. These flags should be set
+    # in the network topology files.
+    ext_cdc = Param.Bool(False, "Enable Clock Domain Crossing")
+    int_cdc = Param.Bool(False, "Enable Clock Domain Crossing")
+
+    # The ext_serdes and int_serdes flags are used to enable
+    # the Serializer-Deserializer units at the external and
+    # internal end of the link respectively. Enabling
+    # these flags is necessary when the connecting object
+    # supports a different flit width.
+    ext_serdes = Param.Bool(False, "Enable Serializer-Deserializer")
+    int_serdes = Param.Bool(False, "Enable Serializer-Deserializer")
+
+    # The network bridge encapsulates both the CDC and Ser-Des
+    # units in HeteroGarnet. This is automatically enabled when
+    # either CDC or Ser-Des is enabled.
+    ext_net_bridge = VectorParam.NetworkBridge(NULL,
+        "Network Bridge at external end")
+    ext_cred_bridge = VectorParam.NetworkBridge(NULL,
+        "Credit Bridge at external end")
+    int_net_bridge = VectorParam.NetworkBridge(NULL,
+        "Network Bridge at internal end")
+    int_cred_bridge = VectorParam.NetworkBridge(NULL,
+        "Credit Bridge at intternal end")
+
+
+    width = Param.UInt32(Parent.ni_flit_size,
+                          "bit width supported by the router")
index a88302b6c4b6952a8a5a5f992e93868b9ee04d9b..63562cd9186ca3876f75d308c520ce5d88ab5aea 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 2008 Princeton University
  * Copyright (c) 2016 Georgia Institute of Technology
  * All rights reserved.
@@ -33,6 +34,7 @@
 #include <cassert>
 
 #include "base/cast.hh"
+#include "debug/RubyNetwork.hh"
 #include "mem/ruby/common/NetDest.hh"
 #include "mem/ruby/network/MessageBuffer.hh"
 #include "mem/ruby/network/garnet2.0/CommonTypes.hh"
@@ -147,7 +149,7 @@ GarnetNetwork::init()
 
 void
 GarnetNetwork::makeExtInLink(NodeID global_src, SwitchID dest, BasicLink* link,
-                            const NetDest& routing_table_entry)
+                             std::vector<NetDest>& routing_table_entry)
 {
     NodeID local_src = getLocalNodeID(global_src);
     assert(local_src < m_nodes);
@@ -163,8 +165,42 @@ GarnetNetwork::makeExtInLink(NodeID global_src, SwitchID dest, BasicLink* 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[local_src]->addOutPort(net_link, credit_link, dest);
+
+    /*
+     * We check if a bridge was enabled at any end of the link.
+     * The bridge is enabled if either of clock domain
+     * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
+     * enabled for the link at each end. The bridge encapsulates
+     * the functionality for both CDC and SerDes and is a Consumer
+     * object similiar to a NetworkLink.
+     *
+     * If a bridge was enabled we connect the NI and Routers to
+     * bridge before connecting the link. Example, if an external
+     * bridge is enabled, we would connect:
+     * NI--->NetworkBridge--->GarnetExtLink---->Router
+     */
+    if (garnet_link->extBridgeEn) {
+        DPRINTF(RubyNetwork, "Enable external bridge for %s\n",
+            garnet_link->name());
+        m_nis[local_src]->
+        addOutPort(garnet_link->extNetBridge[LinkDirection_In],
+                   garnet_link->extCredBridge[LinkDirection_In],
+                   dest);
+    } else {
+        m_nis[local_src]->addOutPort(net_link, credit_link, dest);
+    }
+
+    if (garnet_link->intBridgeEn) {
+        DPRINTF(RubyNetwork, "Enable internal bridge for %s\n",
+            garnet_link->name());
+        m_routers[dest]->
+            addInPort(dst_inport_dirn,
+                      garnet_link->intNetBridge[LinkDirection_In],
+                      garnet_link->intCredBridge[LinkDirection_In]);
+    } else {
+        m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
+    }
+
 }
 
 /*
@@ -176,7 +212,7 @@ GarnetNetwork::makeExtInLink(NodeID global_src, SwitchID dest, BasicLink* link,
 void
 GarnetNetwork::makeExtOutLink(SwitchID src, NodeID global_dest,
                               BasicLink* link,
-                              const NetDest& routing_table_entry)
+                              std::vector<NetDest>& routing_table_entry)
 {
     NodeID local_dest = getLocalNodeID(global_dest);
     assert(local_dest < m_nodes);
@@ -194,10 +230,44 @@ GarnetNetwork::makeExtOutLink(SwitchID src, NodeID global_dest,
     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[local_dest]->addInPort(net_link, credit_link);
+
+    /*
+     * We check if a bridge was enabled at any end of the link.
+     * The bridge is enabled if either of clock domain
+     * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
+     * enabled for the link at each end. The bridge encapsulates
+     * the functionality for both CDC and SerDes and is a Consumer
+     * object similiar to a NetworkLink.
+     *
+     * If a bridge was enabled we connect the NI and Routers to
+     * bridge before connecting the link. Example, if an external
+     * bridge is enabled, we would connect:
+     * NI<---NetworkBridge<---GarnetExtLink<----Router
+     */
+    if (garnet_link->extBridgeEn) {
+        DPRINTF(RubyNetwork, "Enable external bridge for %s\n",
+            garnet_link->name());
+        m_nis[local_dest]->
+            addInPort(garnet_link->extNetBridge[LinkDirection_Out],
+                      garnet_link->extCredBridge[LinkDirection_Out]);
+    } else {
+        m_nis[local_dest]->addInPort(net_link, credit_link);
+    }
+
+    if (garnet_link->intBridgeEn) {
+        DPRINTF(RubyNetwork, "Enable internal bridge for %s\n",
+            garnet_link->name());
+        m_routers[src]->
+            addOutPort(src_outport_dirn,
+                       garnet_link->intNetBridge[LinkDirection_Out],
+                       routing_table_entry, link->m_weight,
+                       garnet_link->intCredBridge[LinkDirection_Out]);
+    } else {
+        m_routers[src]->
+            addOutPort(src_outport_dirn, net_link,
+                       routing_table_entry,
+                       link->m_weight, credit_link);
+    }
 }
 
 /*
@@ -207,7 +277,7 @@ GarnetNetwork::makeExtOutLink(SwitchID src, NodeID global_dest,
 
 void
 GarnetNetwork::makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
-                                const NetDest& routing_table_entry,
+                                std::vector<NetDest>& routing_table_entry,
                                 PortDirection src_outport_dirn,
                                 PortDirection dst_inport_dirn)
 {
@@ -221,10 +291,40 @@ GarnetNetwork::makeInternalLink(SwitchID src, SwitchID dest, BasicLink* 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);
+    /*
+     * We check if a bridge was enabled at any end of the link.
+     * The bridge is enabled if either of clock domain
+     * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
+     * enabled for the link at each end. The bridge encapsulates
+     * the functionality for both CDC and SerDes and is a Consumer
+     * object similiar to a NetworkLink.
+     *
+     * If a bridge was enabled we connect the NI and Routers to
+     * bridge before connecting the link. Example, if a source
+     * bridge is enabled, we would connect:
+     * Router--->NetworkBridge--->GarnetIntLink---->Router
+     */
+    if (garnet_link->dstBridgeEn) {
+        DPRINTF(RubyNetwork, "Enable destination bridge for %s\n",
+            garnet_link->name());
+        m_routers[dest]->addInPort(dst_inport_dirn,
+            garnet_link->dstNetBridge, garnet_link->dstCredBridge);
+    } else {
+        m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
+    }
+
+    if (garnet_link->srcBridgeEn) {
+        DPRINTF(RubyNetwork, "Enable source bridge for %s\n",
+            garnet_link->name());
+        m_routers[src]->
+            addOutPort(src_outport_dirn, garnet_link->srcNetBridge,
+                       routing_table_entry,
+                       link->m_weight, garnet_link->srcCredBridge);
+    } else {
+        m_routers[src]->addOutPort(src_outport_dirn, net_link,
+                        routing_table_entry,
+                        link->m_weight, credit_link);
+    }
 }
 
 // Total routers in the network
@@ -236,11 +336,11 @@ GarnetNetwork::getNumRouters()
 
 // Get ID of router connected to a NI.
 int
-GarnetNetwork::get_router_id(int global_ni)
+GarnetNetwork::get_router_id(int global_ni, int vnet)
 {
     NodeID local_ni = getLocalNodeID(global_ni);
 
-    return m_nis[local_ni]->get_router_id();
+    return m_nis[local_ni]->get_router_id(vnet);
 }
 
 void
index 3821dd8b815688bc21d3e73e55e1bde6fe0a3ddc..5173fa760e1f13969c999a1c7138ceb31b141b7a 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 2008 Princeton University
  * Copyright (c) 2016 Georgia Institute of Technology
  * All rights reserved.
@@ -81,16 +82,16 @@ class GarnetNetwork : public Network
         return m_vnet_type[vnet];
     }
     int getNumRouters();
-    int get_router_id(int ni);
+    int get_router_id(int ni, int vnet);
 
 
     // Methods used by Topology to setup the network
     void makeExtOutLink(SwitchID src, NodeID dest, BasicLink* link,
-                     const NetDest& routing_table_entry);
+                     std::vector<NetDest>& routing_table_entry);
     void makeExtInLink(NodeID src, SwitchID dest, BasicLink* link,
-                    const NetDest& routing_table_entry);
+                    std::vector<NetDest>& routing_table_entry);
     void makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
-                          const NetDest& routing_table_entry,
+                          std::vector<NetDest>& routing_table_entry,
                           PortDirection src_outport_dirn,
                           PortDirection dest_inport_dirn);
 
@@ -109,13 +110,13 @@ class GarnetNetwork : public Network
     void increment_received_packets(int vnet) { m_packets_received[vnet]++; }
 
     void
-    increment_packet_network_latency(Cycles latency, int vnet)
+    increment_packet_network_latency(Tick latency, int vnet)
     {
         m_packet_network_latency[vnet] += latency;
     }
 
     void
-    increment_packet_queueing_latency(Cycles latency, int vnet)
+    increment_packet_queueing_latency(Tick latency, int vnet)
     {
         m_packet_queueing_latency[vnet] += latency;
     }
@@ -124,13 +125,13 @@ class GarnetNetwork : public Network
     void increment_received_flits(int vnet) { m_flits_received[vnet]++; }
 
     void
-    increment_flit_network_latency(Cycles latency, int vnet)
+    increment_flit_network_latency(Tick latency, int vnet)
     {
         m_flit_network_latency[vnet] += latency;
     }
 
     void
-    increment_flit_queueing_latency(Cycles latency, int vnet)
+    increment_flit_queueing_latency(Tick latency, int vnet)
     {
         m_flit_queueing_latency[vnet] += latency;
     }
index 04c0ef46bb744ebdc8aa469c9172892280b55b51..012ab60d8ff06770262239a21854fc0d0c01b818 100644 (file)
@@ -70,3 +70,5 @@ class GarnetRouter(BasicRouter):
                               "virtual channels per virtual network")
     virt_nets = Param.UInt32(Parent.number_of_virtual_networks,
                           "number of virtual networks")
+    width = Param.UInt32(Parent.ni_flit_size,
+                          "bit width supported by the router")
index 640e3b4ace83d8203d9b0d0deac4183457f065a6..db24aefad58c6284b6f3b37e6c2c19dc5dff22b8 100644 (file)
@@ -70,9 +70,13 @@ void
 InputUnit::wakeup()
 {
     flit *t_flit;
-    if (m_in_link->isReady(m_router->curCycle())) {
+    if (m_in_link->isReady(curTick())) {
 
         t_flit = m_in_link->consumeLink();
+        DPRINTF(RubyNetwork, "Router[%d] Consuming:%s Width: %d Flit:%s\n",
+        m_router->get_id(), m_in_link->name(),
+        m_router->getBitWidth(), *t_flit);
+        assert(t_flit->m_width == m_router->getBitWidth());
         int vc = t_flit->get_vc();
         t_flit->increment_hops(); // for stats
 
@@ -80,7 +84,7 @@ InputUnit::wakeup()
             (t_flit->get_type() == HEAD_TAIL_)) {
 
             assert(virtualChannels[vc].get_state() == IDLE_);
-            set_vc_active(vc, m_router->curCycle());
+            set_vc_active(vc, curTick());
 
             // Route computation for this vc
             int outport = m_router->route_compute(t_flit->get_route(),
@@ -109,26 +113,32 @@ InputUnit::wakeup()
         if (pipe_stages == 1) {
             // 1-cycle router
             // Flit goes for SA directly
-            t_flit->advance_stage(SA_, m_router->curCycle());
+            t_flit->advance_stage(SA_, curTick());
         } 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);
+            t_flit->advance_stage(SA_, m_router->clockEdge(wait_time));
 
             // Wakeup the router in that cycle to perform SA
             m_router->schedule_wakeup(Cycles(wait_time));
         }
+
+        if (m_in_link->isReady(curTick())) {
+            m_router->schedule_wakeup(Cycles(1));
+        }
     }
 }
 
 // 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)
+InputUnit::increment_credit(int in_vc, bool free_signal, Tick curTime)
 {
+    DPRINTF(RubyNetwork, "Router[%d]: Sending a credit vc:%d free:%d to %s\n",
+    m_router->get_id(), in_vc, free_signal, m_credit_link->name());
     Credit *t_credit = new Credit(in_vc, free_signal, curTime);
     creditQueue.insert(t_credit);
     m_credit_link->scheduleEventAbsolute(m_router->clockEdge(Cycles(1)));
index d0e2ef66b85c9ecdad48708a9c30212df063e589..40ef251fb89c945fc7c2894638afa952e55a36e5 100644 (file)
@@ -55,13 +55,13 @@ class InputUnit : public Consumer
     inline PortDirection get_direction() { return m_direction; }
 
     inline void
-    set_vc_idle(int vc, Cycles curTime)
+    set_vc_idle(int vc, Tick curTime)
     {
         virtualChannels[vc].set_idle(curTime);
     }
 
     inline void
-    set_vc_active(int vc, Cycles curTime)
+    set_vc_active(int vc, Tick curTime)
     {
         virtualChannels[vc].set_active(curTime);
     }
@@ -90,13 +90,13 @@ class InputUnit : public Consumer
         return virtualChannels[invc].get_outvc();
     }
 
-    inline Cycles
+    inline Tick
     get_enqueue_time(int invc)
     {
         return virtualChannels[invc].get_enqueue_time();
     }
 
-    void increment_credit(int in_vc, bool free_signal, Cycles curTime);
+    void increment_credit(int in_vc, bool free_signal, Tick curTime);
 
     inline flit*
     peekTopFlit(int vc)
@@ -111,13 +111,13 @@ class InputUnit : public Consumer
     }
 
     inline bool
-    need_stage(int vc, flit_stage stage, Cycles time)
+    need_stage(int vc, flit_stage stage, Tick time)
     {
         return virtualChannels[vc].need_stage(stage, time);
     }
 
     inline bool
-    isReady(int invc, Cycles curTime)
+    isReady(int invc, Tick curTime)
     {
         return virtualChannels[invc].isReady(curTime);
     }
diff --git a/src/mem/ruby/network/garnet2.0/NetworkBridge.cc b/src/mem/ruby/network/garnet2.0/NetworkBridge.cc
new file mode 100644 (file)
index 0000000..f088b25
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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 HOLDER 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: Srikant Bharadwaj
+ */
+
+
+#include "mem/ruby/network/garnet2.0/NetworkBridge.hh"
+
+#include <cmath>
+
+#include "debug/RubyNetwork.hh"
+#include "params/GarnetIntLink.hh"
+
+NetworkBridge::NetworkBridge(const Params *p)
+    :CreditLink(p)
+{
+    enCdc = true;
+    enSerDes = true;
+    mType = p->vtype;
+
+    cdcLatency = p->cdc_latency;
+    serDesLatency = p->serdes_latency;
+    lastScheduledAt = 0;
+
+    nLink = p->link;
+    if (mType == Enums::LINK_OBJECT) {
+        nLink->setLinkConsumer(this);
+        setSourceQueue(nLink->getBuffer(), nLink);
+    } else if (mType == Enums::OBJECT_LINK) {
+        nLink->setSourceQueue(&linkBuffer, this);
+        setLinkConsumer(nLink);
+    } else {
+        // CDC type must be set
+        panic("CDC type must be set");
+    }
+
+    lenBuffer.resize(p->vcs_per_vnet * p->virt_nets);
+    sizeSent.resize(p->vcs_per_vnet * p->virt_nets);
+    flitsSent.resize(p->vcs_per_vnet * p->virt_nets);
+    extraCredit.resize(p->vcs_per_vnet * p->virt_nets);
+}
+
+void
+NetworkBridge::initBridge(NetworkBridge *coBrid, bool cdc_en, bool serdes_en)
+{
+    coBridge = coBrid;
+    enCdc = cdc_en;
+    enSerDes = serdes_en;
+}
+
+NetworkBridge::~NetworkBridge()
+{
+}
+
+void
+NetworkBridge::scheduleFlit(flit *t_flit, Cycles latency)
+{
+    Cycles totLatency = latency;
+
+    if (enCdc) {
+        // Add the CDC latency
+        totLatency = latency + cdcLatency;
+    }
+
+    Tick sendTime = link_consumer->getObject()->clockEdge(totLatency);
+    Tick nextAvailTick = lastScheduledAt + link_consumer->getObject()->\
+            cyclesToTicks(Cycles(1));
+    sendTime = std::max(nextAvailTick, sendTime);
+    t_flit->set_time(sendTime);
+    lastScheduledAt = sendTime;
+    linkBuffer.insert(t_flit);
+    link_consumer->scheduleEventAbsolute(sendTime);
+}
+
+void
+NetworkBridge::neutralize(int vc, int eCredit)
+{
+    extraCredit[vc].push(eCredit);
+}
+
+void
+NetworkBridge::flitisizeAndSend(flit *t_flit)
+{
+    // Serialize-Deserialize only if it is enabled
+    if (enSerDes) {
+        // Calculate the target-width
+        int target_width = bitWidth;
+        int cur_width = nLink->bitWidth;
+        if (mType == Enums::OBJECT_LINK) {
+            target_width = nLink->bitWidth;
+            cur_width = bitWidth;
+        }
+
+        DPRINTF(RubyNetwork, "Target width: %d Current: %d\n",
+            target_width, cur_width);
+        assert(target_width != cur_width);
+
+        int vc = t_flit->get_vc();
+
+        if (target_width > cur_width) {
+            // Deserialize
+            // This deserializer combines flits from the
+            // same message together
+            int num_flits = 0;
+            int flitPossible = 0;
+            if (t_flit->get_type() == CREDIT_) {
+                lenBuffer[vc]++;
+                assert(extraCredit[vc].front());
+                if (lenBuffer[vc] == extraCredit[vc].front()) {
+                    flitPossible = 1;
+                    extraCredit[vc].pop();
+                    lenBuffer[vc] = 0;
+                }
+            } else if (t_flit->get_type() == TAIL_ ||
+                       t_flit->get_type() == HEAD_TAIL_) {
+                // If its the end of packet, then send whatever
+                // is available.
+                int sizeAvail = (t_flit->msgSize - sizeSent[vc]);
+                flitPossible = ceil((float)sizeAvail/(float)target_width);
+                assert (flitPossible < 2);
+                num_flits = (t_flit->get_id() + 1) - flitsSent[vc];
+                // Stop tracking the packet.
+                flitsSent[vc] = 0;
+                sizeSent[vc] = 0;
+            } else {
+                // If we are yet to receive the complete packet
+                // track the size recieved and flits deserialized.
+                int sizeAvail =
+                    ((t_flit->get_id() + 1)*cur_width) - sizeSent[vc];
+                flitPossible = floor((float)sizeAvail/(float)target_width);
+                assert (flitPossible < 2);
+                num_flits = (t_flit->get_id() + 1) - flitsSent[vc];
+                if (flitPossible) {
+                    sizeSent[vc] += target_width;
+                    flitsSent[vc] = t_flit->get_id() + 1;
+                }
+            }
+
+            DPRINTF(RubyNetwork, "Deserialize :%dB -----> %dB "
+                " vc:%d\n", cur_width, target_width, vc);
+
+            flit *fl = NULL;
+            if (flitPossible) {
+                fl = t_flit->deserialize(lenBuffer[vc], num_flits,
+                    target_width);
+            }
+
+            // Inform the credit serializer about the number
+            // of flits that were generated.
+            if (t_flit->get_type() != CREDIT_ && fl) {
+                coBridge->neutralize(vc, num_flits);
+            }
+
+            // Schedule only if we are done deserializing
+            if (fl) {
+                DPRINTF(RubyNetwork, "Scheduling a flit\n");
+                lenBuffer[vc] = 0;
+                scheduleFlit(fl, serDesLatency);
+            }
+            // Delete this flit, new flit is sent in any case
+            delete t_flit;
+        } else {
+            // Serialize
+            DPRINTF(RubyNetwork, "Serializing flit :%d -----> %d "
+            "(vc:%d, Original Message Size: %d)\n",
+                cur_width, target_width, vc, t_flit->msgSize);
+
+            int flitPossible = 0;
+            if (t_flit->get_type() == CREDIT_) {
+                // We store the deserialization ratio and then
+                // access it when serializing credits in the
+                // oppposite direction.
+                assert(extraCredit[vc].front());
+                flitPossible = extraCredit[vc].front();
+                extraCredit[vc].pop();
+            } else if (t_flit->get_type() == HEAD_ ||
+                    t_flit->get_type() == BODY_) {
+                int sizeAvail =
+                    ((t_flit->get_id() + 1)*cur_width) - sizeSent[vc];
+                flitPossible = floor((float)sizeAvail/(float)target_width);
+                if (flitPossible) {
+                    sizeSent[vc] += flitPossible*target_width;
+                    flitsSent[vc] += flitPossible;
+                }
+            } else {
+                int sizeAvail = t_flit->msgSize - sizeSent[vc];
+                flitPossible = ceil((float)sizeAvail/(float)target_width);
+                sizeSent[vc] = 0;
+                flitsSent[vc] = 0;
+            }
+            assert(flitPossible > 0);
+
+            // Schedule all the flits
+            // num_flits could be zero for credits
+            for (int i = 0; i < flitPossible; i++) {
+                // Ignore neutralized credits
+                flit *fl = t_flit->serialize(i, flitPossible, target_width);
+                scheduleFlit(fl, serDesLatency);
+                DPRINTF(RubyNetwork, "Serialized to flit[%d of %d parts]:"
+                " %s\n", i+1, flitPossible, *fl);
+            }
+
+            if (t_flit->get_type() != CREDIT_) {
+                coBridge->neutralize(vc, flitPossible);
+            }
+            // Delete this flit, new flit is sent in any case
+            delete t_flit;
+        }
+        return;
+    }
+
+    // If only CDC is enabled schedule it
+    scheduleFlit(t_flit, Cycles(0));
+}
+void
+NetworkBridge::wakeup()
+{
+    flit *t_flit;
+
+    if (link_srcQueue->isReady(curTick())) {
+        t_flit = link_srcQueue->getTopFlit();
+        DPRINTF(RubyNetwork, "Recieved flit %s\n", *t_flit);
+        flitisizeAndSend(t_flit);
+        return;
+    }
+    assert(!link_srcQueue->getSize());
+}
+
+NetworkBridge *
+NetworkBridgeParams::create()
+{
+    return new NetworkBridge(this);
+}
diff --git a/src/mem/ruby/network/garnet2.0/NetworkBridge.hh b/src/mem/ruby/network/garnet2.0/NetworkBridge.hh
new file mode 100644 (file)
index 0000000..f12e0cd
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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 HOLDER 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: Srikant Bharadwaj
+ */
+
+#ifndef __MEM_RUBY_NETWORK_GARNET2_0_NETWORK_BRIDGE_HH__
+#define __MEM_RUBY_NETWORK_GARNET2_0_NETWORK_BRIDGE_HH__
+
+#include <iostream>
+#include <queue>
+#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/GarnetLink.hh"
+#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
+#include "mem/ruby/network/garnet2.0/flitBuffer.hh"
+#include "params/NetworkBridge.hh"
+
+class GarnetNetwork;
+
+class NetworkBridge: public CreditLink
+{
+  public:
+    typedef NetworkBridgeParams Params;
+    NetworkBridge(const Params *p);
+    ~NetworkBridge();
+
+    void initBridge(NetworkBridge *coBrid, bool cdc_en, bool serdes_en);
+
+    void wakeup();
+    void neutralize(int vc, int eCredit);
+
+    void scheduleFlit(flit *t_flit, Cycles latency);
+    void flitisizeAndSend(flit *t_flit);
+
+  protected:
+    // Pointer to co-existing bridge
+    // CreditBridge for Network Bridge and vice versa
+    NetworkBridge *coBridge;
+
+    // Link connected toBridge
+    // could be a source or destination
+    // depending on mType
+    NetworkLink *nLink;
+
+    // CDC enable/disable
+    bool enCdc;
+    // SerDes enable/disable
+    bool enSerDes;
+
+    // Type of Bridge
+    int mType;
+
+    Cycles cdcLatency;
+    Cycles serDesLatency;
+
+    Tick lastScheduledAt;
+
+    // Used by Credit Deserializer
+    std::vector<int> lenBuffer;
+    std::vector<int> sizeSent;
+    std::vector<int> flitsSent;
+    std::vector<std::queue<int>> extraCredit;
+
+};
+
+#endif // __MEM_RUBY_NETWORK_GARNET2_0_NETWORK_BRIDGE_HH__
index f4d446d4c8a0c184f3093a37fed863b630ed9b8b..46db22db836397554ad3205d956aaccc8253b7a5 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 2020 Inria
  * Copyright (c) 2016 Georgia Institute of Technology
  * Copyright (c) 2008 Princeton University
@@ -45,9 +46,8 @@ using namespace std;
 
 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_router_id(-1), m_vc_allocator(m_virtual_networks, 0),
-    m_vc_round_robin(0), outFlitQueue(), outCreditQueue(),
+    m_virtual_networks(p->virt_nets), m_vc_per_vnet(0),
+    m_vc_allocator(m_virtual_networks, 0),
     m_deadlock_threshold(p->garnet_deadlock_threshold),
     vc_busy_counter(m_virtual_networks, 0)
 {
@@ -57,7 +57,7 @@ NetworkInterface::NetworkInterface(const Params *p)
 
     // instantiating the NI flit buffers
     for (auto& time : m_ni_out_vcs_enqueue_time) {
-        time = Cycles(INFINITE_);
+        time = Tick(INFINITE_);
     }
 
     m_stall_count.resize(m_virtual_networks);
@@ -77,10 +77,14 @@ void
 NetworkInterface::addInPort(NetworkLink *in_link,
                               CreditLink *credit_link)
 {
-    inNetLink = in_link;
+    InputPort *newInPort = new InputPort(in_link, credit_link);
+    inPorts.push_back(newInPort);
+    DPRINTF(RubyNetwork, "Adding input port:%s with vnets %s\n",
+    in_link->name(), newInPort->printVnets());
+
     in_link->setLinkConsumer(this);
-    outCreditLink = credit_link;
-    credit_link->setSourceQueue(&outCreditQueue);
+    credit_link->setSourceQueue(newInPort->outCreditQueue(), this);
+
 }
 
 void
@@ -88,13 +92,14 @@ NetworkInterface::addOutPort(NetworkLink *out_link,
                              CreditLink *credit_link,
                              SwitchID router_id)
 {
-    inCreditLink = credit_link;
-    credit_link->setLinkConsumer(this);
+    OutputPort *newOutPort = new OutputPort(out_link, credit_link, router_id);
+    outPorts.push_back(newOutPort);
 
-    outNetLink = out_link;
-    out_link->setSourceQueue(&outFlitQueue);
+    DPRINTF(RubyNetwork, "OutputPort:%s Vnet: %s\n",
+    out_link->name(), newOutPort->printVnets());
 
-    m_router_id = router_id;
+    out_link->setSourceQueue(newOutPort->outFlitQueue(), this);
+    credit_link->setLinkConsumer(this);
 }
 
 void
@@ -128,11 +133,12 @@ NetworkInterface::incrementStats(flit *t_flit)
 
     // Latency
     m_net_ptr->increment_received_flits(vnet);
-    Cycles network_delay =
-        t_flit->get_dequeue_time() - t_flit->get_enqueue_time() - Cycles(1);
-    Cycles src_queueing_delay = t_flit->get_src_delay();
-    Cycles dest_queueing_delay = (curCycle() - t_flit->get_dequeue_time());
-    Cycles queueing_delay = src_queueing_delay + dest_queueing_delay;
+    Tick network_delay =
+        t_flit->get_dequeue_time() -
+        t_flit->get_enqueue_time() - cyclesToTicks(Cycles(1));
+    Tick src_queueing_delay = t_flit->get_src_delay();
+    Tick dest_queueing_delay = (curTick() - t_flit->get_dequeue_time());
+    Tick queueing_delay = src_queueing_delay + dest_queueing_delay;
 
     m_net_ptr->increment_flit_network_latency(network_delay, vnet);
     m_net_ptr->increment_flit_queueing_latency(queueing_delay, vnet);
@@ -160,9 +166,14 @@ NetworkInterface::incrementStats(flit *t_flit)
 void
 NetworkInterface::wakeup()
 {
-    DPRINTF(RubyNetwork, "Network Interface %d connected to router %d "
-            "woke up at time: %lld\n", m_id, m_router_id, curCycle());
+    std::ostringstream oss;
+    for (auto &oPort: outPorts) {
+        oss << oPort->routerID() << "[" << oPort->printVnets() << "] ";
+    }
+    DPRINTF(RubyNetwork, "Network Interface %d connected to router:%s "
+            "woke up. Period: %ld\n", m_id, oss.str(), clockPeriod());
 
+    assert(curTick() == clockEdge());
     MsgPtr msg_ptr;
     Tick curTime = clockEdge();
 
@@ -183,63 +194,81 @@ NetworkInterface::wakeup()
     }
 
     scheduleOutputLink();
-    checkReschedule();
 
     // Check if there are flits stalling a virtual channel. Track if a
     // message is enqueued to restrict ejection to one message per cycle.
-    bool messageEnqueuedThisCycle = checkStallQueue();
+    checkStallQueue();
 
     /*********** Check the incoming flit link **********/
-    if (inNetLink->isReady(curCycle())) {
-        flit *t_flit = inNetLink->consumeLink();
-        int vnet = t_flit->get_vnet();
-        t_flit->set_dequeue_time(curCycle());
-
-        // If a tail flit is received, enqueue into the protocol buffers if
-        // space is available. Otherwise, exchange non-tail flits for credits.
-        if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) {
-            if (!messageEnqueuedThisCycle &&
-                outNode_ptr[vnet]->areNSlotsAvailable(1, curTime)) {
-                // Space is available. Enqueue to protocol buffer.
-                outNode_ptr[vnet]->enqueue(t_flit->get_msg_ptr(), curTime,
-                                           cyclesToTicks(Cycles(1)));
-
+    DPRINTF(RubyNetwork, "Number of input ports: %d\n", inPorts.size());
+    for (auto &iPort: inPorts) {
+        NetworkLink *inNetLink = iPort->inNetLink();
+        if (inNetLink->isReady(curTick())) {
+            flit *t_flit = inNetLink->consumeLink();
+            DPRINTF(RubyNetwork, "Recieved flit:%s\n", *t_flit);
+            assert(t_flit->m_width == iPort->bitWidth());
+
+            int vnet = t_flit->get_vnet();
+            t_flit->set_dequeue_time(curTick());
+
+            // If a tail flit is received, enqueue into the protocol buffers
+            // if space is available. Otherwise, exchange non-tail flits for
+            // credits.
+            if (t_flit->get_type() == TAIL_ ||
+                t_flit->get_type() == HEAD_TAIL_) {
+                if (!iPort->messageEnqueuedThisCycle &&
+                    outNode_ptr[vnet]->areNSlotsAvailable(1, curTime)) {
+                    // Space is available. Enqueue to protocol buffer.
+                    outNode_ptr[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 *cFlit = new Credit(t_flit->get_vc(),
+                                               true, curTick());
+                    iPort->sendCredit(cFlit);
+                    // Update stats and delete flit pointer
+                    incrementStats(t_flit);
+                    delete t_flit;
+                } else {
+                    // No space available- Place tail flit in stall queue and
+                    // set up a callback for when protocol buffer is dequeued.
+                    // Stat update and flit pointer deletion will occur upon
+                    // unstall.
+                    iPort->m_stall_queue.push_back(t_flit);
+                    m_stall_count[vnet]++;
+
+                    outNode_ptr[vnet]->registerDequeueCallback([this]() {
+                        dequeueCallback(); });
+                }
+            } else {
+                // Non-tail flit. Send back a credit but not VC free signal.
+                Credit *cFlit = new Credit(t_flit->get_vc(), false,
+                                               curTick());
                 // Simply send a credit back since we are not buffering
                 // this flit in the NI
-                sendCredit(t_flit, true);
+                iPort->sendCredit(cFlit);
 
-                // Update stats and delete flit pointer
+                // Update stats and delete flit pointer.
                 incrementStats(t_flit);
                 delete t_flit;
-            } else {
-                // No space available- Place tail flit in stall queue and set
-                // up a callback for when protocol buffer is dequeued. Stat
-                // update and flit pointer deletion will occur upon unstall.
-                m_stall_queue.push_back(t_flit);
-                m_stall_count[vnet]++;
-
-                auto cb = std::bind(&NetworkInterface::dequeueCallback, this);
-                outNode_ptr[vnet]->registerDequeueCallback(cb);
             }
-        } else {
-            // Non-tail flit. Send back a credit but not VC free signal.
-            sendCredit(t_flit, false);
-
-            // Update stats and delete flit pointer.
-            incrementStats(t_flit);
-            delete t_flit;
         }
     }
 
     /****************** Check the incoming credit link *******/
 
-    if (inCreditLink->isReady(curCycle())) {
-        Credit *t_credit = (Credit*) inCreditLink->consumeLink();
-        outVcState[t_credit->get_vc()].increment_credit();
-        if (t_credit->is_free_signal()) {
-            outVcState[t_credit->get_vc()].setState(IDLE_, curCycle());
+    for (auto &oPort: outPorts) {
+        CreditLink *inCreditLink = oPort->inCreditLink();
+        if (inCreditLink->isReady(curTick())) {
+            Credit *t_credit = (Credit*) inCreditLink->consumeLink();
+            outVcState[t_credit->get_vc()].increment_credit();
+            if (t_credit->is_free_signal()) {
+                outVcState[t_credit->get_vc()].setState(IDLE_,
+                    curTick());
+            }
+            delete t_credit;
         }
-        delete t_credit;
     }
 
 
@@ -247,61 +276,68 @@ NetworkInterface::wakeup()
     // was unstalled in the same cycle as a new message arrives. In this
     // case, we should schedule another wakeup to ensure the credit is sent
     // back.
-    if (outCreditQueue.getSize() > 0) {
-        outCreditLink->scheduleEventAbsolute(clockEdge(Cycles(1)));
+    for (auto &iPort: inPorts) {
+        if (iPort->outCreditQueue()->getSize() > 0) {
+            DPRINTF(RubyNetwork, "Sending a credit %s via %s at %ld\n",
+            *(iPort->outCreditQueue()->peekTopFlit()),
+            iPort->outCreditLink()->name(), clockEdge(Cycles(1)));
+            iPort->outCreditLink()->
+                scheduleEventAbsolute(clockEdge(Cycles(1)));
+        }
     }
+    checkReschedule();
 }
 
 void
-NetworkInterface::sendCredit(flit *t_flit, bool is_free)
-{
-    Credit *credit_flit = new Credit(t_flit->get_vc(), is_free, curCycle());
-    outCreditQueue.insert(credit_flit);
-}
-
-bool
 NetworkInterface::checkStallQueue()
 {
-    bool messageEnqueuedThisCycle = false;
-    Tick curTime = clockEdge();
-
-    if (!m_stall_queue.empty()) {
-        for (auto stallIter = m_stall_queue.begin();
-             stallIter != m_stall_queue.end(); ) {
-            flit *stallFlit = *stallIter;
-            int vnet = stallFlit->get_vnet();
-
-            // If we can now eject to the protocol buffer, send back credits
-            if (outNode_ptr[vnet]->areNSlotsAvailable(1, curTime)) {
-                outNode_ptr[vnet]->enqueue(stallFlit->get_msg_ptr(), curTime,
-                                           cyclesToTicks(Cycles(1)));
-
-                // Send back a credit with free signal now that the VC is no
-                // longer stalled.
-                sendCredit(stallFlit, true);
-
-                // Update Stats
-                incrementStats(stallFlit);
-
-                // Flit can now safely be deleted and removed from stall queue
-                delete stallFlit;
-                m_stall_queue.erase(stallIter);
-                m_stall_count[vnet]--;
-
-                // If there are no more stalled messages for this vnet, the
-                // callback on it's MessageBuffer is not needed.
-                if (m_stall_count[vnet] == 0)
-                    outNode_ptr[vnet]->unregisterDequeueCallback();
-
-                messageEnqueuedThisCycle = true;
-                break;
-            } else {
-                ++stallIter;
+    // Check all stall queues.
+    // There is one stall queue for each input link
+    for (auto &iPort: inPorts) {
+        iPort->messageEnqueuedThisCycle = false;
+        Tick curTime = clockEdge();
+
+        if (!iPort->m_stall_queue.empty()) {
+            for (auto stallIter = iPort->m_stall_queue.begin();
+                 stallIter != iPort->m_stall_queue.end(); ) {
+                flit *stallFlit = *stallIter;
+                int vnet = stallFlit->get_vnet();
+
+                // If we can now eject to the protocol buffer,
+                // send back credits
+                if (outNode_ptr[vnet]->areNSlotsAvailable(1,
+                    curTime)) {
+                    outNode_ptr[vnet]->enqueue(stallFlit->get_msg_ptr(),
+                        curTime, cyclesToTicks(Cycles(1)));
+
+                    // Send back a credit with free signal now that the
+                    // VC is no longer stalled.
+                    Credit *cFlit = new Credit(stallFlit->get_vc(), true,
+                                                   curTick());
+                    iPort->sendCredit(cFlit);
+
+                    // Update Stats
+                    incrementStats(stallFlit);
+
+                    // Flit can now safely be deleted and removed from stall
+                    // queue
+                    delete stallFlit;
+                    iPort->m_stall_queue.erase(stallIter);
+                    m_stall_count[vnet]--;
+
+                    // If there are no more stalled messages for this vnet, the
+                    // callback on it's MessageBuffer is not needed.
+                    if (m_stall_count[vnet] == 0)
+                        outNode_ptr[vnet]->unregisterDequeueCallback();
+
+                    iPort->messageEnqueuedThisCycle = true;
+                    break;
+                } else {
+                    ++stallIter;
+                }
             }
         }
     }
-
-    return messageEnqueuedThisCycle;
 }
 
 // Embed the protocol message into flits
@@ -316,8 +352,14 @@ NetworkInterface::flitisizeMessage(MsgPtr msg_ptr, int vnet)
 
     // 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());
+    OutputPort *oPort = getOutportForVnet(vnet);
+    assert(oPort);
+    int num_flits = (int)divCeil((float) m_net_ptr->MessageSizeType_to_int(
+        net_msg_ptr->getMessageSize()), (float)oPort->bitWidth());
+
+    DPRINTF(RubyNetwork, "Message Size:%d vnet:%d bitWidth:%d\n",
+        m_net_ptr->MessageSizeType_to_int(net_msg_ptr->getMessageSize()),
+        vnet, oPort->bitWidth());
 
     // loop to convert all multicast messages into unicast messages
     for (int ctr = 0; ctr < dest_nodes.size(); ctr++) {
@@ -355,13 +397,14 @@ NetworkInterface::flitisizeMessage(MsgPtr msg_ptr, int vnet)
         // 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.src_router = oPort->routerID();
         route.dest_ni = destID;
-        route.dest_router = m_net_ptr->get_router_id(destID);
+        route.dest_router = m_net_ptr->get_router_id(destID, vnet);
 
         // initialize hops_traversed to -1
         // so that the first router increments it to 0
@@ -371,14 +414,16 @@ NetworkInterface::flitisizeMessage(MsgPtr msg_ptr, int 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());
+                m_net_ptr->MessageSizeType_to_int(
+                net_msg_ptr->getMessageSize()),
+                oPort->bitWidth(), curTick());
 
-            fl->set_src_delay(curCycle() - ticksToCycles(msg_ptr->getTime()));
+            fl->set_src_delay(curTick() - ticksToCycles(msg_ptr->getTime()));
             niOutVcs[vc].insert(fl);
         }
 
-        m_ni_out_vcs_enqueue_time[vc] = curCycle();
-        outVcState[vc].setState(ACTIVE_, curCycle());
+        m_ni_out_vcs_enqueue_time[vc] = curTick();
+        outVcState[vc].setState(ACTIVE_, curTick());
     }
     return true ;
 }
@@ -394,7 +439,7 @@ NetworkInterface::calculateVC(int vnet)
             m_vc_allocator[vnet] = 0;
 
         if (outVcState[(vnet*m_vc_per_vnet) + delta].isInState(
-                    IDLE_, curCycle())) {
+                    IDLE_, curTick())) {
             vc_busy_counter[vnet] = 0;
             return ((vnet*m_vc_per_vnet) + delta);
         }
@@ -408,6 +453,67 @@ NetworkInterface::calculateVC(int vnet)
     return -1;
 }
 
+void
+NetworkInterface::scheduleOutputPort(OutputPort *oPort)
+{
+   int vc = oPort->vcRoundRobin();
+
+   for (int i = 0; i < niOutVcs.size(); i++) {
+       vc++;
+       if (vc == niOutVcs.size())
+           vc = 0;
+
+       int t_vnet = get_vnet(vc);
+       if (oPort->isVnetSupported(t_vnet)) {
+           // model buffer backpressure
+           if (niOutVcs[vc].isReady(curTick()) &&
+               outVcState[vc].has_credit()) {
+
+               bool is_candidate_vc = true;
+               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 (niOutVcs[t_vc].isReady(curTick())) {
+                           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;
+
+               // Update the round robin arbiter
+               oPort->vcRoundRobin(vc);
+
+               outVcState[vc].decrement_credit();
+
+               // Just removing the top flit
+               flit *t_flit = niOutVcs[vc].getTopFlit();
+               t_flit->set_time(clockEdge(Cycles(1)));
+
+               // Scheduling the flit
+               scheduleFlit(t_flit);
+
+               if (t_flit->get_type() == TAIL_ ||
+                  t_flit->get_type() == HEAD_TAIL_) {
+                   m_ni_out_vcs_enqueue_time[vc] = Tick(INFINITE_);
+               }
+
+               // Done with this port, continue to schedule
+               // other ports
+               return;
+           }
+       }
+   }
+}
+
+
 
 /** This function looks at the NI buffers
  *  if some buffer has flits which are ready to traverse the link in the next
@@ -418,54 +524,57 @@ NetworkInterface::calculateVC(int vnet)
 void
 NetworkInterface::scheduleOutputLink()
 {
-    int vc = m_vc_round_robin;
-
-    for (int i = 0; i < niOutVcs.size(); i++) {
-        vc++;
-        if (vc == niOutVcs.size())
-            vc = 0;
-
-        // model buffer backpressure
-        if (niOutVcs[vc].isReady(curCycle()) &&
-            outVcState[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 (niOutVcs[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;
+    // Schedule each output link
+    for (auto &oPort: outPorts) {
+        scheduleOutputPort(oPort);
+    }
+}
 
-            m_vc_round_robin = vc;
+NetworkInterface::InputPort *
+NetworkInterface::getInportForVnet(int vnet)
+{
+    for (auto &iPort : inPorts) {
+        if (iPort->isVnetSupported(vnet)) {
+            return iPort;
+        }
+    }
 
-            outVcState[vc].decrement_credit();
-            // Just removing the flit
-            flit *t_flit = niOutVcs[vc].getTopFlit();
-            t_flit->set_time(curCycle() + Cycles(1));
-            outFlitQueue.insert(t_flit);
-            // schedule the out link
-            outNetLink->scheduleEventAbsolute(clockEdge(Cycles(1)));
+    return nullptr;
+}
 
-            if (t_flit->get_type() == TAIL_ ||
-               t_flit->get_type() == HEAD_TAIL_) {
-                m_ni_out_vcs_enqueue_time[vc] = Cycles(INFINITE_);
-            }
-            return;
+/*
+ * This function returns the outport which supports the given vnet.
+ * Currently, HeteroGarnet does not support multiple outports to
+ * support same vnet. Thus, this function returns the first-and
+ * only outport which supports the vnet.
+ */
+NetworkInterface::OutputPort *
+NetworkInterface::getOutportForVnet(int vnet)
+{
+    for (auto &oPort : outPorts) {
+        if (oPort->isVnetSupported(vnet)) {
+            return oPort;
         }
     }
+
+    return nullptr;
+}
+void
+NetworkInterface::scheduleFlit(flit *t_flit)
+{
+    OutputPort *oPort = getOutportForVnet(t_flit->get_vnet());
+
+    if (oPort) {
+        DPRINTF(RubyNetwork, "Scheduling at %s time:%ld flit:%s Message:%s\n",
+        oPort->outNetLink()->name(), clockEdge(Cycles(1)),
+        *t_flit, *(t_flit->get_msg_ptr()));
+        oPort->outFlitQueue()->insert(t_flit);
+        oPort->outNetLink()->scheduleEventAbsolute(clockEdge(Cycles(1)));
+        return;
+    }
+
+    panic("No output port found for vnet:%d\n", t_flit->get_vnet());
+    return;
 }
 
 int
@@ -482,7 +591,9 @@ NetworkInterface::get_vnet(int 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
+// output VC buffer.
+// Also check if we have to reschedule because of a clock period
+// difference.
 void
 NetworkInterface::checkReschedule()
 {
@@ -498,7 +609,26 @@ NetworkInterface::checkReschedule()
     }
 
     for (auto& ni_out_vc : niOutVcs) {
-        if (ni_out_vc.isReady(curCycle() + Cycles(1))) {
+        if (ni_out_vc.isReady(clockEdge(Cycles(1)))) {
+            scheduleEvent(Cycles(1));
+            return;
+        }
+    }
+
+    // Check if any input links have flits to be popped.
+    // This can happen if the links are operating at
+    // a higher frequency.
+    for (auto &iPort : inPorts) {
+        NetworkLink *inNetLink = iPort->inNetLink();
+        if (inNetLink->isReady(curTick())) {
+            scheduleEvent(Cycles(1));
+            return;
+        }
+    }
+
+    for (auto &oPort : outPorts) {
+        CreditLink *inCreditLink = oPort->inCreditLink();
+        if (inCreditLink->isReady(curTick())) {
             scheduleEvent(Cycles(1));
             return;
         }
@@ -519,7 +649,9 @@ NetworkInterface::functionalWrite(Packet *pkt)
         num_functional_writes += ni_out_vc.functionalWrite(pkt);
     }
 
-    num_functional_writes += outFlitQueue.functionalWrite(pkt);
+    for (auto &oPort: outPorts) {
+        num_functional_writes += oPort->outFlitQueue()->functionalWrite(pkt);
+    }
     return num_functional_writes;
 }
 
index 7e3083844a67e14ae69e0a6a9da3de70ee37046b..945b446d7b6191eedba432a01e0338f629e950b7 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 2020 Inria
  * Copyright (c) 2016 Georgia Institute of Technology
  * Copyright (c) 2008 Princeton University
@@ -37,6 +38,7 @@
 
 #include "mem/ruby/common/Consumer.hh"
 #include "mem/ruby/network/garnet2.0/CommonTypes.hh"
+#include "mem/ruby/network/garnet2.0/Credit.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"
@@ -67,37 +69,213 @@ class NetworkInterface : public ClockedObject, public Consumer
 
     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 *);
 
+    void scheduleFlit(flit *t_flit);
+
+    int get_router_id(int vnet)
+    {
+        OutputPort *oPort = getOutportForVnet(vnet);
+        assert(oPort);
+        return oPort->routerID();
+    }
+
+    class OutputPort
+    {
+      public:
+          OutputPort(NetworkLink *outLink, CreditLink *creditLink,
+              int routerID)
+          {
+              _vnets = outLink->mVnets;
+              _outFlitQueue = new flitBuffer();
+
+              _outNetLink = outLink;
+              _inCreditLink = creditLink;
+
+              _routerID = routerID;
+              _bitWidth = outLink->bitWidth;
+              _vcRoundRobin = 0;
+
+          }
+
+          flitBuffer *
+          outFlitQueue()
+          {
+              return _outFlitQueue;
+          }
+
+          NetworkLink *
+          outNetLink()
+          {
+              return _outNetLink;
+          }
+
+          CreditLink *
+          inCreditLink()
+          {
+              return _inCreditLink;
+          }
+
+          int
+          routerID()
+          {
+              return _routerID;
+          }
+
+          uint32_t bitWidth()
+          {
+              return _bitWidth;
+          }
+
+          bool isVnetSupported(int pVnet)
+          {
+              if (!_vnets.size()) {
+                  return true;
+              }
+
+              for (auto &it : _vnets) {
+                  if (it == pVnet) {
+                      return true;
+                  }
+              }
+              return false;
+
+          }
+
+          std::string
+          printVnets()
+          {
+              std::stringstream ss;
+              for (auto &it : _vnets) {
+                  ss << it;
+                  ss << " ";
+              }
+              return ss.str();
+          }
+
+          int vcRoundRobin()
+          {
+              return _vcRoundRobin;
+          }
+
+          void vcRoundRobin(int vc)
+          {
+              _vcRoundRobin = vc;
+          }
+
+
+      private:
+          std::vector<int> _vnets;
+          flitBuffer *_outFlitQueue;
+
+          NetworkLink *_outNetLink;
+          CreditLink *_inCreditLink;
+
+          int _vcRoundRobin; // For round robin scheduling
+
+          int _routerID;
+          uint32_t _bitWidth;
+    };
+
+    class InputPort
+    {
+      public:
+          InputPort(NetworkLink *inLink, CreditLink *creditLink)
+          {
+              _vnets = inLink->mVnets;
+              _outCreditQueue = new flitBuffer();
+
+              _inNetLink = inLink;
+              _outCreditLink = creditLink;
+              _bitWidth = inLink->bitWidth;
+          }
+
+          flitBuffer *
+          outCreditQueue()
+          {
+              return _outCreditQueue;
+          }
+
+          NetworkLink *
+          inNetLink()
+          {
+              return _inNetLink;
+          }
+
+          CreditLink *
+          outCreditLink()
+          {
+              return _outCreditLink;
+          }
+
+          bool isVnetSupported(int pVnet)
+          {
+              if (!_vnets.size()) {
+                  return true;
+              }
+
+              for (auto &it : _vnets) {
+                  if (it == pVnet) {
+                      return true;
+                  }
+              }
+              return false;
+
+          }
+
+          void sendCredit(Credit *cFlit)
+          {
+              _outCreditQueue->insert(cFlit);
+          }
+
+          uint32_t bitWidth()
+          {
+              return _bitWidth;
+          }
+
+          std::string
+          printVnets()
+          {
+              std::stringstream ss;
+              for (auto &it : _vnets) {
+                  ss << it;
+                  ss << " ";
+              }
+              return ss.str();
+          }
+
+          // Queue for stalled flits
+          std::deque<flit *> m_stall_queue;
+          bool messageEnqueuedThisCycle;
+      private:
+          std::vector<int> _vnets;
+          flitBuffer *_outCreditQueue;
+
+          NetworkLink *_inNetLink;
+          CreditLink *_outCreditLink;
+          uint32_t _bitWidth;
+    };
+
+
   private:
     GarnetNetwork *m_net_ptr;
     const NodeID m_id;
     const int m_virtual_networks, m_vc_per_vnet;
     int m_router_id; // id of my router
     std::vector<int> m_vc_allocator;
-    int m_vc_round_robin; // For round robin scheduling
-    /** Used to model link contention. */
-    flitBuffer outFlitQueue;
-    flitBuffer outCreditQueue;
+    std::vector<OutputPort *> outPorts;
+    std::vector<InputPort *> inPorts;
     int m_deadlock_threshold;
     std::vector<OutVcState> outVcState;
 
-    NetworkLink *inNetLink;
-    NetworkLink *outNetLink;
-    CreditLink *inCreditLink;
-    CreditLink *outCreditLink;
-
-    // Queue for stalled flits
-    std::deque<flit *> m_stall_queue;
     std::vector<int> m_stall_count;
 
     // Input Flit Buffers
     // The flit buffers which will serve the Consumer
     std::vector<flitBuffer>  niOutVcs;
-    std::vector<Cycles> m_ni_out_vcs_enqueue_time;
+    std::vector<Tick> m_ni_out_vcs_enqueue_time;
 
     // The Message buffers that takes messages from the protocol
     std::vector<MessageBuffer *> inNode_ptr;
@@ -106,15 +284,19 @@ class NetworkInterface : public ClockedObject, public Consumer
     // When a vc stays busy for a long time, it indicates a deadlock
     std::vector<int> vc_busy_counter;
 
-    bool checkStallQueue();
+    void checkStallQueue();
     bool flitisizeMessage(MsgPtr msg_ptr, int vnet);
     int calculateVC(int vnet);
 
+
+    void scheduleOutputPort(OutputPort *oPort);
     void scheduleOutputLink();
     void checkReschedule();
-    void sendCredit(flit *t_flit, bool is_free);
 
     void incrementStats(flit *t_flit);
+
+    InputPort *getInportForVnet(int vnet);
+    OutputPort *getOutportForVnet(int vnet);
 };
 
 #endif // __MEM_RUBY_NETWORK_GARNET2_0_NETWORKINTERFACE_HH__
index d4bccd828bcf11f69fdefe98fb16a557012e158d..8d00470d42ff3b02bbd5ea3e126ced8cd561e657 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 2020 Inria
  * Copyright (c) 2016 Georgia Institute of Technology
  * Copyright (c) 2008 Princeton University
 
 #include "mem/ruby/network/garnet2.0/NetworkLink.hh"
 
+#include "base/trace.hh"
+#include "debug/RubyNetwork.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),
+      m_latency(p->link_latency), m_link_utilized(0),
+      m_vc_load(p->vcs_per_vnet * p->virt_nets),
       linkBuffer(), link_consumer(nullptr),
-      link_srcQueue(nullptr), m_link_utilized(0),
-      m_vc_load(p->vcs_per_vnet * p->virt_nets)
+      link_srcQueue(nullptr)
 {
+    int num_vnets = (p->supported_vnets).size();
+    assert(num_vnets > 0);
+    mVnets.resize(num_vnets);
+    bitWidth = p->width;
+    for (int i = 0; i < num_vnets; i++) {
+        mVnets[i] = p->supported_vnets[i];
+    }
+    DPRINTF(RubyNetwork,"Created with bitwidth:%d\n", bitWidth);
 }
 
 void
@@ -50,23 +61,40 @@ NetworkLink::setLinkConsumer(Consumer *consumer)
 }
 
 void
-NetworkLink::setSourceQueue(flitBuffer* src_queue)
+NetworkLink::setSourceQueue(flitBuffer *src_queue, ClockedObject *srcClockObj)
 {
     link_srcQueue = src_queue;
+    src_object = srcClockObj;
 }
 
 void
 NetworkLink::wakeup()
 {
+    DPRINTF(RubyNetwork, "Woke up to transfer flits from %s\n",
+        src_object->name());
     assert(link_srcQueue != nullptr);
-    if (link_srcQueue->isReady(curCycle())) {
+    assert(curTick() == clockEdge());
+    if (link_srcQueue->isReady(curTick())) {
         flit *t_flit = link_srcQueue->getTopFlit();
-        t_flit->set_time(curCycle() + m_latency);
+        DPRINTF(RubyNetwork, "Transmission will finish at %ld :%s\n",
+                clockEdge(m_latency), *t_flit);
+        if (m_type != NUM_LINK_TYPES_) {
+            // Only for assertions and debug messages
+            assert(t_flit->m_width == bitWidth);
+            assert((std::find(mVnets.begin(), mVnets.end(),
+                t_flit->get_vnet()) != mVnets.end()) ||
+                (mVnets.size() == 0));
+        }
+        t_flit->set_time(clockEdge(m_latency));
         linkBuffer.insert(t_flit);
         link_consumer->scheduleEventAbsolute(clockEdge(m_latency));
         m_link_utilized++;
         m_vc_load[t_flit->get_vc()]++;
     }
+
+    if (!link_srcQueue->isEmpty()) {
+        scheduleEvent(Cycles(1));
+    }
 }
 
 void
index bc3d73a79e10ffdf840da7de4e46420cb445840d..5810d0d30e331cb9679a16258b41c607f3c031b2 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 2020 Inria
  * Copyright (c) 2016 Georgia Institute of Technology
  * Copyright (c) 2008 Princeton University
@@ -51,17 +52,21 @@ class NetworkLink : public ClockedObject, public Consumer
     ~NetworkLink() = default;
 
     void setLinkConsumer(Consumer *consumer);
-    void setSourceQueue(flitBuffer *src_queue);
+    void setSourceQueue(flitBuffer *src_queue, ClockedObject *srcClockObject);
     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();
+    flitBuffer *getBuffer() { return &linkBuffer;}
+    virtual 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 bool isReady(Tick curTime)
+    {
+        return linkBuffer.isReady(curTime);
+    }
 
     inline flit* peekLink() { return linkBuffer.peekTopFlit(); }
     inline flit* consumeLink() { return linkBuffer.getTopFlit(); }
@@ -69,18 +74,25 @@ class NetworkLink : public ClockedObject, public Consumer
     uint32_t functionalWrite(Packet *);
     void resetStats();
 
+    std::vector<int> mVnets;
+    uint32_t bitWidth;
+
   private:
     const int m_id;
     link_type m_type;
     const Cycles m_latency;
 
-    flitBuffer linkBuffer;
-    Consumer *link_consumer;
-    flitBuffer *link_srcQueue;
+    ClockedObject *src_object;
 
     // Statistical variables
     unsigned int m_link_utilized;
     std::vector<unsigned int> m_vc_load;
+
+  protected:
+    flitBuffer linkBuffer;
+    Consumer *link_consumer;
+    flitBuffer *link_srcQueue;
+
 };
 
 #endif // __MEM_RUBY_NETWORK_GARNET2_0_NETWORKLINK_HH__
index d22ad3d0eff8c38f2fb23fe29e51740aacc1e129..05252bcb53c7fd0c277a348a969d68ea992420bd 100644 (file)
@@ -45,12 +45,12 @@ class OutVcState
     void decrement_credit();
 
     inline bool
-    isInState(VC_state_type state, Cycles request_time)
+    isInState(VC_state_type state, Tick request_time)
     {
         return ((m_vc_state == state) && (request_time >= m_time) );
     }
     inline void
-    setState(VC_state_type state, Cycles time)
+    setState(VC_state_type state, Tick time)
     {
         m_vc_state = state;
         m_time = time;
@@ -58,7 +58,7 @@ class OutVcState
 
   private:
     int m_id ;
-    Cycles m_time;
+    Tick m_time;
     VC_state_type m_vc_state;
     int m_credit_count;
     int m_max_credit_count;
index 2270feaf345e9c9f95f6ccf8d50c593a0b4997ed..9a048c9784ae1a6f8452529f9b72cff9eb0f7032 100644 (file)
@@ -51,9 +51,11 @@ OutputUnit::OutputUnit(int id, PortDirection direction, Router *router)
 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());
+    DPRINTF(RubyNetwork, "Router %d OutputUnit %s decrementing credit:%d for "
+            "outvc %d at time: %lld for %s\n", m_router->get_id(),
+            m_router->getPortDirectionName(get_direction()),
+            outVcState[out_vc].get_credit_count(),
+            out_vc, m_router->curCycle(), m_credit_link->name());
 
     outVcState[out_vc].decrement_credit();
 }
@@ -61,9 +63,11 @@ OutputUnit::decrement_credit(int out_vc)
 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());
+    DPRINTF(RubyNetwork, "Router %d OutputUnit %s incrementing credit:%d for "
+            "outvc %d at time: %lld from:%s\n", m_router->get_id(),
+            m_router->getPortDirectionName(get_direction()),
+            outVcState[out_vc].get_credit_count(),
+            out_vc, m_router->curCycle(), m_credit_link->name());
 
     outVcState[out_vc].increment_credit();
 }
@@ -74,7 +78,7 @@ OutputUnit::increment_credit(int out_vc)
 bool
 OutputUnit::has_credit(int out_vc)
 {
-    assert(outVcState[out_vc].isInState(ACTIVE_, m_router->curCycle()));
+    assert(outVcState[out_vc].isInState(ACTIVE_, curTick()));
     return outVcState[out_vc].has_credit();
 }
 
@@ -85,7 +89,7 @@ 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()))
+        if (is_vc_idle(vc, curTick()))
             return true;
     }
 
@@ -98,8 +102,8 @@ 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())) {
-            outVcState[vc].setState(ACTIVE_, m_router->curCycle());
+        if (is_vc_idle(vc, curTick())) {
+            outVcState[vc].setState(ACTIVE_, curTick());
             return vc;
         }
     }
@@ -118,14 +122,18 @@ OutputUnit::select_free_vc(int vnet)
 void
 OutputUnit::wakeup()
 {
-    if (m_credit_link->isReady(m_router->curCycle())) {
+    if (m_credit_link->isReady(curTick())) {
         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());
+            set_vc_state(IDLE_, t_credit->get_vc(), curTick());
 
         delete t_credit;
+
+        if (m_credit_link->isReady(curTick())) {
+            scheduleEvent(Cycles(1));
+        }
     }
 }
 
index dbb35eeed605f71926b61f5f5c2406f0ba2b4448..699470730cfdd837baf6ee02973241bb89b6aa10 100644 (file)
@@ -75,13 +75,13 @@ class OutputUnit : public Consumer
     }
 
     inline void
-    set_vc_state(VC_state_type state, int vc, Cycles curTime)
+    set_vc_state(VC_state_type state, int vc, Tick curTime)
     {
       outVcState[vc].setState(state, curTime);
     }
 
     inline bool
-    is_vc_idle(int vc, Cycles curTime)
+    is_vc_idle(int vc, Tick curTime)
     {
         return (outVcState[vc].isInState(IDLE_, curTime));
     }
index 73b7dce2ee19068caa0f6bdcfd78541bdb96de9a..82d49e9bd678f5d8c16a1969467c854dd10e4105 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 2020 Inria
  * Copyright (c) 2016 Georgia Institute of Technology
  * Copyright (c) 2008 Princeton University
@@ -43,8 +44,9 @@ using namespace std;
 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_network_ptr(nullptr),
-    routingUnit(this), switchAllocator(this), crossbarSwitch(this)
+    m_num_vcs(m_virtual_networks * m_vc_per_vnet), m_bit_width(p->width),
+    m_network_ptr(nullptr), routingUnit(this), switchAllocator(this),
+    crossbarSwitch(this)
 {
     m_input_unit.clear();
     m_output_unit.clear();
@@ -63,6 +65,7 @@ void
 Router::wakeup()
 {
     DPRINTF(RubyNetwork, "Router %d woke up\n", m_id);
+    assert(clockEdge() == curTick());
 
     // check for incoming flits
     for (int inport = 0; inport < m_input_unit.size(); inport++) {
@@ -90,13 +93,17 @@ void
 Router::addInPort(PortDirection inport_dirn,
                   NetworkLink *in_link, CreditLink *credit_link)
 {
+    fatal_if(in_link->bitWidth != m_bit_width, "Widths of link %s(%d)does"
+            " not match that of Router%d(%d). Consider inserting SerDes "
+            "Units.", in_link->name(), in_link->bitWidth, m_id, m_bit_width);
+
     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());
+    credit_link->setSourceQueue(input_unit->getCreditQueue(), this);
 
     m_input_unit.push_back(std::shared_ptr<InputUnit>(input_unit));
 
@@ -106,16 +113,19 @@ Router::addInPort(PortDirection inport_dirn,
 void
 Router::addOutPort(PortDirection outport_dirn,
                    NetworkLink *out_link,
-                   const NetDest& routing_table_entry, int link_weight,
+                   std::vector<NetDest>& routing_table_entry, int link_weight,
                    CreditLink *credit_link)
 {
+    fatal_if(out_link->bitWidth != m_bit_width, "Widths of units do not match."
+            " Consider inserting SerDes Units");
+
     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());
+    out_link->setSourceQueue(output_unit->getOutQueue(), this);
 
     m_output_unit.push_back(std::shared_ptr<OutputUnit>(output_unit));
 
index 19fc7f007fe76b7913449ba576a69a1ea71b985f..ba3a581ab2f59a03b8ac5000a87e515f67093e30 100644 (file)
@@ -68,7 +68,7 @@ class Router : public BasicRouter, public Consumer
     void addInPort(PortDirection inport_dirn, NetworkLink *link,
                    CreditLink *credit_link);
     void addOutPort(PortDirection outport_dirn, NetworkLink *link,
-                    const NetDest& routing_table_entry,
+                    std::vector<NetDest>& routing_table_entry,
                     int link_weight, CreditLink *credit_link);
 
     Cycles get_pipe_stages(){ return m_latency; }
@@ -100,6 +100,8 @@ class Router : public BasicRouter, public Consumer
         return m_output_unit[port].get();
     }
 
+    int getBitWidth() { return m_bit_width; }
+
     PortDirection getOutportDirection(int outport);
     PortDirection getInportDirection(int inport);
 
@@ -131,6 +133,7 @@ class Router : public BasicRouter, public Consumer
   private:
     Cycles m_latency;
     int m_virtual_networks, m_vc_per_vnet, m_num_vcs;
+    uint32_t m_bit_width;
     GarnetNetwork *m_network_ptr;
 
     RoutingUnit routingUnit;
index 9c0d21b47a300178a5a9672994baf0a47b3e5dab..5ba0dec6b26616c022b7b153ffdba098a65e0f8a 100644 (file)
@@ -31,7 +31,7 @@
 #include "mem/ruby/network/garnet2.0/RoutingUnit.hh"
 
 #include "base/cast.hh"
-#include "base/logging.hh"
+#include "debug/RubyNetwork.hh"
 #include "mem/ruby/network/garnet2.0/InputUnit.hh"
 #include "mem/ruby/network/garnet2.0/Router.hh"
 #include "mem/ruby/slicc_interface/Message.hh"
@@ -44,9 +44,14 @@ RoutingUnit::RoutingUnit(Router *router)
 }
 
 void
-RoutingUnit::addRoute(const NetDest& routing_table_entry)
+RoutingUnit::addRoute(std::vector<NetDest>& routing_table_entry)
 {
-    m_routing_table.push_back(routing_table_entry);
+    if (routing_table_entry.size() > m_routing_table.size()) {
+        m_routing_table.resize(routing_table_entry.size());
+    }
+    for (int v = 0; v < routing_table_entry.size(); v++) {
+        m_routing_table[v].push_back(routing_table_entry[v]);
+    }
 }
 
 void
@@ -55,13 +60,29 @@ RoutingUnit::addWeight(int link_weight)
     m_weight_table.push_back(link_weight);
 }
 
+bool
+RoutingUnit::supportsVnet(int vnet, std::vector<int> sVnets)
+{
+    // If all vnets are supported, return true
+    if (sVnets.size() == 0) {
+        return true;
+    }
+
+    // Find the vnet in the vector, return true
+    if (std::find(sVnets.begin(), sVnets.end(), vnet) != sVnets.end()) {
+        return true;
+    }
+
+    // Not supported vnet
+    return false;
+}
+
 /*
  * 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)
 {
@@ -78,8 +99,9 @@ RoutingUnit::lookupRoutingTable(int vnet, NetDest msg_destination)
     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])) {
+    for (int link = 0; link < m_routing_table[vnet].size(); link++) {
+        if (msg_destination.intersectionIsNotEmpty(
+            m_routing_table[vnet][link])) {
 
         if (m_weight_table[link] <= min_weight)
             min_weight = m_weight_table[link];
@@ -87,11 +109,11 @@ RoutingUnit::lookupRoutingTable(int vnet, NetDest msg_destination)
     }
 
     // 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])) {
+    for (int link = 0; link < m_routing_table[vnet].size(); link++) {
+        if (msg_destination.intersectionIsNotEmpty(
+            m_routing_table[vnet][link])) {
 
             if (m_weight_table[link] == min_weight) {
-
                 num_candidates++;
                 output_link_candidates.push_back(link);
             }
index aff8f7e26c25cf255a7cafeec50de11c21727547..a0ed90127a07f9c055647274520e78c25495f9b2 100644 (file)
@@ -49,7 +49,7 @@ class RoutingUnit
                       PortDirection inport_dirn);
 
     // Topology-agnostic Routing Table based routing (default)
-    void addRoute(const NetDest& routing_table_entry);
+    void addRoute(std::vector<NetDest>& routing_table_entry);
     void addWeight(int link_weight);
 
     // get output port from routing table
@@ -69,11 +69,16 @@ class RoutingUnit
                              int inport,
                              PortDirection inport_dirn);
 
+    // Returns true if vnet is present in the vector
+    // of vnets or if the vector supports all vnets.
+    bool supportsVnet(int vnet, std::vector<int> sVnets);
+
+
   private:
     Router *m_router;
 
     // Routing Table
-    std::vector<NetDest> m_routing_table;
+    std::vector<std::vector<NetDest>> m_routing_table;
     std::vector<int> m_weight_table;
 
     // Inport and Outport direction to idx maps
index a621036c053aa839298113ef5f12d88ef0ca17a3..e3bc1108ab00ac8a46af0a846503906277879089 100644 (file)
@@ -49,3 +49,4 @@ Source('VirtualChannel.cc')
 Source('flitBuffer.cc')
 Source('flit.cc')
 Source('Credit.cc')
+Source('NetworkBridge.cc')
index 33cddc3f820ba88dd3f772187228f7f30fde8ee3..144f2085b5bbbe552777b90ca203090eeff60bd2 100644 (file)
@@ -114,7 +114,7 @@ SwitchAllocator::arbitrate_inports()
         for (int invc_iter = 0; invc_iter < m_num_vcs; invc_iter++) {
             auto input_unit = m_router->getInputUnit(inport);
 
-            if (input_unit->need_stage(invc, SA_, m_router->curCycle())) {
+            if (input_unit->need_stage(invc, SA_, curTick())) {
                 // This flit is in SA stage
 
                 int outport = input_unit->get_outport(invc);
@@ -192,7 +192,7 @@ SwitchAllocator::arbitrate_outports()
                 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",
+                                     "cycle: %lld\n",
                         m_router->get_id(), outvc,
                         m_router->getPortDirectionName(
                             output_unit->get_direction()),
@@ -218,7 +218,7 @@ SwitchAllocator::arbitrate_outports()
                 output_unit->decrement_credit(outvc);
 
                 // flit ready for Switch Traversal
-                t_flit->advance_stage(ST_, m_router->curCycle());
+                t_flit->advance_stage(ST_, curTick());
                 m_router->grant_switch(inport, t_flit);
                 m_output_arbiter_activity++;
 
@@ -226,20 +226,18 @@ SwitchAllocator::arbitrate_outports()
                     t_flit->get_type() == HEAD_TAIL_) {
 
                     // This Input VC should now be empty
-                    assert(!(input_unit->isReady(invc, m_router->curCycle())));
+                    assert(!(input_unit->isReady(invc, curTick())));
 
                     // Free this VC
-                    input_unit->set_vc_idle(invc, m_router->curCycle());
+                    input_unit->set_vc_idle(invc, curTick());
 
                     // Send a credit back
                     // along with the information that this VC is now idle
-                    input_unit->increment_credit(invc, true,
-                        m_router->curCycle());
+                    input_unit->increment_credit(invc, true, curTick());
                 } else {
                     // Send a credit back
                     // but do not indicate that the VC is idle
-                    input_unit->increment_credit(invc, false,
-                        m_router->curCycle());
+                    input_unit->increment_credit(invc, false, curTick());
                 }
 
                 // remove this request
@@ -313,14 +311,14 @@ SwitchAllocator::send_allowed(int inport, int invc, int outport, int outvc)
         auto input_unit = m_router->getInputUnit(inport);
 
         // enqueue time of this flit
-        Cycles t_enqueue_time = input_unit->get_enqueue_time(invc);
+        Tick t_enqueue_time = input_unit->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 (input_unit->need_stage(temp_vc, SA_, m_router->curCycle()) &&
+            if (input_unit->need_stage(temp_vc, SA_, curTick()) &&
                (input_unit->get_outport(temp_vc) == outport) &&
                (input_unit->get_enqueue_time(temp_vc) < t_enqueue_time)) {
                 return false;
@@ -350,7 +348,7 @@ SwitchAllocator::vc_allocate(int outport, int inport, int invc)
 void
 SwitchAllocator::check_for_wakeup()
 {
-    Cycles nextCycle = m_router->curCycle() + Cycles(1);
+    Tick nextCycle = m_router->clockEdge(Cycles(1));
 
     for (int i = 0; i < m_num_inports; i++) {
         for (int j = 0; j < m_num_vcs; j++) {
index a469a84fd4e69a43593d381135c002803e8915f8..0b53983f95ffc2057007f52786aab2c9ad694fcd 100644 (file)
 #include "mem/ruby/network/garnet2.0/VirtualChannel.hh"
 
 VirtualChannel::VirtualChannel()
-  : inputBuffer(), m_vc_state(IDLE_, Cycles(0)), m_output_port(-1),
+  : inputBuffer(), m_vc_state(IDLE_, Tick(0)), m_output_port(-1),
     m_enqueue_time(INFINITE_), m_output_vc(-1)
 {
 }
 
 void
-VirtualChannel::set_idle(Cycles curTime)
+VirtualChannel::set_idle(Tick curTime)
 {
     m_vc_state.first = IDLE_;
     m_vc_state.second = curTime;
-    m_enqueue_time = Cycles(INFINITE_);
+    m_enqueue_time = Tick(INFINITE_);
     m_output_port = -1;
     m_output_vc = -1;
 }
 
 void
-VirtualChannel::set_active(Cycles curTime)
+VirtualChannel::set_active(Tick curTime)
 {
     m_vc_state.first = ACTIVE_;
     m_vc_state.second = curTime;
@@ -56,7 +56,7 @@ VirtualChannel::set_active(Cycles curTime)
 }
 
 bool
-VirtualChannel::need_stage(flit_stage stage, Cycles time)
+VirtualChannel::need_stage(flit_stage stage, Tick time)
 {
     if (inputBuffer.isReady(time)) {
         assert(m_vc_state.first == ACTIVE_ && m_vc_state.second <= time);
index 752dfb440f035ea71c99f26407b378a84ed5ba77..f20629964a3dbba5264e98d74ef42e1c9ce7c726 100644 (file)
@@ -43,20 +43,20 @@ class VirtualChannel
     VirtualChannel();
     ~VirtualChannel() = default;
 
-    bool need_stage(flit_stage stage, Cycles time);
-    void set_idle(Cycles curTime);
-    void set_active(Cycles curTime);
+    bool need_stage(flit_stage stage, Tick time);
+    void set_idle(Tick curTime);
+    void set_active(Tick 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 Tick get_enqueue_time()          { return m_enqueue_time; }
+    inline void set_enqueue_time(Tick time) { m_enqueue_time = time; }
     inline VC_state_type get_state()        { return m_vc_state.first; }
 
     inline bool
-    isReady(Cycles curTime)
+    isReady(Tick curTime)
     {
         return inputBuffer.isReady(curTime);
     }
@@ -68,7 +68,7 @@ class VirtualChannel
     }
 
     inline void
-    set_state(VC_state_type m_state, Cycles curTime)
+    set_state(VC_state_type m_state, Tick curTime)
     {
         m_vc_state.first = m_state;
         m_vc_state.second = curTime;
@@ -90,9 +90,9 @@ class VirtualChannel
 
   private:
     flitBuffer inputBuffer;
-    std::pair<VC_state_type, Cycles> m_vc_state;
+    std::pair<VC_state_type, Tick> m_vc_state;
     int m_output_port;
-    Cycles m_enqueue_time;
+    Tick m_enqueue_time;
     int m_output_vc;
 };
 
index 4219e04f848bc3867f7cc8be10cbb3a34aa9fb72..28a79d4a40960df97d131b4c7bfcfc0daf561f65 100644 (file)
 
 #include "mem/ruby/network/garnet2.0/flit.hh"
 
+#include "base/intmath.hh"
+#include "debug/RubyNetwork.hh"
+
 // Constructor for the flit
 flit::flit(int id, int  vc, int vnet, RouteInfo route, int size,
-    MsgPtr msg_ptr, Cycles curTime)
+    MsgPtr msg_ptr, int MsgSize, uint32_t bWidth, Tick curTime)
 {
     m_size = size;
     m_msg_ptr = msg_ptr;
@@ -44,7 +47,9 @@ flit::flit(int id, int  vc, int vnet, RouteInfo route, int size,
     m_vc = vc;
     m_route = route;
     m_stage.first = I_;
-    m_stage.second = m_time;
+    m_stage.second = curTime;
+    m_width = bWidth;
+    msgSize = MsgSize;
 
     if (size == 1) {
         m_type = HEAD_TAIL_;
@@ -58,6 +63,38 @@ flit::flit(int id, int  vc, int vnet, RouteInfo route, int size,
         m_type = BODY_;
 }
 
+flit *
+flit::serialize(int ser_id, int parts, uint32_t bWidth)
+{
+    assert(m_width > bWidth);
+
+    int ratio = (int)divCeil(m_width, bWidth);
+    int new_id = (m_id*ratio) + ser_id;
+    int new_size = (int)divCeil((float)msgSize, (float)bWidth);
+    assert(new_id < new_size);
+
+    flit *fl = new flit(new_id, m_vc, m_vnet, m_route,
+                    new_size, m_msg_ptr, msgSize, bWidth, m_time);
+    fl->set_enqueue_time(m_enqueue_time);
+    fl->set_src_delay(src_delay);
+    return fl;
+}
+
+flit *
+flit::deserialize(int des_id, int num_flits, uint32_t bWidth)
+{
+    int ratio = (int)divCeil((float)bWidth, (float)m_width);
+    int new_id = ((int)divCeil((float)(m_id+1), (float)ratio)) - 1;
+    int new_size = (int)divCeil((float)msgSize, (float)bWidth);
+    assert(new_id < new_size);
+
+    flit *fl = new flit(new_id, m_vc, m_vnet, m_route,
+                    new_size, m_msg_ptr, msgSize, bWidth, m_time);
+    fl->set_enqueue_time(m_enqueue_time);
+    fl->set_src_delay(src_delay);
+    return fl;
+}
+
 // Flit can be printed out for debugging purposes
 void
 flit::print(std::ostream& out) const
@@ -65,13 +102,15 @@ flit::print(std::ostream& out) const
     out << "[flit:: ";
     out << "Id=" << m_id << " ";
     out << "Type=" << m_type << " ";
+    out << "Size=" << m_size << " ";
     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 << "Set Time=" << m_time << " ";
+    out << "Width=" << m_width<< " ";
     out << "]";
 }
 
index d5c1f66f6bc0c52c6a62a3459092c90488f6033f..1bbd152a7dd4bc9c7c80e55e631edef808ed3779 100644 (file)
@@ -43,41 +43,44 @@ class flit
   public:
     flit() {}
     flit(int id, int vc, int vnet, RouteInfo route, int size,
-         MsgPtr msg_ptr, Cycles curTime);
+         MsgPtr msg_ptr, int MsgSize, uint32_t bWidth, Tick curTime);
+
+    virtual ~flit(){};
 
     int get_outport() {return m_outport; }
     int get_size() { return m_size; }
-    Cycles get_enqueue_time() { return m_enqueue_time; }
-    Cycles get_dequeue_time() { return m_dequeue_time; }
+    Tick get_enqueue_time() { return m_enqueue_time; }
+    Tick get_dequeue_time() { return m_dequeue_time; }
     int get_id() { return m_id; }
-    Cycles get_time() { return m_time; }
+    Tick 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; }
+    std::pair<flit_stage, Tick> get_stage() { return m_stage; }
+    Tick get_src_delay() { return src_delay; }
 
     void set_outport(int port) { m_outport = port; }
-    void set_time(Cycles time) { m_time = time; }
+    void set_time(Tick 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 set_dequeue_time(Cycles time) { m_dequeue_time = time; }
+    void set_src_delay(Tick delay) { src_delay = delay; }
+    void set_dequeue_time(Tick time) { m_dequeue_time = time; }
+    void set_enqueue_time(Tick time) { m_enqueue_time = time; }
 
     void increment_hops() { m_route.hops_traversed++; }
-    void print(std::ostream& out) const;
+    virtual void print(std::ostream& out) const;
 
     bool
-    is_stage(flit_stage stage, Cycles time)
+    is_stage(flit_stage stage, Tick time)
     {
         return (stage == m_stage.first &&
                 time >= m_stage.second);
     }
 
     void
-    advance_stage(flit_stage t_stage, Cycles newTime)
+    advance_stage(flit_stage t_stage, Tick newTime)
     {
         m_stage.first = t_stage;
         m_stage.second = newTime;
@@ -96,18 +99,24 @@ class flit
 
     bool functionalWrite(Packet *pkt);
 
+    virtual flit* serialize(int ser_id, int parts, uint32_t bWidth);
+    virtual flit* deserialize(int des_id, int num_flits, uint32_t bWidth);
+
+    uint32_t m_width;
+    int msgSize;
   protected:
     int m_id;
     int m_vnet;
     int m_vc;
     RouteInfo m_route;
     int m_size;
-    Cycles m_enqueue_time, m_dequeue_time, m_time;
+    Tick m_enqueue_time, m_dequeue_time;
+    Tick m_time;
     flit_type m_type;
     MsgPtr m_msg_ptr;
     int m_outport;
-    Cycles src_delay;
-    std::pair<flit_stage, Cycles> m_stage;
+    Tick src_delay;
+    std::pair<flit_stage, Tick> m_stage;
 };
 
 inline std::ostream&
index 53b3e11db024ee6aaae73a91af7b5946fd265ab6..c72163985f860d01826cd7ad5b3d68111309af7a 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 2008 Princeton University
  * Copyright (c) 2016 Georgia Institute of Technology
  * All rights reserved.
@@ -47,7 +48,7 @@ flitBuffer::isEmpty()
 }
 
 bool
-flitBuffer::isReady(Cycles curTime)
+flitBuffer::isReady(Tick curTime)
 {
     if (m_buffer.size() != 0 ) {
         flit *t_flit = peekTopFlit();
index f4bb28bf92018e4a26152ecc912a28d3f4200e20..f98ecf6df02ee1aa36149fdf201ac04025a6a12e 100644 (file)
@@ -44,7 +44,7 @@ class flitBuffer
     flitBuffer();
     flitBuffer(int maximum_size);
 
-    bool isReady(Cycles curTime);
+    bool isReady(Tick curTime);
     bool isEmpty();
     void print(std::ostream& out) const;
     bool isFull();
index d3b5515123384509dd8e242111ab396ab49f74ca..edffc3d92c8a1fb419fff2a9a587d4915d1dda6b 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2020 Advanced Micro Devices, Inc.
  * Copyright (c) 2019 ARM Limited
  * All rights reserved.
  *
@@ -85,7 +86,7 @@ SimpleNetwork::init()
 void
 SimpleNetwork::makeExtOutLink(SwitchID src, NodeID global_dest,
                               BasicLink* link,
-                              const NetDest& routing_table_entry)
+                              std::vector<NetDest>& routing_table_entry)
 {
     NodeID local_dest = getLocalNodeID(global_dest);
     assert(local_dest < m_nodes);
@@ -95,14 +96,14 @@ SimpleNetwork::makeExtOutLink(SwitchID src, NodeID global_dest,
     SimpleExtLink *simple_link = safe_cast<SimpleExtLink*>(link);
 
     m_switches[src]->addOutPort(m_fromNetQueues[local_dest],
-                                routing_table_entry, simple_link->m_latency,
+                                routing_table_entry[0], simple_link->m_latency,
                                 simple_link->m_bw_multiplier);
 }
 
 // From an endpoint node to a switch
 void
 SimpleNetwork::makeExtInLink(NodeID global_src, SwitchID dest, BasicLink* link,
-                          const NetDest& routing_table_entry)
+                          std::vector<NetDest>& routing_table_entry)
 {
     NodeID local_src = getLocalNodeID(global_src);
     assert(local_src < m_nodes);
@@ -112,7 +113,7 @@ SimpleNetwork::makeExtInLink(NodeID global_src, SwitchID dest, BasicLink* link,
 // From a switch to a switch
 void
 SimpleNetwork::makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
-                                const NetDest& routing_table_entry,
+                                std::vector<NetDest>& routing_table_entry,
                                 PortDirection src_outport,
                                 PortDirection dst_inport)
 {
@@ -131,7 +132,7 @@ SimpleNetwork::makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
     SimpleIntLink *simple_link = safe_cast<SimpleIntLink*>(link);
 
     m_switches[dest]->addInPort(queues);
-    m_switches[src]->addOutPort(queues, routing_table_entry,
+    m_switches[src]->addOutPort(queues, routing_table_entry[0],
                                 simple_link->m_latency,
                                 simple_link->m_bw_multiplier);
 }
index b2e5080de59d8b4baf89356491c97609a6ac0761..90e26128fd3ad84fc59de9aac81db21d4bf17d90 100644 (file)
@@ -60,11 +60,11 @@ class SimpleNetwork : public Network
 
     // Methods used by Topology to setup the network
     void makeExtOutLink(SwitchID src, NodeID dest, BasicLink* link,
-                     const NetDest& routing_table_entry);
+                     std::vector<NetDest>& routing_table_entry);
     void makeExtInLink(NodeID src, SwitchID dest, BasicLink* link,
-                    const NetDest& routing_table_entry);
+                    std::vector<NetDest>& routing_table_entry);
     void makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
-                          const NetDest& routing_table_entry,
+                          std::vector<NetDest>& routing_table_entry,
                           PortDirection src_outport,
                           PortDirection dst_inport);