diff --git a/src/finn/custom_op/fpgadataflow/__init__.py b/src/finn/custom_op/fpgadataflow/__init__.py
index c0d5d6cc1984ab3d73bd5cb9c3bcfea5aab4773e..2a7df101817ba4892f48dd59df21dcc0f5a22b76 100644
--- a/src/finn/custom_op/fpgadataflow/__init__.py
+++ b/src/finn/custom_op/fpgadataflow/__init__.py
@@ -38,14 +38,50 @@ class HLSCustomOp(CustomOp):
 
         """
         self.code_gen_dict = {}
+        self.ipgen_template= """
+        #include "bnn-library.h"
+        // includes for network parameters
+        $GLOBALS$
+
+        // defines for network parameters
+        $DEFINES$
+        
+        $BLACKBOXFUNCTION$
+        {
+        $PRAGMAS$
+        $DOCOMPUTE$
+        }
+        """
 
     def get_nodeattr_types(self):
         return {
             "backend": ("s", True, "fpgadataflow"),
             "code_gen_dir_npysim": ("s", False, ""),
+            "code_gen_dir_ipgen": ("s", False, ""),
             "executable_path": ("s", False, ""),
         }
 
+    def code_generation_ipgen(self, model):
+        node = self.onnx_node
+        self.global_includes()
+        self.defines()
+        self.blackboxfunction()
+        self.pragmas()
+        self.docompute()
+
+        template = self.ipgen_template
+
+        for key in self.code_gen_dict:
+            # transform list into long string separated by '\n'
+            code_gen_line = "\n".join(self.code_gen_dict[key])
+            template = template.replace(key, code_gen_line)
+        code_gen_dir = self.get_nodeattr("code_gen_dir_ipgen")
+        f = open(os.path.join(code_gen_dir, "top_{}.cpp".format(node.op_type)), "w")
+        f.write(template)
+        f.close()
+        self.code_gen_dict.clear()
+
+
     def code_generation_npysim(self, model):
         node = self.onnx_node
         self.generate_params(model)
@@ -67,6 +103,7 @@ class HLSCustomOp(CustomOp):
         f = open(os.path.join(code_gen_dir, "execute_{}.cpp".format(node.op_type)), "w")
         f.write(template)
         f.close()
+        self.code_gen_dict.clear()
 
     def compile_singlenode_code(self):
         code_gen_dir = self.get_nodeattr("code_gen_dir_npysim")
@@ -161,3 +198,10 @@ compilation transformations?
     @abstractmethod
     def save_as_npy(self):
         pass
+
+    def blackboxfunction(self):
+        pass
+
+    def pragmas(self):
+        pass
+
diff --git a/src/finn/custom_op/fpgadataflow/convolutioninputgenerator.py b/src/finn/custom_op/fpgadataflow/convolutioninputgenerator.py
index 1afb4aab2b6f8f2de589d3448afd2fca06a287a0..4c1f5051d161f181e3523382494b129c1007cb77 100644
--- a/src/finn/custom_op/fpgadataflow/convolutioninputgenerator.py
+++ b/src/finn/custom_op/fpgadataflow/convolutioninputgenerator.py
@@ -168,3 +168,18 @@ class ConvolutionInputGenerator(HLSCustomOp):
 
     def save_as_npy(self):
         self.code_gen_dict["$SAVEASCNPY$"] = []
+
+    def blackboxfunction(self):
+        self.code_gen_dict["$BLACKBOXFUNCTION$"] = [
+            """void {}(hls::stream<ap_uint<SIMD1*Input_precision1>> &in,
+                hls::stream<ap_uint<SIMD1*Input_precision1>> &out)""".format(
+                self.onnx_node.name
+            )
+        ]
+
+    def pragmas(self):
+        self.code_gen_dict["$PRAGMAS$"] = ["#pragma HLS INTERFACE axis port=in"]
+        self.code_gen_dict["$PRAGMAS$"].append("#pragma HLS INTERFACE axis port=out")
+        self.code_gen_dict["$PRAGMAS$"].append(
+            "#pragma HLS INTERFACE ap_ctrl_none port=return"
+        )