diff --git a/src/finn/transformation/fpgadataflow/make_deployment.py b/src/finn/transformation/fpgadataflow/make_deployment.py new file mode 100644 index 0000000000000000000000000000000000000000..22a252a43189996085829e6ba623cbcaddf714cb --- /dev/null +++ b/src/finn/transformation/fpgadataflow/make_deployment.py @@ -0,0 +1,50 @@ +import os +from distutils.dir_util import copy_tree +from shutil import copy + +from finn.transformation import Transformation +from finn.util.basic import make_build_dir + + +class DeployToPYNQ(Transformation): + """Collects all necessary files for deployment and copies them to the PYNQ board. + Expects information about PYNQ board to make scp possible: + * ip address of board + * username and password for board + * target directory where the files are stored on the board""" + + def __init__(self, ip, username, password, target_dir): + super().__init__() + self.ip = ip + self.username = username + self.password = password + self.target_dir = target_dir + + def apply(self, model): + # set metadata properties accordingly to user input specifications + model.set_metadata_prop("pynq_ip", self.ip) + model.set_metadata_prop("pynq_username", self.username) + model.set_metadata_prop("pynq_password", self.password) + model.set_metadata_prop("pynq_target_dir", self.target_dir) + + # create directory for deployment files + deployment_dir = make_build_dir(prefix="pynq_deployment_") + model.set_metadata_prop("pynq_deployment_dir", deployment_dir) + + # get and copy necessary files + # .bit and .hwh file + vivado_pynq_proj = model.get_metadata_prop("vivado_pynq_proj") + for file in os.listdir(vivado_pynq_proj): + if file.endswith(".bit"): + bitfile = os.path.join(vivado_pynq_proj, file) + elif file.endswith(".hwh"): + hwhfile = os.path.join(vivado_pynq_proj, file) + copy(bitfile, deployment_dir) + copy(hwhfile, deployment_dir) + + # driver.py and python libraries + pynq_driver_dir = model.get_metadata_prop("pynq_driver_dir") + copy_tree(pynq_driver_dir, deployment_dir) + model.set_metadata_prop("pynq_deploy_dir", deployment_dir) + + return (model, False) diff --git a/src/finn/util/data_packing.py b/src/finn/util/data_packing.py index 3363a4fb9d07ef478e34377f1882a6644e331f96..58c62219287940eb6533d2513e66d2c9c33cfb01 100644 --- a/src/finn/util/data_packing.py +++ b/src/finn/util/data_packing.py @@ -277,7 +277,7 @@ def finnpy_to_packed_bytearray(ndarray, dtype): return np.apply_along_axis(fn, packed_hexstring.ndim - 1, packed_hexstring) -def packed_bytearray_to_finnpy(packed_bytearray, dtype, output_shape=None): +def packed_bytearray_to_finnpy(packed_bytearray, dtype, output_shape=None, reverse_inner=False): """Given a packed numpy uint8 ndarray, unpack it into a FINN array of given DataType. output_shape can be specified to remove padding from the packed dimension, or set to None to be inferred from the input.""" @@ -300,6 +300,6 @@ def packed_bytearray_to_finnpy(packed_bytearray, dtype, output_shape=None): packed_hexstring = np.apply_along_axis( npbytearray2hexstring, packed_dim, packed_bytearray ) - ret = unpack_innermost_dim_from_hex_string(packed_hexstring, dtype, output_shape) + ret = unpack_innermost_dim_from_hex_string(packed_hexstring, dtype, output_shape, reverse_inner) return ret diff --git a/tests/fpgadataflow/test_data_packing.py b/tests/fpgadataflow/test_data_packing.py index c9d0cd064bbc487a35ade1a2bffeaf40d32a458e..3616219ef0e1046e7ef1a6daf3c1bfb6528a21cc 100644 --- a/tests/fpgadataflow/test_data_packing.py +++ b/tests/fpgadataflow/test_data_packing.py @@ -1,4 +1,5 @@ import shutil +import os import subprocess import numpy as np @@ -59,8 +60,8 @@ def make_npy2apintstream_testcase(ndarray, dtype): f.write("\n".join(test_app_string)) cmd_compile = """ g++ -o test_npy2apintstream test.cpp /workspace/cnpy/cnpy.cpp \ --I/workspace/cnpy/ -I/workspace/vivado-hlslib -I/workspace/finn/src/finn/data/cpp \ ---std=c++11 -lz""" +-I/workspace/cnpy/ -I{}/include -I/workspace/finn/src/finn/data/cpp \ +--std=c++11 -lz""".format(os.environ["VIVADO_PATH"]) with open(test_dir + "/compile.sh", "w") as f: f.write(cmd_compile) compile = subprocess.Popen( diff --git a/tests/fpgadataflow/test_fpgadataflow_ip_stitch.py b/tests/fpgadataflow/test_fpgadataflow_ip_stitch.py index 5d7d41a23908aabbab2f21ae5387bf2e46cba201..32de9b382c0c95d7411a5e17ec78e6c4ea876673 100644 --- a/tests/fpgadataflow/test_fpgadataflow_ip_stitch.py +++ b/tests/fpgadataflow/test_fpgadataflow_ip_stitch.py @@ -1,4 +1,5 @@ -import os.path +# import os.path +import os import pytest @@ -10,6 +11,7 @@ from finn.core.modelwrapper import ModelWrapper from finn.transformation.fpgadataflow.codegen_ipgen import CodeGen_ipgen from finn.transformation.fpgadataflow.codegen_ipstitch import CodeGen_ipstitch from finn.transformation.fpgadataflow.hlssynth_ipgen import HLSSynth_IPGen +from finn.transformation.fpgadataflow.make_deployment import DeployToPYNQ from finn.transformation.fpgadataflow.make_pynq_driver import MakePYNQDriver from finn.transformation.fpgadataflow.make_pynq_proj import MakePYNQProject from finn.transformation.fpgadataflow.synth_pynq_proj import SynthPYNQProject @@ -22,12 +24,12 @@ from finn.util.basic import ( # TODO control board/part for tests from a global place # settings for Ultra96 -test_fpga_part = "xczu3eg-sbva484-1-e" -test_pynq_board = "Ultra96" +# test_fpga_part = "xczu3eg-sbva484-1-e" +# test_pynq_board = "Ultra96" # settings for PYNQ-Z1 -# test_fpga_part = "xc7z020clg400-1" -# test_pynq_board = "Pynq-Z1" +test_fpga_part = "xc7z020clg400-1" +test_pynq_board = "Pynq-Z1" ip_stitch_model_dir = make_build_dir("test_fpgadataflow_ipstitch") @@ -260,3 +262,30 @@ def test_fpgadataflow_ipstitch_pynq_driver(): assert driver_dir is not None assert os.path.isdir(driver_dir) model.save(ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_pynq_driver.onnx") + + +@pytest.mark.dependency(depends=["test_fpgadataflow_ipstitch_pynq_driver"]) +def test_fpgadataflow_ipstitch_pynq_deployment_folder(): + model = ModelWrapper( + ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_pynq_driver.onnx" + ) + ip = "172.21.165.113" + username = "xilinx" + password = "xilinx" + target_dir = "/home/xilinx/" + os.environ["FINN_INST_NAME"] + model = model.transform(DeployToPYNQ(ip, username, password, target_dir)) + pynq_ip = model.get_metadata_prop("pynq_ip") + pynq_username = model.get_metadata_prop("pynq_username") + pynq_password = model.get_metadata_prop("pynq_password") + pynq_target_dir = model.get_metadata_prop("pynq_target_dir") + + assert pynq_ip == ip + assert pynq_username == username + assert pynq_password == password + assert pynq_target_dir == target_dir + + deployment_dir = model.get_metadata_prop("pynq_deploy_dir") + assert deployment_dir is not None + assert os.path.isdir(deployment_dir) + + model.save(ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_pynq_deployment.onnx")