mem-garnet: Add masked functionalRead support

Recently the CHI protocol was introduced in Ruby.
The protocol introduces an alternative interface for
functional reads:

bool functionalRead(PacketPtr, WriteMask&)

This commit adds functionalRead(PacketPtr, WriteMask&)
implementations for various Garnet components.

Change-Id: Idd571899d679407b7b000c1a83a0a5420868cf28
Signed-off-by: Carlos Falquez <c.falquez@fz-juelich.de>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/46900
Tested-by: kokoro <noreply+kokoro@google.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Reviewed-by: Tiago Muck <tiago.muck@arm.com>
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
diff --git a/src/mem/ruby/network/garnet/CrossbarSwitch.cc b/src/mem/ruby/network/garnet/CrossbarSwitch.cc
index cae7113..b4d6696 100644
--- a/src/mem/ruby/network/garnet/CrossbarSwitch.cc
+++ b/src/mem/ruby/network/garnet/CrossbarSwitch.cc
@@ -91,6 +91,17 @@
     }
 }
 
+bool
+CrossbarSwitch::functionalRead(Packet *pkt, WriteMask &mask)
+{
+    bool read = false;
+    for (auto& switch_buffer : switchBuffers) {
+        if (switch_buffer.functionalRead(pkt, mask))
+            read = true;
+   }
+   return read;
+}
+
 uint32_t
 CrossbarSwitch::functionalWrite(Packet *pkt)
 {
diff --git a/src/mem/ruby/network/garnet/CrossbarSwitch.hh b/src/mem/ruby/network/garnet/CrossbarSwitch.hh
index 8ab632e..b497078 100644
--- a/src/mem/ruby/network/garnet/CrossbarSwitch.hh
+++ b/src/mem/ruby/network/garnet/CrossbarSwitch.hh
@@ -67,6 +67,7 @@
 
     inline double get_crossbar_activity() { return m_crossbar_activity; }
 
+    bool functionalRead(Packet *pkt, WriteMask &mask);
     uint32_t functionalWrite(Packet *pkt);
     void resetStats();
 
diff --git a/src/mem/ruby/network/garnet/GarnetNetwork.cc b/src/mem/ruby/network/garnet/GarnetNetwork.cc
index 01b2473..5792269 100644
--- a/src/mem/ruby/network/garnet/GarnetNetwork.cc
+++ b/src/mem/ruby/network/garnet/GarnetNetwork.cc
@@ -197,10 +197,12 @@
     if (garnet_link->extBridgeEn) {
         DPRINTF(RubyNetwork, "Enable external bridge for %s\n",
             garnet_link->name());
+        NetworkBridge *n_bridge = garnet_link->extNetBridge[LinkDirection_In];
         m_nis[local_src]->
-        addOutPort(garnet_link->extNetBridge[LinkDirection_In],
+        addOutPort(n_bridge,
                    garnet_link->extCredBridge[LinkDirection_In],
                    dest, m_routers[dest]->get_vc_per_vnet());
+        m_networkbridges.push_back(n_bridge);
     } else {
         m_nis[local_src]->addOutPort(net_link, credit_link, dest,
             m_routers[dest]->get_vc_per_vnet());
@@ -209,10 +211,12 @@
     if (garnet_link->intBridgeEn) {
         DPRINTF(RubyNetwork, "Enable internal bridge for %s\n",
             garnet_link->name());
+        NetworkBridge *n_bridge = garnet_link->intNetBridge[LinkDirection_In];
         m_routers[dest]->
             addInPort(dst_inport_dirn,
-                      garnet_link->intNetBridge[LinkDirection_In],
+                      n_bridge,
                       garnet_link->intCredBridge[LinkDirection_In]);
+        m_networkbridges.push_back(n_bridge);
     } else {
         m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
     }
@@ -266,9 +270,10 @@
     if (garnet_link->extBridgeEn) {
         DPRINTF(RubyNetwork, "Enable external bridge for %s\n",
             garnet_link->name());
+        NetworkBridge *n_bridge = garnet_link->extNetBridge[LinkDirection_Out];
         m_nis[local_dest]->
-            addInPort(garnet_link->extNetBridge[LinkDirection_Out],
-                      garnet_link->extCredBridge[LinkDirection_Out]);
+            addInPort(n_bridge, garnet_link->extCredBridge[LinkDirection_Out]);
+        m_networkbridges.push_back(n_bridge);
     } else {
         m_nis[local_dest]->addInPort(net_link, credit_link);
     }
@@ -276,12 +281,14 @@
     if (garnet_link->intBridgeEn) {
         DPRINTF(RubyNetwork, "Enable internal bridge for %s\n",
             garnet_link->name());
+        NetworkBridge *n_bridge = garnet_link->intNetBridge[LinkDirection_Out];
         m_routers[src]->
             addOutPort(src_outport_dirn,
-                       garnet_link->intNetBridge[LinkDirection_Out],
+                       n_bridge,
                        routing_table_entry, link->m_weight,
                        garnet_link->intCredBridge[LinkDirection_Out],
                        m_routers[src]->get_vc_per_vnet());
+        m_networkbridges.push_back(n_bridge);
     } else {
         m_routers[src]->
             addOutPort(src_outport_dirn, net_link,
@@ -332,8 +339,10 @@
     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);
+        NetworkBridge *n_bridge = garnet_link->dstNetBridge;
+        m_routers[dest]->addInPort(dst_inport_dirn, n_bridge,
+                                   garnet_link->dstCredBridge);
+        m_networkbridges.push_back(n_bridge);
     } else {
         m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
     }
@@ -341,11 +350,13 @@
     if (garnet_link->srcBridgeEn) {
         DPRINTF(RubyNetwork, "Enable source bridge for %s\n",
             garnet_link->name());
+        NetworkBridge *n_bridge = garnet_link->srcNetBridge;
         m_routers[src]->
-            addOutPort(src_outport_dirn, garnet_link->srcNetBridge,
+            addOutPort(src_outport_dirn, n_bridge,
                        routing_table_entry,
                        link->m_weight, garnet_link->srcCredBridge,
                        m_routers[dest]->get_vc_per_vnet());
+        m_networkbridges.push_back(n_bridge);
     } else {
         m_routers[src]->addOutPort(src_outport_dirn, net_link,
                         routing_table_entry,
@@ -604,6 +615,33 @@
         (*m_ctrl_traffic_distribution[src_node][dest_node])++;
 }
 
+bool
+GarnetNetwork::functionalRead(Packet *pkt, WriteMask &mask)
+{
+    bool read = false;
+    for (unsigned int i = 0; i < m_routers.size(); i++) {
+        if (m_routers[i]->functionalRead(pkt, mask))
+            read = true;
+    }
+
+    for (unsigned int i = 0; i < m_nis.size(); ++i) {
+        if (m_nis[i]->functionalRead(pkt, mask))
+            read = true;
+    }
+
+    for (unsigned int i = 0; i < m_networklinks.size(); ++i) {
+        if (m_networklinks[i]->functionalRead(pkt, mask))
+            read = true;
+    }
+
+    for (unsigned int i = 0; i < m_networkbridges.size(); ++i) {
+        if (m_networkbridges[i]->functionalRead(pkt, mask))
+            read = true;
+    }
+
+    return read;
+}
+
 uint32_t
 GarnetNetwork::functionalWrite(Packet *pkt)
 {
diff --git a/src/mem/ruby/network/garnet/GarnetNetwork.hh b/src/mem/ruby/network/garnet/GarnetNetwork.hh
index d18caae..db37628 100644
--- a/src/mem/ruby/network/garnet/GarnetNetwork.hh
+++ b/src/mem/ruby/network/garnet/GarnetNetwork.hh
@@ -55,6 +55,7 @@
 class NetworkInterface;
 class Router;
 class NetworkLink;
+class NetworkBridge;
 class CreditLink;
 
 class GarnetNetwork : public Network
@@ -105,6 +106,7 @@
                           PortDirection src_outport_dirn,
                           PortDirection dest_inport_dirn);
 
+    bool functionalRead(Packet *pkt, WriteMask &mask);
     //! Function for performing a functional write. The return value
     //! indicates the number of messages that were written.
     uint32_t functionalWrite(Packet *pkt);
@@ -208,6 +210,7 @@
     std::vector<VNET_type > m_vnet_type;
     std::vector<Router *> m_routers;   // All Routers in Network
     std::vector<NetworkLink *> m_networklinks; // All flit links in the network
+    std::vector<NetworkBridge *> m_networkbridges; // All network bridges
     std::vector<CreditLink *> m_creditlinks; // All credit links in the network
     std::vector<NetworkInterface *> m_nis;   // All NI's in Network
     int m_next_packet_id; // static vairable for packet id allocation
diff --git a/src/mem/ruby/network/garnet/InputUnit.cc b/src/mem/ruby/network/garnet/InputUnit.cc
index e8515a6..179bb64 100644
--- a/src/mem/ruby/network/garnet/InputUnit.cc
+++ b/src/mem/ruby/network/garnet/InputUnit.cc
@@ -151,6 +151,17 @@
     m_credit_link->scheduleEventAbsolute(m_router->clockEdge(Cycles(1)));
 }
 
+bool
+InputUnit::functionalRead(Packet *pkt, WriteMask &mask)
+{
+    bool read = false;
+    for (auto& virtual_channel : virtualChannels) {
+        if (virtual_channel.functionalRead(pkt, mask))
+            read = true;
+    }
+
+    return read;
+}
 
 uint32_t
 InputUnit::functionalWrite(Packet *pkt)
diff --git a/src/mem/ruby/network/garnet/InputUnit.hh b/src/mem/ruby/network/garnet/InputUnit.hh
index cc9bb1a..4c4baeb 100644
--- a/src/mem/ruby/network/garnet/InputUnit.hh
+++ b/src/mem/ruby/network/garnet/InputUnit.hh
@@ -152,7 +152,9 @@
     double get_buf_write_activity(unsigned int vnet) const
     { return m_num_buffer_writes[vnet]; }
 
+    bool functionalRead(Packet *pkt, WriteMask &mask);
     uint32_t functionalWrite(Packet *pkt);
+
     void resetStats();
 
   private:
diff --git a/src/mem/ruby/network/garnet/NetworkInterface.cc b/src/mem/ruby/network/garnet/NetworkInterface.cc
index 1154718..31d625c 100644
--- a/src/mem/ruby/network/garnet/NetworkInterface.cc
+++ b/src/mem/ruby/network/garnet/NetworkInterface.cc
@@ -668,6 +668,23 @@
     out << "[Network Interface]";
 }
 
+bool
+NetworkInterface::functionalRead(Packet *pkt, WriteMask &mask)
+{
+    bool read = false;
+    for (auto& ni_out_vc : niOutVcs) {
+        if (ni_out_vc.functionalRead(pkt, mask))
+            read = true;
+    }
+
+    for (auto &oPort: outPorts) {
+        if (oPort->outFlitQueue()->functionalRead(pkt, mask))
+            read = true;
+    }
+
+    return read;
+}
+
 uint32_t
 NetworkInterface::functionalWrite(Packet *pkt)
 {
diff --git a/src/mem/ruby/network/garnet/NetworkInterface.hh b/src/mem/ruby/network/garnet/NetworkInterface.hh
index b5affa0..d42db5e 100644
--- a/src/mem/ruby/network/garnet/NetworkInterface.hh
+++ b/src/mem/ruby/network/garnet/NetworkInterface.hh
@@ -79,6 +79,7 @@
     int get_vnet(int vc);
     void init_net_ptr(GarnetNetwork *net_ptr) { m_net_ptr = net_ptr; }
 
+    bool functionalRead(Packet *pkt, WriteMask &mask);
     uint32_t functionalWrite(Packet *);
 
     void scheduleFlit(flit *t_flit);
diff --git a/src/mem/ruby/network/garnet/NetworkLink.cc b/src/mem/ruby/network/garnet/NetworkLink.cc
index 38a8eac..43bb6c3 100644
--- a/src/mem/ruby/network/garnet/NetworkLink.cc
+++ b/src/mem/ruby/network/garnet/NetworkLink.cc
@@ -119,6 +119,12 @@
     m_link_utilized = 0;
 }
 
+bool
+NetworkLink::functionalRead(Packet *pkt, WriteMask &mask)
+{
+    return linkBuffer.functionalRead(pkt, mask);
+}
+
 uint32_t
 NetworkLink::functionalWrite(Packet *pkt)
 {
diff --git a/src/mem/ruby/network/garnet/NetworkLink.hh b/src/mem/ruby/network/garnet/NetworkLink.hh
index 449d2bc..b60a513 100644
--- a/src/mem/ruby/network/garnet/NetworkLink.hh
+++ b/src/mem/ruby/network/garnet/NetworkLink.hh
@@ -81,6 +81,7 @@
     inline flit* peekLink() { return linkBuffer.peekTopFlit(); }
     inline flit* consumeLink() { return linkBuffer.getTopFlit(); }
 
+    bool functionalRead(Packet *pkt, WriteMask &mask);
     uint32_t functionalWrite(Packet *);
     void resetStats();
 
diff --git a/src/mem/ruby/network/garnet/OutputUnit.cc b/src/mem/ruby/network/garnet/OutputUnit.cc
index e669c36..d5ad753 100644
--- a/src/mem/ruby/network/garnet/OutputUnit.cc
+++ b/src/mem/ruby/network/garnet/OutputUnit.cc
@@ -172,6 +172,12 @@
     m_out_link->scheduleEventAbsolute(m_router->clockEdge(Cycles(1)));
 }
 
+bool
+OutputUnit::functionalRead(Packet *pkt, WriteMask &mask)
+{
+    return outBuffer.functionalRead(pkt, mask);
+}
+
 uint32_t
 OutputUnit::functionalWrite(Packet *pkt)
 {
diff --git a/src/mem/ruby/network/garnet/OutputUnit.hh b/src/mem/ruby/network/garnet/OutputUnit.hh
index 703c625..b07035c 100644
--- a/src/mem/ruby/network/garnet/OutputUnit.hh
+++ b/src/mem/ruby/network/garnet/OutputUnit.hh
@@ -104,6 +104,7 @@
         return m_vc_per_vnet;
     }
 
+    bool functionalRead(Packet *pkt, WriteMask &mask);
     uint32_t functionalWrite(Packet *pkt);
 
   private:
diff --git a/src/mem/ruby/network/garnet/Router.cc b/src/mem/ruby/network/garnet/Router.cc
index 2e5b0fe..5232b91 100644
--- a/src/mem/ruby/network/garnet/Router.cc
+++ b/src/mem/ruby/network/garnet/Router.cc
@@ -274,6 +274,26 @@
     out << aggregate_fault_prob << std::endl;
 }
 
+bool
+Router::functionalRead(Packet *pkt, WriteMask &mask)
+{
+    bool read = false;
+    if (crossbarSwitch.functionalRead(pkt, mask))
+        read = true;
+
+    for (uint32_t i = 0; i < m_input_unit.size(); i++) {
+        if (m_input_unit[i]->functionalRead(pkt, mask))
+            read = true;
+    }
+
+    for (uint32_t i = 0; i < m_output_unit.size(); i++) {
+        if (m_output_unit[i]->functionalRead(pkt, mask))
+            read = true;
+    }
+
+    return read;
+}
+
 uint32_t
 Router::functionalWrite(Packet *pkt)
 {
diff --git a/src/mem/ruby/network/garnet/Router.hh b/src/mem/ruby/network/garnet/Router.hh
index 874f6f7..dbcdda9 100644
--- a/src/mem/ruby/network/garnet/Router.hh
+++ b/src/mem/ruby/network/garnet/Router.hh
@@ -139,6 +139,7 @@
                                                       aggregate_fault_prob);
     }
 
+    bool functionalRead(Packet *pkt, WriteMask &mask);
     uint32_t functionalWrite(Packet *);
 
   private:
diff --git a/src/mem/ruby/network/garnet/VirtualChannel.cc b/src/mem/ruby/network/garnet/VirtualChannel.cc
index a473bca..18e89a0 100644
--- a/src/mem/ruby/network/garnet/VirtualChannel.cc
+++ b/src/mem/ruby/network/garnet/VirtualChannel.cc
@@ -75,6 +75,12 @@
     return false;
 }
 
