From 4672031c90861297a93556a40c71a8c32db4d4e1 Mon Sep 17 00:00:00 2001
From: Yaman Umuroglu <maltanar@gmail.com>
Date: Tue, 11 Feb 2020 18:50:40 +0100
Subject: [PATCH] [CustomOp] add StreamingDataflowPartition CustomOp

---
 src/finn/custom_op/registry.py                |  2 +
 .../custom_op/streamingdataflowpartition.py   | 65 +++++++++++++++++++
 2 files changed, 67 insertions(+)
 create mode 100644 src/finn/custom_op/streamingdataflowpartition.py

diff --git a/src/finn/custom_op/registry.py b/src/finn/custom_op/registry.py
index bd1605c96..c38a28dae 100644
--- a/src/finn/custom_op/registry.py
+++ b/src/finn/custom_op/registry.py
@@ -7,6 +7,7 @@ from finn.custom_op.fpgadataflow.streamingfclayer_batch import StreamingFCLayer_
 from finn.custom_op.fpgadataflow.streamingmaxpool_batch import StreamingMaxPool_Batch
 from finn.custom_op.fpgadataflow.tlastmarker import TLastMarker
 from finn.custom_op.multithreshold import MultiThreshold
+from finn.custom_op.streamingdataflowpartition import StreamingDataflowPartition
 from finn.custom_op.xnorpopcount import XnorPopcountMatMul
 
 # create a mapping of all known CustomOp names and classes
@@ -18,6 +19,7 @@ custom_op["StreamingMaxPool_Batch"] = StreamingMaxPool_Batch
 custom_op["StreamingFCLayer_Batch"] = StreamingFCLayer_Batch
 custom_op["ConvolutionInputGenerator"] = ConvolutionInputGenerator
 custom_op["TLastMarker"] = TLastMarker
+custom_op["StreamingDataflowPartition"] = StreamingDataflowPartition
 
 
 def getCustomOp(node):
diff --git a/src/finn/custom_op/streamingdataflowpartition.py b/src/finn/custom_op/streamingdataflowpartition.py
new file mode 100644
index 000000000..856ba6d56
--- /dev/null
+++ b/src/finn/custom_op/streamingdataflowpartition.py
@@ -0,0 +1,65 @@
+from finn.custom_op import CustomOp
+
+# note that the StreamingDataflowPartition node is only a meta/container node,
+# it does not produce any HLS or bitfile by itself. it's a placeholder for
+# a group of fpgadataflow nodes that have been separated out into a FINN-ONNX
+# model of its own.
+
+
+class StreamingDataflowPartition(CustomOp):
+    def get_nodeattr_types(self):
+        return {
+            "model": ("s", True, ""),
+        }
+
+    def make_shape_compatible_op(self):
+        pass
+
+    def infer_node_datatype(self, model):
+        pass
+
+    def execute_node(self, context, graph):
+        # TODO add RPC execution with synthesized bitfile?
+        # whole-design rtlsim with PyVerilator may also be an alternative
+        pass
+
+    def verify_node(self):
+        info_messages = []
+
+        # verify number of attributes
+        num_of_attr = 1
+        if len(self.onnx_node.attribute) == num_of_attr:
+            info_messages.append("The number of attributes is correct")
+        else:
+            info_messages.append(
+                """The number of attributes is incorrect,
+            {} should have {} attributes""".format(
+                    self.onnx_node.op_type, num_of_attr
+                )
+            )
+
+        # verify that "domain" is set to "finn"
+        domain_value = self.onnx_node.domain
+        if domain_value == "finn":
+            info_messages.append("Attribute domain is set correctly")
+        else:
+            info_messages.append('Attribute domain should be set to "finn"')
+
+        # verify that all necessary attributes exist
+        try:
+            self.get_nodeattr("model")
+            info_messages.append("All necessary attributes exist")
+        except Exception:
+            info_messages.append(
+                """The necessary attributes do not exist.
+                StreamingDataflowPartition needs the following attribute(s):
+                model"""
+            )
+
+        # verify the number of inputs
+        if len(self.onnx_node.input) == 1:
+            info_messages.append("The number of inputs is correct")
+        else:
+            info_messages.append("StreamingDataflowPartition needs 1 data input")
+
+        return info_messages
-- 
GitLab