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")