+bool
+VirtualChannel::functionalRead(Packet *pkt, WriteMask &mask)
+{
+    return inputBuffer.functionalRead(pkt, mask);
+}
+
 uint32_t
 VirtualChannel::functionalWrite(Packet *pkt)
 {
diff --git a/src/mem/ruby/network/garnet/VirtualChannel.hh b/src/mem/ruby/network/garnet/VirtualChannel.hh
index 29f3698..04b046b 100644
--- a/src/mem/ruby/network/garnet/VirtualChannel.hh
+++ b/src/mem/ruby/network/garnet/VirtualChannel.hh
@@ -95,6 +95,7 @@
         return inputBuffer.getTopFlit();
     }
 
+    bool functionalRead(Packet *pkt, WriteMask &mask);
     uint32_t functionalWrite(Packet *pkt);
 
   private:
diff --git a/src/mem/ruby/network/garnet/flit.cc b/src/mem/ruby/network/garnet/flit.cc
index b65297c..d31d826 100644
--- a/src/mem/ruby/network/garnet/flit.cc
+++ b/src/mem/ruby/network/garnet/flit.cc
@@ -126,6 +126,13 @@
 }
 
 bool
+flit::functionalRead(Packet *pkt, WriteMask &mask)
+{
+    Message *msg = m_msg_ptr.get();
+    return msg->functionalRead(pkt, mask);
+}
+
+bool
 flit::functionalWrite(Packet *pkt)
 {
     Message *msg = m_msg_ptr.get();
diff --git a/src/mem/ruby/network/garnet/flit.hh b/src/mem/ruby/network/garnet/flit.hh
index a84dc57..a52d741 100644
--- a/src/mem/ruby/network/garnet/flit.hh
+++ b/src/mem/ruby/network/garnet/flit.hh
@@ -107,6 +107,7 @@
         }
     }
 
