diff --git a/src/finn/transformation/fpgadataflow/codegen_ipstitch.py b/src/finn/transformation/fpgadataflow/codegen_ipstitch.py
index 4cb148b17610719276410c4fa35a27bee6ac7493..a39b3c439db4ac4cbc1f2c2e9a39993e9adbc447 100644
--- a/src/finn/transformation/fpgadataflow/codegen_ipstitch.py
+++ b/src/finn/transformation/fpgadataflow/codegen_ipstitch.py
@@ -88,6 +88,7 @@ class CodeGen_ipstitch(Transformation):
                 )
 
         # create a temporary folder for the project
+        prjname = "finn_vivado_stitch_proj"
         vivado_stitch_proj_dir = make_build_dir(prefix="vivado_stitch_proj_")
         model.set_metadata_prop("vivado_stitch_proj", vivado_stitch_proj_dir)
         # start building the tcl script
@@ -95,7 +96,7 @@ class CodeGen_ipstitch(Transformation):
         # create vivado project
         tcl.append(
             "create_project %s %s -part %s"
-            % ("finn_vivado_stitch_proj", vivado_stitch_proj_dir, self.fpgapart)
+            % (prjname, vivado_stitch_proj_dir, self.fpgapart)
         )
         # add all the generated IP dirs to ip_repo_paths
         ip_dirs_str = " ".join(ip_dirs)
@@ -125,6 +126,23 @@ class CodeGen_ipstitch(Transformation):
         tcl.append("ipx::create_xgui_files [ipx::find_open_core %s]" % block_vlnv)
         tcl.append("ipx::update_checksums [ipx::find_open_core %s]" % block_vlnv)
         tcl.append("ipx::save_core [ipx::find_open_core %s]" % block_vlnv)
+        # create wrapper hdl (for rtlsim later on)
+        bd_base = "%s/%s.srcs/sources_1/bd/%s" % (
+            vivado_stitch_proj_dir,
+            prjname,
+            block_name,
+        )
+        bd_filename = "%s/%s.bd" % (bd_base, block_name)
+        tcl.append("make_wrapper -files [get_files %s] -top" % bd_filename)
+        wrapper_filename = "%s/hdl/%s_wrapper.v" % (bd_base, block_name)
+        tcl.append("add_files -norecurse %s" % wrapper_filename)
+        model.set_metadata_prop("wrapper_filename", wrapper_filename)
+        # export list of used Verilog files (for rtlsim later on)
+        tcl.append("set all_v_files [get_files -filter {FILE_TYPE == Verilog}]")
+        v_file_list = "%s/all_verilog_srcs.txt" % vivado_stitch_proj_dir
+        tcl.append("set fp [open %s w]" % v_file_list)
+        tcl.append("puts $fp $all_v_files")
+        tcl.append("close $fp")
         # write the project creator tcl script
         tcl_string = "\n".join(tcl) + "\n"
         with open(vivado_stitch_proj_dir + "/make_project.tcl", "w") as f:
diff --git a/src/finn/util/fpgadataflow.py b/src/finn/util/fpgadataflow.py
index 9434b16ecc1ce4f6d05e5692a00cdfe9c59edbb6..f11192a121a4b4a8a0524629fe6b3988923a363b 100644
--- a/src/finn/util/fpgadataflow.py
+++ b/src/finn/util/fpgadataflow.py
@@ -1,12 +1,8 @@
-import subprocess
 import os
-import numpy as np
+import subprocess
+
+from pyverilator import PyVerilator
 
-from finn.core.datatype import DataType
-from finn.util.data_packing import (
-    pack_innermost_dim_as_hex_string,
-    unpack_innermost_dim_from_hex_string,
-)
 
 class IPGenBuilder:
     def __init__(self):
@@ -34,3 +30,18 @@ class IPGenBuilder:
         bash_command = ["bash", self.ipgen_script]
         process_compile = subprocess.Popen(bash_command, stdout=subprocess.PIPE)
         process_compile.communicate()
+
+
+def pyverilate_stitched_ip(model):
+    "Given a model with stitched IP, return a PyVerilator sim object."
+    vivado_stitch_proj_dir = model.get_metadata_prop("vivado_stitch_proj")
+    with open(vivado_stitch_proj_dir + "/all_verilog_srcs.txt", "r") as f:
+        all_verilog_srcs = f.read().split()
+
+    def file_to_dir(x):
+        return os.path.dirname(os.path.realpath(x))
+
+    all_verilog_dirs = list(map(file_to_dir, all_verilog_srcs))
+    top_verilog = model.get_metadata_prop("wrapper_filename")
+    sim = PyVerilator.build(top_verilog, verilog_path=all_verilog_dirs)
+    return sim
diff --git a/tests/fpgadataflow/test_fpgadataflow_ip_stitch.py b/tests/fpgadataflow/test_fpgadataflow_ip_stitch.py
index 11b6dc63065fb376f95f44dd92319439321c78f8..1795887f30145059213cbe1c1821cf569c40d28b 100644
--- a/tests/fpgadataflow/test_fpgadataflow_ip_stitch.py
+++ b/tests/fpgadataflow/test_fpgadataflow_ip_stitch.py
@@ -23,6 +23,7 @@ from finn.util.basic import (
     make_build_dir,
     pynq_part_map,
 )
+from finn.util.fpgadataflow import pyverilate_stitched_ip
 
 test_pynq_board = os.getenv("PYNQ_BOARD", default="Pynq-Z1")
 test_fpga_part = pynq_part_map[test_pynq_board]
@@ -207,6 +208,25 @@ def test_fpgadataflow_ipstitch_do_stitch():
     model.save(ip_stitch_model_dir + "/test_fpgadataflow_ip_stitch.onnx")
 
 
+@pytest.mark.dependency(depends=["test_fpgadataflow_ipstitch_do_stitch"])
+def test_fpgadataflow_ipstitch_rtlsim():
+    model = ModelWrapper(ip_stitch_model_dir + "/test_fpgadataflow_ip_stitch.onnx")
+    sim = pyverilate_stitched_ip(model)
+    exp_io = [
+        "ap_clk_0",
+        "ap_rst_n_0",
+        "in0_V_V_0_tdata",
+        "in0_V_V_0_tready",
+        "in0_V_V_0_tvalid",
+        "out_r_0_tdata",
+        "out_r_0_tkeep",
+        "out_r_0_tlast",
+        "out_r_0_tready",
+        "out_r_0_tvalid",
+    ]
+    assert dir(sim.io) == exp_io
+
+
 @pytest.mark.dependency(depends=["test_fpgadataflow_ipstitch_do_stitch"])
 def test_fpgadataflow_ipstitch_pynq_projgen():
     model = ModelWrapper(ip_stitch_model_dir + "/test_fpgadataflow_ip_stitch.onnx")