diff --git a/src/finn/transformation/fpgadataflow/make_pynq_proj.py b/src/finn/transformation/fpgadataflow/make_pynq_proj.py new file mode 100644 index 0000000000000000000000000000000000000000..bdb618c37127479cebb52ba821f1b097fc228b9d --- /dev/null +++ b/src/finn/transformation/fpgadataflow/make_pynq_proj.py @@ -0,0 +1,93 @@ +import os +import subprocess +import tempfile as tmp + +from finn.core.utils import get_by_name +from finn.transformation import Transformation + + +class MakePYNQProject(Transformation): + """Create a PYNQ project (including the shell infrastructure) from the + already-stitched IP block for this graph. + All nodes in the graph must have the fpgadataflow backend attribute, + and the CodeGen_ipstitch transformation must have been previously run on + the graph. + + Outcome if successful: sets the vivado_pynq_proj attribute in the ONNX + ModelProto's metadata_props field, with the created project dir as the + value. + """ + + def __init__(self, platform): + super().__init__() + self.platform = platform + + def apply(self, model): + pynq_shell_path = os.environ["PYNQSHELL_PATH"] + if not os.path.isdir(pynq_shell_path): + raise Exception("Ensure the PYNQ-HelloWorld utility repo is cloned.") + ipstitch_path = model.get_metadata_prop("vivado_pynq_proj") + if ipstitch_path is None or (not os.path.isdir(ipstitch_path)): + raise Exception("No stitched IPI design found, apply CodeGen_ipstitch first.") + + # TODO extract the actual in-out bytes from graph + in_bytes = 8 + out_bytes = 8 + in_if_name = "in0_V_V" + out_if_name = "out_V_V" + + # create a temporary folder for the project + vivado_pynq_proj_dir = tmp.mkdtemp(prefix="vivado_pynq_proj_") + model.set_metadata_prop("vivado_pynq_proj", vivado_pynq_proj_dir) + + ip_config_tcl = """ +variable config_ip_repo +variable config_ip_vlnv +variable config_ip_bytes_in +variable config_ip_bytes_out +variable config_ip_axis_name_in +variable config_ip_axis_name_out +variable config_ip_use_axilite +variable config_ip_project_dir + +# for arguments involving paths below: use absolute paths or relative to the +# platform/overlay/bitstream folder +# where to create the project +set config_ip_project_dir %s +# IP repositories that the project depends on +set config_ip_repo %s + +# non-path arguments +# VLNV of the IP block +set config_ip_vlnv xilinx.com:hls:resize_accel:1.0 +# width of the AXI stream into the IP, in bytes +set config_ip_bytes_in %d +# width of the AXI stream out of the IP, in bytes +set config_ip_bytes_out %d +# the name of the input AXI stream interface +set config_ip_axis_name_in %s +# the name of the output AXI stream interface +set config_ip_axis_name_out %s +# whether the IP needs an AXI Lite interface for control +set config_ip_use_axilite 0 + """ % ( + vivado_pynq_proj_dir, ipstitch_path + "/ip", in_bytes, out_bytes, + in_if_name, out_if_name + ) + + with open(vivado_pynq_proj_dir + "/ip_config.tcl", "w") as f: + f.write(ip_config_tcl) + # create a shell script and call Vivado + make_project_sh = vivado_pynq_proj_dir + "/make_project.sh" + working_dir = os.environ["PWD"] + with open(make_project_sh, "w") as f: + f.write("#!/bin/bash \n") + f.write("cd {}\n".format(pynq_shell_path)) + f.write("export platform=%s\n" % (self.platform)) + f.write("export ip_config=%s\n" % (vivado_pynq_proj_dir + "/ip_config.tcl")) + f.write("make block_design\n") + f.write("cd {}\n".format(working_dir)) + bash_command = ["bash", make_project_sh] + process_compile = subprocess.Popen(bash_command, stdout=subprocess.PIPE) + process_compile.communicate() + return (model, False)