+    bool functionalRead(Packet *pkt, WriteMask &mask);
     bool functionalWrite(Packet *pkt);
 
     virtual flit* serialize(int ser_id, int parts, uint32_t bWidth);
diff --git a/src/mem/ruby/network/garnet/flitBuffer.cc b/src/mem/ruby/network/garnet/flitBuffer.cc
index b6a2e0a..6b3b56c 100644
--- a/src/mem/ruby/network/garnet/flitBuffer.cc
+++ b/src/mem/ruby/network/garnet/flitBuffer.cc
@@ -85,6 +85,19 @@
     max_size = maximum;
 }
 
+bool
+flitBuffer::functionalRead(Packet *pkt, WriteMask &mask)
+{
+    bool read = false;
+    for (unsigned int i = 0; i < m_buffer.size(); ++i) {
+        if (m_buffer[i]->functionalRead(pkt, mask)) {
+            read = true;
+        }
+    }
+
+    return read;
+}
+
 uint32_t
 flitBuffer::functionalWrite(Packet *pkt)
 {
diff --git a/src/mem/ruby/network/garnet/flitBuffer.hh b/src/mem/ruby/network/garnet/flitBuffer.hh
index d37f9a5..089c931 100644
--- a/src/mem/ruby/network/garnet/flitBuffer.hh
+++ b/src/mem/ruby/network/garnet/flitBuffer.hh
@@ -80,6 +80,7 @@
         m_buffer.push_back(flt);
     }
 
+    bool functionalRead(Packet *pkt, WriteMask &mask);
     uint32_t functionalWrite(Packet *pkt);
 
   private: